"""
    lorestr_i2.py: CCP4 GUI Project
    
    This library is free software: you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public License
    version 3, modified in accordance with the provisions of the
    license to address the requirements of UK law.
    
    You should have received a copy of the modified GNU Lesser General
    Public License along with this library.  If not, copies may be
    downloaded from http://www.ccp4.ac.uk/ccp4license.php
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.
    """

import os
from CCP4PluginScript import CPluginScript
from lxml import etree
import CCP4Utils

import CCP4ErrorHandling
from CCP4ErrorHandling import *
import CCP4Modules
from lxml import etree
from xml.etree import ElementTree as ET


class lorestr_i2(CPluginScript):
    TASKNAME = 'lorestr_i2'   # Task name - should be same as class name and match pluginTitle in the .def.xml file
    TASKVERSION= 0.1               # Version of this plugin
    MAINTAINER = 'kovoleg'
    ERROR_CODES = { 201 : {'description' : 'Failed to analyse output files' },
                    202 : {'description' : 'Failed applying selection ot PDB file' }
                    }
    PURGESEARCHLIST = [ [ 'hklin.mtz' , 0 ],
                       ['log_mtzjoin.txt', 0]
                       ]
    TASKCOMMAND="lorestr" #_dummy
    PERFORMANCECLASS = 'CRefinementPerformance'
    
    def __init__(self, *args, **kws):
        super(lorestr_i2, self).__init__(*args, **kws)
        self._readyReadStandardOutputHandler = self.handleReadyReadStandardOutput
        self.xmlroot = etree.Element('lorestr_i2')
#        from refmacLogScraper import logScraper
#        self.logScraper = logScraper(xmlroot=self.xmlroot, flushXML=self.flushXML)
        self.xmlLength = 0

    def processInputFiles(self):
        #Preprocess reflections to generate an "HKLIN" file
        '''
        #makeHklin0 takes as arguments a list of sublists
        #Each sublist comprises 1) A reflection data object identifier (one of those specified in the inputData container 
        #                           the task in the corresponding .def.xml
        #                       2) The requested data representation type to be placed into the file that is generated
        #
        #makeHklin0 returns a tuple comprising:
        #                       1) the file path of the file that has been created
        #                       2) a list of strings, each of which contains a comma-separated list of column labels output from
        #                       the input data objects
        #                       3) A CCP4 Error object        
        import CCP4XtalData
        self.hklin, self.columns, error = self.makeHklin0([
            ['F_SIGF',CCP4XtalData.CObsDataFile.CONTENT_FLAG_FMEAN]
        ])
        self.columnsAsArray = self.columns.split(",")
        
        import CCP4ErrorHandling
        if error.maxSeverity()>CCP4ErrorHandling.SEVERITY_WARNING:
            return CPluginScript.FAILED
        '''
        
        #Preprocess coordinates to extract a subset
        '''
        # The method "getSelectedAtomsPdbFile" applied to a coordinate data object
        # selects those atoms declared in the objects "selectionString" property and writes them into
        # a pruned down file, the name of which is provided in the argument
        self.selectedCoordinatesPath = os.path.join(self.getWorkDirectory(), "selected_xyzin.pdb")
        self.container.inputData.XYZIN.getSelectedAtomsPdbFile(self.selectedCoordinatesPath)
        '''

        import CCP4XtalData
        error = None
        self.hklin = None
        dataObjects = []
        #print '\n\n\n***contentFlag',self.container.inputData.F_SIGF.contentFlag
        #Append Observation with representation dependent on whether we are detwining on Is or not

        obsTypeRoot = 'CONTENT_FLAG_F'
        obsPairOrMean = 'MEAN'
        obsType = getattr(CCP4XtalData.CObsDataFile, obsTypeRoot+obsPairOrMean)
        dataObjects += [['F_SIGF',obsType]] # ,obsType

        #Apply coordinate selection if set
        import os
        self.inputCoordPath = os.path.normpath(self.container.inputData.XYZIN.fullPath.__str__())
        if self.container.inputData.XYZIN.isSelectionSet():
            self.inputCoordPath = os.path.normpath(os.path.join(self.getWorkDirectory(),'selected.pdb'))
            self.container.inputData.XYZIN.getSelectedAtomsPdbFile(self.inputCoordPath)

        #Include FreeRflag if called for
        if self.container.inputData.FREERFLAG.isSet():
            dataObjects += ['FREERFLAG']
        self.hklin,error = self.makeHklin(dataObjects)

        import CCP4ErrorHandling
        if error.maxSeverity()>CCP4ErrorHandling.SEVERITY_WARNING:
            return CPluginScript.FAILED
        else:
            return CPluginScript.SUCCEEDED

    def handleReadyReadStandardOutput(self):

        print 'Runtime call handleReadyReadStandardOutput\n\n'

        if not hasattr(self,'logFileHandle'): self.logFileHandle = open(self.makeFileName('LOG'),'w')
        if not hasattr(self,'logFileBuffer'): self.logFileBuffer = ''
        pid = self.getProcessId()
        qprocess = CCP4Modules.PROCESSMANAGER().getJobData(pid,attribute='qprocess')
        availableStdout = qprocess.readAllStandardOutput()
        self.logFileHandle.write(availableStdout)
        self.logFileHandle.flush()

        self.xmlroot = etree.Element("lorestr_i2")
        logText = etree.SubElement(self.xmlroot,"LogText")
        logText.text = etree.CDATA(availableStdout)
        self.flushXML()

