"""
     edstats.py: CCP4 GUI Project
     Copyright (C) 2014 University of York

     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.
"""

"""
     Jon Agirre         2014 - Started development

"""

from CCP4PluginScript import CPluginScript
from CCP4Modules import PROCESSMANAGER
import CCP4ErrorHandling


class edstats(CPluginScript):

    TASKMODULE          = 'validation'          # Where this plugin will appear on the gui  
    TASKTITLE           = 'Measure agreement between model and density'  # A short title for gui menu
    TASKNAME            = 'edstats'  # Task name - should be same as class name
    TASKCOMMAND         = 'edstats'  # The command to execute, should be reachable
    DESCRIPTION         = 'Calculates real-space metrics for evaluating the agreement between model and density (Edstats)'
    TASKVERSION         = 0.1                   # Version of this plugin
    WHATNEXT            = ['coot_rebuild']
    MAINTAINER = 'jon.agirre@york.ac.uk'

    def processInputFiles(self):
      import CCP4XtalData

      self.cfftPlugin1 = self.makeCfftPlugin1 ( )
      error = self.cfftPlugin1.process ( )
      if error == CPluginScript.FAILED:
          self.reportStatus ( error )
      else :
          self.container.inputData.MAPIN1 = self.cfftPlugin1.container.outputData.MAPOUT

      self.cfftPlugin2 = self.makeCfftPlugin2 ( )
      error = self.cfftPlugin2.process ( )
      if error == CPluginScript.FAILED:
          self.reportStatus ( error )
      else :
          self.container.inputData.MAPIN2 = self.cfftPlugin2.container.outputData.MAPOUT
          
    
      #print 'taskMakeHklin F_SIGF',self.container.inputData.F_SIGF,type(self.container.inputData.F_SIGF),self.container.inputData.F_SIGF.contentFlag
      #self.hklin,error = self.makeHklin ( [ ['F_SIGF',CCP4XtalData.CObsDataFile.CONTENT_FLAG_FMEAN ] ] )
      #if error.maxSeverity()>CCP4ErrorHandling.SEVERITY_WARNING: return CPluginScript.FAILED
      
      return CPluginScript.SUCCEEDED

    def processOutputFiles(self):
        
        import os
        out = self.container.outputData
        self.path_wrk = str( self.getWorkDirectory() )

        fileName3 = os.path.join ( self.path_wrk, 'coot_script.py' )

        if os.path.isfile ( fileName3 ) :
            out.COOTSCRIPTOUT.set ( fileName3 )
            out.COOTSCRIPTOUT.annotation.set ( 'guided tour on the reported issues' )
        
        from lxml import etree
        xmlRoot = etree.Element('Edstats')
        segmentNode = None
        
        lines = open(self.makeFileName('LOG')).readlines()
        
        readingTable = False
        
        mcBadBits = []
        scBadBits = []
        
        zdm = float ( self.container.controlParameters.SIGMA_RZ_MINUS )
        zdp = float ( self.container.controlParameters.SIGMA_RZ_PLUS  )
        zo  = float ( self.container.controlParameters.SIGMA_RO )

        for line in lines:
            
            if readingTable :
                if len( line.strip().split ( ) ) > 20: 
                    residueNode = etree.SubElement(xmlRoot,'Residue')
                    
                    resnameNode     = etree.SubElement(residueNode,'Name')
                    resnameNode.text = line.strip().split( )[0]
                    
                    resChainNode      = etree.SubElement(residueNode,'Chain')
                    resChainNode.text = line.strip().split( )[1]
                    
                    resNumberNode      = etree.SubElement(residueNode,'Number')
                    resNumberNode.text = line.strip().split( )[2]
                    
                    resZCCmNode    = etree.SubElement(residueNode,'ZCCm')
                    resZCCmNode.text = line.strip().split( )[10]

                    resZOmNode    = etree.SubElement(residueNode,'ZOm')
                    resZOmNode.text = line.strip().split( )[11]
                    
                    resZDmmNode    = etree.SubElement(residueNode,'ZDmm')
                    resZDmmNode.text = line.strip().split( )[13]

                    resZDpmNode    = etree.SubElement(residueNode,'ZDpm')
                    resZDpmNode.text = line.strip().split( )[14]
                    
                    resZCCsNode    = etree.SubElement(residueNode,'ZCCs')
                    resZCCsNode.text = line.strip().split( )[22]

                    resZOsNode    = etree.SubElement(residueNode,'ZOs')
                    resZOsNode.text = line.strip().split( )[23]
                    
                    resZDmsNode    = etree.SubElement(residueNode,'ZDms')
                    resZDmsNode.text = line.strip().split( )[25]

                    resZDpsNode    = etree.SubElement(residueNode,'ZDps')
                    resZDpsNode.text = line.strip().split( )[26]

                    resZCCaNode    = etree.SubElement(residueNode,'ZCCa')
                    resZCCaNode.text = line.strip().split( )[34]

                    resZOaNode    = etree.SubElement(residueNode,'ZOa')
                    resZOaNode.text = line.strip().split( )[35]
                    
                    resZDmaNode    = etree.SubElement(residueNode,'ZDma')
                    resZDmaNode.text = line.strip().split( )[37]

                    resZDpaNode    = etree.SubElement(residueNode,'ZDpa')
                    resZDpaNode.text = line.strip().split( )[38]

                    # Now we create a list with main chain outliers to be fixed within Coot

                    if resZDmmNode.text != "n/a" and resZDpmNode.text != "n/a" and resZOmNode.text != "n/a" :
                        if float ( resZDmmNode.text ) < zdm or float ( resZDpmNode.text ) > zdp or float ( resZOmNode.text ) < zo :
                            badResidue = {"name":resnameNode.text, 
                                          "id":resNumberNode.text,
                                          "chain":resChainNode.text,
                                          "minus":resZDmmNode.text,
                                          "plus":resZDpmNode.text}
                            mcBadBits.append ( badResidue )
    
                    if resZDmsNode.text != "n/a" and resZDpsNode.text != "n/a" and resZOsNode.text != "n/a" :
                        if float ( resZDmsNode.text ) < zdm or float ( resZDpsNode.text ) > zdp or float ( resZOsNode.text ) < zo :
                            badResidue = {"name":resnameNode.text, 
                                          "id":resNumberNode.text,
                                          "chain":resChainNode.text,
                                          "minus":resZDmmNode.text,
                                          "plus":resZDpmNode.text}
                            scBadBits.append ( badResidue )
    
            elif line.strip().startswith('RT  CI'):      
                readingTable = True

        with open(self.container.outputData.COOTSCRIPTOUT.fullPath.__str__(),"w") as cootscript:
            if len(mcBadBits) > 0:
                interestingMCBitsDef = 'interestingMCBits = ['
                for res in mcBadBits:
                    interestingMCBitsDef += ('{"chain":"%s","firstResidue":"%s","lastResidue":"%s"}\n,'%(res['chain'],res['id'],res['id']))
                    
                interestingMCBitsDef += ']\n'

                cootscript.write(interestingMCBitsDef)
                cootscript.write('ccp4i2Interface.addInterestingBitsMenu(title="Edstats - main chain outliers", interestingBits=interestingMCBits)\n')

            if len(scBadBits) > 0:
                interestingSCBitsDef = 'interestingSCBits = ['
                for res in scBadBits:
                    interestingSCBitsDef += ('{"chain":"%s","firstResidue":"%s","lastResidue":"%s"}\n,'%(res['chain'],res['id'],res['id']))
                    
                interestingSCBitsDef += ']\n'

                cootscript.write(interestingSCBitsDef)
                cootscript.write('ccp4i2Interface.addInterestingBitsMenu(title="Edstats - side chain outliers", interestingBits=interestingSCBits)\n')

        with open(self.makeFileName('PROGRAMXML'),'w') as xmlFile:
            xmlString = etree.tostring(xmlRoot, pretty_print=True)
            xmlFile.write(xmlString)

        return CPluginScript.SUCCEEDED

    def makeCommandAndScript(self):
      import os
      import CCP4XtalData
   
      self.path_wrk = str( self.getWorkDirectory() )
      edstatsOut = os.path.join ( self.path_wrk, 'edstats.out' )

      
      self.appendCommandLine([ 'XYZIN', self.container.inputData.XYZIN.fullPath ])

      # INPUT DATA
      self.appendCommandLine([ 'MAPIN1', self.container.inputData.MAPIN1.fullPath ]) 
     
      if self.container.inputData.MAPIN2.isSet():
        self.appendCommandLine([ 'MAPIN2', self.container.inputData.MAPIN2.fullPath ])
      
      self.appendCommandLine ( [ ' OUT edstats.out ' ] )
      self.appendCommandLine ( [ ' XYZOUT XYZOUT.pdb ' ] )
      
      self.appendCommandScript( "reslo=%s"%( str ( self.container.inputData.RES_LOW ) ))
      self.appendCommandScript( "reshi=%s"%( str ( self.container.inputData.RES_HIGH ) ))
    
      if self.container.controlParameters.MAIN_AVERAGING.isSet() :
        self.appendCommandScript("main=%s"%(str(self.container.controlParameters.MAIN_AVERAGING)))   

      if self.container.controlParameters.SIDE_AVERAGING.isSet() :
        self.appendCommandScript("side=%s"%(str(self.container.controlParameters.SIDE_AVERAGING))) 
 
      if self.container.controlParameters.SCALING :
        self.appendCommandScript("resc=%s"%(str(self.container.controlParameters.SCALING_TYPE)))
      else :
        self.appendCommandScript("resc=none")

      return CPluginScript.SUCCEEDED

    def makeCfftPlugin1 ( self ):
        cfftPlugin1 = self.makePluginObject( 'fft' )
        cfftPlugin1.container.inputData.FPHIIN = self.container.inputData.FPHIIN1
        cfftPlugin1.container.inputData.RESOLUTION = self.container.inputData.RES_HIGH * 3.0 / 4.1
        return cfftPlugin1

