# -*- coding: utf-8 -*-
########################################################################################
#                                                                                      #
#   Author: Bertrand Néron                                                          #
#   Organization:'Biological Software and Databases' Group, Institut Pasteur, Paris.   #  
#   Distributed under GPLv2 Licence. Please refer to the COPYING.LIB document.         #
#                                                                                      #
########################################################################################

import os
import string
from logging import getLogger
f_log = getLogger(__name__)

from Mobyle.MobyleError import MobyleError , UnSupportedFormatError
from Mobyle.Converter.DataConverter import DataConverter

from Bio import AlignIO
from Bio.AlignIO.PhylipIO import RelaxedPhylipWriter

def write_alignment(self, alignment):
    """
    Write a relaxed phylip alignment o
    allow white spaces in sequence name
    replace white space by '_'
    """
    # Check inputs
    for s in alignment:
        name = s.id.strip()
        for c in string.whitespace:
            if c in name:
                name = name.replace(c, "_")
                s.id = name
    # Calculate a truncation length - maximum length of sequence ID plus a
    # single character for padding
    # If no sequences, set id_width to 1. super(...) call will raise a
    # ValueError
    if len(alignment) == 0:
        id_width = 1
    else:
        id_width = max((len(s.id.strip()) for s in alignment)) + 1
    super(RelaxedPhylipWriter, self).write_alignment(alignment, id_width)
    
RelaxedPhylipWriter.write_alignment =  write_alignment
       
class phylipi_phyml(DataConverter):
    
    def __init__(self, path):
        super( phylipi_phyml , self ).__init__( path )
        self.program_name = 'PhylipI2Phylip-relaxed'

    def detect(self, dataFileName):
        #we lay on squizz to detect the format file
        return None, None
    
    def detectedFormat(self):
        #we lay on squizz to detect the format file
        return []
    
    def convert(self, dataFileName , outputFormat , inputFormat = None):
        outputFormat = outputFormat.lower()
        assert outputFormat == 'phylip-relaxed'
        
        if inputFormat is None:
            raise UnSupportedFormatError("the input format must be specify" )
        inputFormat = inputFormat.lower()
        
        if inputFormat not in ('phylip', 'phylipi'):
            raise UnSupportedFormatError("support only phylip as input, provide " + str(inputFormat))
        with open(dataFileName) as data_input:
            #read allow only one multiple alignment
            #for more msa (after bootstarp) use parse
            #but for now squiz manage only one msa perfile
            try:    
                align = AlignIO.read(data_input, 'phylip')
            except Exception, err:
                f_log.error( "failed to read phylip alignment", exc_info= True)
                raise UnSupportedFormatError( "the conversion from phylip to phylip-relaxed failed")
        outFileName = os.path.splitext( dataFileName )[0] + "." + outputFormat
        with  open(outFileName, 'w') as output:
            try:
                AlignIO.write(align, output , 'phylip-relaxed')
            except Exception, err:
                f_log.error( "failed to write phylip-relaxed alignment", exc_info= True)
                raise UnSupportedFormatError( "the convertion from fasta to phylip-relaxed failed")    
        return outFileName 
    
    def convertedFormat(self):
        return [('PHYLIP', 'PHYLIP-RELAXED'), ('PHYLIPI', 'PHYLIP-RELAXED')]