#        self.logScraper.processLogChunk(str(availableStdout))





    def flushXML(self):
        newXml = etree.tostring(self.xmlroot,pretty_print=True)
        if len(newXml)>self.xmlLength:
            self.xmlLength = len(newXml)
            with open (self.makeFileName('PROGRAMXML')+'_tmp','w') as programXmlFile:
                programXmlFile.write(newXml)
            import shutil
            shutil.move(self.makeFileName('PROGRAMXML')+'_tmp', self.makeFileName('PROGRAMXML'))


    def makeCommandAndScript(self, **kw):
        import os
        self.hklout = os.path.join(self.workDirectory,"hklout.mtz")

# ccp4-python -m lorestr.main
# -f 1.mtz
# -p1 1.pdb
# -xyzout 1_lorestr1.pdb
# -hklout 1_lorestr1.mtz
# -o ./8_lorestr
# -nc 3
# -minres 3.5
# -nh 5
# -auto
# -save_space

# Input
        self.appendCommandLine(['-p1', self.inputCoordPath])
        self.appendCommandLine(['-f', self.hklin])
        if self.container.inputData.TLSIN.isSet():
            self.appendCommandLine(['-tls', self.container.inputData.TLSIN.fullPath])

#        if self.container.inputData.REFERENCE_MODEL.isSet():
#            self.appendCommandLine(['-p2', self.container.inputData.REFERENCE_MODEL.fullPath])

        p2 = ['-p2']
        for iCoordSet, xyzRef in enumerate(self.container.inputData.REFERENCE_LIST):
            p2.append(str(xyzRef.fullPath))
        if len(p2) > 1:
            self.appendCommandLine(p2)

# Output
        self.appendCommandLine(['-xyzout', self.container.outputData.XYZOUT.fullPath])
        self.appendCommandLine(['-hklout', self.hklout])
        self.appendCommandLine(['-o', self.workDirectory + '/lorestrOutput'])



#        self.appendCommandLine(['LIBOUT',self.container.outputData.LIBOUT.fullPath])
#        self.appendCommandLine(['XMLOUT',os.path.normpath(os.path.join(self.getWorkDirectory(),'XMLOUT.xml'))])

# Parameters
        self.appendCommandLine(['-xml', str(self.makeFileName('PROGRAMXML'))]) # ccp4i2 compatibility

        if self.container.controlParameters.AUTO:
            self.appendCommandLine(['-auto'])

        if self.container.controlParameters.MR:
            self.appendCommandLine(['-mr'])

        if self.container.controlParameters.SS:
            self.appendCommandLine(['-save_space'])

        if self.container.controlParameters.DNA:
            self.appendCommandLine(['-dna'])

        if self.container.controlParameters.CPU:
            self.appendCommandLine(['-cpu', str(self.container.controlParameters.CPU)])

        if self.container.controlParameters.MINRES:
            self.appendCommandLine(['-minres', str(self.container.controlParameters.MINRES)])

        if self.container.controlParameters.NC:
            self.appendCommandLine(['-nc', str(self.container.controlParameters.NC)])

        if self.container.controlParameters.NH:
            self.appendCommandLine(['-nh', str(self.container.controlParameters.NH)])

        return CPluginScript.SUCCEEDED

    def processOutputFiles(self):
        #Associate the tasks output coordinate file with the output coordinate object XYZOUT:

        self.container.outputData.XYZOUT.setFullPath(os.path.join(self.getWorkDirectory(),"XYZOUT.pdb"))

      # Split an MTZ file into minimtz data objects
#        outputFilesToMake = ['FPHIOUT','DIFFPHIOUT']
#        columnsToTake = ['FWT,PHWT','DELFWT,PHDELWT']
#        infile = self.hklout
#        error = self.splitHklout(outputFilesToMake, columnsToTake, infile=infile)

        self.container.outputData.XYZOUT.annotation = 'Refined model'
        self.container.outputData.FPHIOUT.annotation = 'Weighted map after refinement'
        self.container.outputData.DIFFPHIOUT.annotation = 'Weighted difference map after refinement'
        self.container.outputData.FPHIOUT.subType = 1
        self.container.outputData.DIFFPHIOUT.subType = 2

        outputFiles = ['FPHIOUT','DIFFPHIOUT']
        outputColumns = ['FWT,PHWT','DELFWT,PHDELWT']

        error = self.splitHklout(outputFiles,outputColumns)


        xmlRoot = ET.parse(self.makeFileName('PROGRAMXML')).getroot()
        bestProtocolNumber = int(xmlRoot.find("Protocols").findtext("BestProtocol"))
        rFact = xmlRoot.find("Protocols").find("P%d" % bestProtocolNumber).findtext("Rfact")
        rFree = xmlRoot.find("Protocols").find("P%d" % bestProtocolNumber).findtext("Rfree")


        self.container.outputData.PERFORMANCE.RFactor = float(rFact)
        self.container.outputData.PERFORMANCE.RFree = float(rFree)


        import CCP4ErrorHandling
        if error.maxSeverity()>CCP4ErrorHandling.SEVERITY_WARNING:
            return CPluginScript.FAILED

        return CPluginScript.SUCCEEDED