# I'd like to keep separate plugins because I plan to do divergent stuff in the future. 3/4.1 seemed to work.

    def makeCfftPlugin2 ( self ):
        cfftPlugin2 = self.makePluginObject( 'fft' )
        cfftPlugin2.container.inputData.FPHIIN = self.container.inputData.FPHIIN2
        cfftPlugin2.container.inputData.RESOLUTION = self.container.inputData.RES_HIGH * 3.0 / 4.1
        return cfftPlugin2

#=============================================================================================
import unittest
class testEdstats(unittest.TestCase):
  
    def test1(self):
      # Test creation of log file using ../test_data/test1.params.xml input
      from CCP4Utils import getCCP4I2Dir
      import CCP4Utils, os
      workDirectory = CCP4Utils.getTestTmpDir()
      logFile = os.path.join(workDirectory,'edstats_test1.log')
      # Delete any existing log file
      if os.path.exists(logFile): os.remove(logFile)
      self.wrapper = edstats(name='edstats_test1',workDirectory=workDirectory)
      self.wrapper.container.loadDataFromXml(os.path.join(getCCP4I2Dir(),'wrappers','edstats','test_data','test1.params.xml'))
      self.wrapper.setWaitForFinished(1000000)
      pid = self.wrapper.process()
      self.wrapper.setWaitForFinished(-1)
      if len(self.wrapper.errorReport)>0: print self.wrapper.errorReport.report()
      #self.assertTrue(os.path.exists(logFile),'No log file found')


def TESTSUITE():
  suite = unittest.TestLoader().loadTestsFromTestCase(testEdstats)
  return suite

def testModule():
  suite = TESTSUITE()
  unittest.TextTestRunner(verbosity=2).run(suite)
