#! /usr/bin/env python
#
# Copyright INRA-URGI 2009-2011
# 
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
# 
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
# 
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
# 
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
import os
import random
from optparse import OptionParser
from SMART.Java.Python.structure.TranscriptContainer import TranscriptContainer
from SMART.Java.Python.misc.Progress import Progress
from commons.core.parsing.ParserChooser import ParserChooser
from commons.core.writer.Gff3Writer import Gff3Writer

OPERATIONS = ("plus", "minus", "times", "div")

class CombineTags(object):

    def __init__(self, verbosity = 0):
        self.verbosity       = verbosity

    def setInputFile(self, fileName, format):
        self.inputFileName = fileName
        parserChooser = ParserChooser(self.verbosity)
        parserChooser.findFormat(format, "transcript")
        self.parser = parserChooser.getParser(fileName)

    def setOutputFile(self, fileName):
        self.outputWriter = Gff3Writer(fileName, self.verbosity)

    def setTags(self, tag1, tag2, outputTag, defaultValue = None):
        self.tag1         = tag1
        self.tag2         = tag2
        self.outputTag    = outputTag
        self.defaultValue = defaultValue

    def setOperation(self, operation):
        self.operation = operation
        if self.operation not in OPERATIONS:
            raise Exception("Do no handle operation %s, only: %s" % (self.operation, ", ".join(OPERATIONS)))

    def run(self):
        progress = Progress(self.parser.getNbTranscripts(), "Printing transcripts %s" % (self.inputFileName), self.verbosity)
        for transcript in self.parser.getIterator():
            tag1 = transcript.getTagValue(self.tag1)
            tag2 = transcript.getTagValue(self.tag2)
            if tag1 == None or tag2 == None:
                if self.defaultValue == None:
                    raise Exception("Transcript %s misses one of the tags %s and %s, and has no default value !" % (transcript, self.tag1, self.tag2))
                newTag = self.defaultValue
            else:
                tag1, tag2 = float(tag1), float(tag2)
                if self.operation == "plus":
                    newTag = tag1 + tag2
                elif self.operation == "minus":
                    newTag = tag1 - tag2
                elif self.operation == "times":
                    newTag = tag1 * tag2
                elif self.operation == "div":
                    newTag = tag1 / tag2
            transcript.setTagValue(self.outputTag, newTag)
            self.outputWriter.addTranscript(transcript)
            progress.inc()
        progress.done()
        self.parser.close()
        self.outputWriter.close()


if __name__ == "__main__":
    
    # parse command line
    description = "Change Tag Name v1.0.1: Change the name of tag of a list of transcripts. [Category: Data Modification]"

    parser = OptionParser(description = description)
    parser.add_option("-i", "--input",       dest="inputFileName",  action="store",               type="string", help="input file [compulsory] [format: file in transcript format given by -f]")
    parser.add_option("-f", "--inputFormat", dest="inputFormat",    action="store",               type="string", help="format of the input file [compulsory] [format: transcript file format]")
    parser.add_option("-o", "--output",      dest="outputFileName", action="store",               type="string", help="output file [compulsory] [format: output file in GFF3 format]")
    parser.add_option("-t", "--tag1",        dest="tag1",           action="store",               type="string", help="name of the first tag [compulsory] [format: string]")
    parser.add_option("-T", "--tag2",        dest="tag2",           action="store",               type="string", help="name of the second tag [compulsory] [format: string]")
    parser.add_option("-d", "--default",     dest="defaultValue",   action="store", default=None, type="string", help="default value when one of the tag is absent [compulsory] [format: float]")
    parser.add_option("-n", "--new",         dest="newTag",         action="store",               type="string", help="name of the new tag [compulsory] [format: string]")
    parser.add_option("-p", "--operation",   dest="operation",      action="store",               type="string", help="operation combining the tags [compulsory] [format: choice (plus, minus, times, div)]")
    parser.add_option("-v", "--verbosity",   dest="verbosity",      action="store", default=1,    type="int",    help="trace level [format: int] [default: 1]")
    (options, args) = parser.parse_args()

    combiner = CombineTags(options.verbosity)
    combiner.setInputFile(options.inputFileName, options.inputFormat)
    combiner.setOutputFile("%s.gff3" % (options.outputFileName))
    combiner.setTags(options.tag1, options.tag2, options.newTag, options.defaultValue)
    combiner.setOperation(options.operation)
    combiner.run()
