# -------------------------------------------------
import os,sys
try:
  from CCP4ReportParser import *
except:
  execfile(os.path.join(os.environ['CCP4I2_TOP'],'bin/ccp4i2.pythonrc'))
  from CCP4ReportParser import *

import pointless_report
import aimless_report
import ctruncate_report

from aimless_pipe_utils import *

class aimless_pipe_report(Report):
  # Specify which gui task and/or pluginscript this applies to
  TASKNAME = 'aimless_pipe'
  RUNNING = True
  def __init__(self,xmlnode=None,jobInfo={},**kw):
    Report.__init__(self,xmlnode=xmlnode,jobInfo=jobInfo,style="width:800px;overflow:auto;",**kw)

    try:
      self.fileroot = self.jobInfo['fileroot']
    except:
      self.fileroot = None

    if kw.get('jobStatus',None) is not None and kw.get('jobStatus').lower() == 'nooutput':
      return
    elif kw.get('jobStatus',None) is not None and kw.get('jobStatus').lower().count('running'):
      self.pointlessReport()
    else:
      self.defaultReport()

  # - - - - - - - - - - - - - - - - - - - - - - - 
  def defaultReport(self, parent=None):
    if parent is None: parent = self
##    Report.__init__(self,xmlnode=xmlnode,jobInfo=jobInfo,style="width:1280px;overflow:auto;",**kw)

    # . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . . 
    # Instantiate aimless and pointless and ctruncate reports from which to cherry pick
    # The nooutput flag makes sure thay don't do anything

    # First check if any parts of the report exist

    errorspresent = False
    pointlessFatalErrors = False
    aimlessFatalErrors = False
    
    #  0) PIPELINE_ERROR  fatal error somewhere
    if self.xmlnode.haspath('PIPELINE_ERROR'):
      errorspresent = True
      errormessage =  self.xmlnode.select('PIPELINE_ERROR')
      print "errormessage", errormessage
      errorDiv = parent.addDiv(
        style="width:90%;border: 2px solid red; clear:both; margin:3px; padding:6px;")
      errorDiv.addText(text='FATAL ERROR',
                       style='font-weight:bold; font-size:150%; color:red;')
      errorDiv.append(errormessage)
      
    #  1) POINTLESS
    pointlessxml = self.xmlnode.xpath0("POINTLESS")
    havePointlessReport = (pointlessxml != None) and (len(pointlessxml) > 0)
    #  2) AIMLESS
    aimlessxml = self.xmlnode.xpath0("AIMLESS")
    haveAimlessReport = (aimlessxml != None) and (len(aimlessxml) > 0)
    #  3) CTRUNCATE
    ctruncatexmlsnode = self.xmlnode.xpath0("CTRUNCATES")
    haveCtruncateReport = (ctruncatexmlsnode != None) and (len(ctruncatexmlsnode) > 0)

    # Empty XML file
    if not havePointlessReport and not haveAimlessReport and not haveCtruncateReport:
      parent.addText(text='No Report data available, probably due to failure of job',
                     style='color:red;')
      return

    if havePointlessReport:
      self.pointlessreport = \
          pointless_report.pointless_report(xmlnode=pointlessxml, jobStatus='nooutput')
      self.pointlessreport.setFileRoot(self.fileroot) # pass on fileroot
      #print "self.pointlessreport", self.pointlessreport

    if (haveAimlessReport):
      self.aimlessreport = \
               aimless_report.aimless_report(xmlnode=aimlessxml, jobStatus='nooutput')
      self.aimlessreport.setFileRoot(self.fileroot) # pass on fileroot

    ctruncatexmlnodelist = None
    self.ctruncatereports = None
    if haveCtruncateReport:
      ctruncatexmlnodelist = ctruncatexmlsnode.xpath("CTRUNCATE")

      if (ctruncatexmlnodelist != None):
        #print ctruncatexmlnodelist
        self.ctruncatereports = []
        for ctruncatexmlnode in ctruncatexmlnodelist:
          self.ctruncatereports.append(
            ctruncate_report.ctruncate_report(xmlnode=ctruncatexmlnode, jobStatus='nooutput') )
          #print "!! ctruncatereports !! ", self.ctruncatereports

    # . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . . 
    # Process fatal error messages, if any
    
    if havePointlessReport and self.pointlessreport.isFatalError():
        errorspresent = True
        pointlessFatalErrors = True

    if haveAimlessReport and self.aimlessreport.isFatalError():
        errorspresent = True
        aimlessFatalErrors = True

    if errorspresent:
      if pointlessFatalErrors:
        errorDiv.append('<br/>')
        errorDiv.addText(text='Errors from Pointless', style='font-size:120%;color:red;')
        self.pointlessreport.Errors(errorDiv)   #  report any fatal errors
      if aimlessFatalErrors:
        errorDiv.append('<br/>')
        errorDiv.addText(text='Errors from Aimless', style='font-size:120%;color:red;')
        self.aimlessreport.Errors(errorDiv)   #  report any fatal errors
        
    # . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . . 
    #   Overall summaries, layout different if > 1 dataset
    self.numberofdatasets = 1
    if (haveAimlessReport):
      self.numberofdatasets = self.aimlessreport.numberOfDatasets()


    # . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . . 
    # Summary of summaries
    summaryDiv = parent.addDiv(\
      style="width:100%;border-width: 1px; border-color: black; clear:both; margin:0px; padding:0px;")
    summaryfold = summaryDiv.addFold(label='Key summary', brief='Headline',
                                     initiallyOpen=True)
    if havePointlessReport:
      fail = self.pointlessreport.Errors(summaryfold)   #  report any fatal errors
      if fail:
        return

      self.pointlessreport.keyText(summaryfold)

    if haveAimlessReport:
      self.aimlessreport.keyText(summaryfold)

    # ctruncate
    if self.ctruncatereports != None:
      self.ctruncatereports[0].keyText(summaryfold)

    freerxml = self.xmlnode.xpath0('FREERFLAG')
    if freerxml != None:
      self.addFreerReports(freerxml, summaryfold)

    # . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . . 
    # Main summary
    overallsummaryDiv = parent.addDiv(\
      style="width:100%;border-width: 1px; border-color: black; clear:both; margin:0px; padding:0px;")
    overallfold = overallsummaryDiv.addFold(label='Overall summary',
                                            brief='Summary',initiallyOpen=True)

    # Put the key messages about spacegroup and resolution at the very top
    headlineDiv = overallfold.addDiv(style="border-width: 1px; border-color: black; clear:both; margin:0px; padding:5px;")
    leftDiv = headlineDiv.addDiv(style="width:49%;float:left;text-align:center;margin:0px; padding:0px; line-height:100%; font-size:100%;border:0px;")
    if havePointlessReport:
      self.addPointlessSummary(leftDiv)
    # Pointless element table in:
    #    (1) if 1 dataset, in leftDiv with Pointless summary
    #    (2) if >1 dataset in new Div on right of Pointless summary
    if self.numberofdatasets == 1:
      nextDiv = leftDiv.addDiv(style="border: 1px solid black; margin: 1px; padding:1px;")
    else:
      nextDiv = headlineDiv.addDiv(style="width:49%;float:left;margin:1px;text-align:center; \
        padding:3px;border:1px solid black;")

    if havePointlessReport:
      self.pointlessreport.ElementScoresTable(nextDiv)
    
    if haveAimlessReport:
      # Aimless summary
      if self.numberofdatasets == 1:
        statsDiv = headlineDiv.addDiv(style="width:46%;float:left;text-align:center;margin:0px; padding:10px;border:1px solid black;")
      else:
        statsDiv = overallfold.addDiv(style="border:1px solid black; clear:both; margin:5px; padding:10px;")

      self.aimlessreport.addAimlessSummary(statsDiv)

      if self.numberofdatasets > 1:
        interdatasetDiv = overallfold.addDiv(style="border-width: 1px; border-color: black; \
            clear:both; margin:0px; padding:0px;")
        aHeaderDiv = interdatasetDiv.addDiv(style="clear:both;font-weight:bold; font-size:130%;")
        aHeaderDiv.append('<br/>Comparison of anomalous and dispersive differences between datasets')
        self.aimlessreport.addInterDatasetGraphs(interdatasetDiv)

      self.aimlessreport.importantGraphs(overallfold)

      if self.ctruncatereports != None:
        headerDiv = overallfold.addDiv(style='width:100%;text-align:center;font-weight: bold; font-size:130%;')
        headerDiv.addText(text='Graphs for detecting twinning etc, more details in Istats section')
        twinned = self.ctruncatereports[0].addWarningTwin(headerDiv,check=True)
        headerDiv.append('<br/>')
        if twinned:
          headerDiv.addText(text='This dataset is probably twinned',
                          style='color:red;')
        else:
          headerDiv.addText(text='This dataset is probably NOT twinned',
                          style='font-style:italic; color:green;')

        twinDiv = overallfold.addDiv()
        twinleftDiv = twinDiv.addDiv(style="width:48%;float:left;text-align:center;margin:6px; padding:0px; ")
        twinleftDiv.addText(text='L-test for twinning',style="font-weight:bold; font-size:130%;")
        self.ctruncatereports[0].CtruncateLtest(twinleftDiv)

        twinrightDiv = twinDiv.addDiv(style="width:48%;float:left;text-align:center;margin:6px; padding:0px; ")
        self.ctruncatereports[0].acentricMoments(twinrightDiv)

        self.addTruncateWilson(twinleftDiv)
      
      details1Div = parent.addDiv(style="border-width: 1px; border-color: black; clear:both; margin:0px; padding:0px;")
      details1Div.append('<br/>')
      if havePointlessReport:
        self.pointlessreport.Details(details1Div)

      nextgraphsDiv = parent.addDiv(style="border-width: 1px; border-color: black; clear:both; margin:0px; padding:0px;")
      nextfold = nextgraphsDiv.addFold(label='Other merging graphs', brief='MergingGraphs', initiallyOpen=True)
      self.aimlessreport.moreGraphs(nextfold)

      details2Div = parent.addDiv(style="border-width: 1px; border-color: black; clear:both; margin:0px; padding:0px;")
      fold = details2Div.addFold(label="Details of merging", brief='MergingDetails')
      #  Resolution estimates
      leftDiv = fold.addDiv(style="width:50%;float:left;text-align:center;margin:0px; padding:0px; line-height:100%; font-size:100%;")
      aHeaderDiv = leftDiv.addDiv(style="clear:both;font-weight:bold; font-size:130%;")
      aHeaderDiv.append('Resolution estimates')      
      self.aimlessreport.ResolutionEstimates(leftDiv, aimlessxml.xpath("Result/Dataset"))

      # Other stuff
      rightDiv = fold.addDiv(style="width:50%;float:left;text-align:center;margin:0px; padding:0px; line-height:100%; font-size:100%;")
      self.aimlessreport.otherStatistics(rightDiv)
      
      fold.append('<br/>')
      crossDiv = fold.addDiv(style="width:100%;float:left;text-align:center;margin:0px; padding:0px; line-height:100%; font-size:100%;")
      crossHDiv = crossDiv.addDiv(style="clear:both;font-weight:bold; font-size:130%;text-align:left")

      self.aimlessreport.interRunTable(crossDiv)
      
      truncateDiv = parent.addDiv(style="border-width: 1px; border-color: black; clear:both; margin:0px; padding:0px;")
      #truncateDiv.append('<br/>')
      fold = truncateDiv.addFold(label="Intensity statistics: twinning tNCS etc",brief='Istats')

      if self.ctruncatereports != None:
        self.addCtruncateReports(fold)

      #The following is to return the html to doing one item per line
      parent.addDiv(style="width:95%; clear:both;")

  # - - - - - - - - - - - - - - - - - - - - - - - 
  def pointlessReport(self, parent=None):
    # just for Pointless

    if parent is None: parent = self
##    Report.__init__(self,xmlnode=xmlnode,jobInfo=jobInfo,style="width:1280px;overflow:auto;",**kw)

    # . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . . 
    # Instantiate pointless report from which to cherry pick
    # The nooutput flag makes sure thay don't do anything
    # First check if any parts of the report exist

    errorspresent = False
    pointlessFatalErrors = False
    
    #  0) PIPELINE_ERROR  fatal error somewhere
    if self.xmlnode.haspath('PIPELINE_ERROR'):
      errorspresent = True
      errormessage =  self.xmlnode.select('PIPELINE_ERROR')
      print "errormessage", errormessage
      errorDiv = parent.addDiv(
        style="width:90%;border: 2px solid red; clear:both; margin:3px; padding:6px;")
      errorDiv.addText(text='FATAL ERROR',
                       style='font-weight:bold; font-size:150%; color:red;')
      errorDiv.append(errormessage)
      
    #  1) POINTLESS
    pointlessxml = self.xmlnode.xpath0("POINTLESS")
    havePointlessReport = (pointlessxml != None) and (len(pointlessxml) > 0)

    # Empty XML file
    if not havePointlessReport:
      parent.addText(text='No Report data available, probably due to failure of job',
                     style='color:red;')
      return

    # Pointless report exists
    self.pointlessreport = \
           pointless_report.pointless_report(xmlnode=pointlessxml, jobStatus='nooutput')
    self.pointlessreport.setFileRoot(self.fileroot) # pass on fileroot
    #print "self.pointlessreport", self.pointlessreport

    # . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . . 
    # Process fatal error messages, if any
    if havePointlessReport and self.pointlessreport.isFatalError():
      errorspresent = True
      pointlessFatalErrors = True

    if errorspresent:
      if pointlessFatalErrors:
        errorDiv.append('<br/>')
        errorDiv.addText(text='Errors from Pointless', style='font-size:120%;color:red;')
        self.pointlessreport.Errors(errorDiv)   #  report any fatal errors
        
    # . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . . 
    # Summary of summaries
    summaryDiv = parent.addDiv(\
      style="width:100%;border-width: 1px; border-color: black; clear:both; margin:0px; padding:0px;")
    if havePointlessReport:
      fail = self.pointlessreport.Errors(summaryDiv)   #  report any fatal errors
      if fail:
        return

      summaryDiv.addText(text="Report from Pointless while Aimless is running",
                         style='font-weight:bold; font-size:150%; color:red;')

      self.pointlessreport.keyText(summaryDiv)

    # . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . .  . . . . 
    # Main summary
    overallsummaryDiv = parent.addDiv(\
      style="width:100%;border-width: 1px; border-color: black; clear:both; margin:0px; padding:0px;")

    # Put the key messages about spacegroup and resolution at the very top
    headlineDiv = overallsummaryDiv.addDiv(style="border-width: 1px; border-color: black; clear:both; margin:0px; padding:5px;")
    leftDiv = headlineDiv.addDiv(style="width:49%;float:left;text-align:center;margin:0px; padding:0px; line-height:100%; font-size:100%;border:0px;")
    self.addPointlessSummary(leftDiv)
    rightDiv = headlineDiv.addDiv(style="width:50%;float:left;text-align:center;margin:0px; padding:0px; line-height:100%; font-size:100%;border:1px solid black;")

    if havePointlessReport:
      self.pointlessreport.ElementScoresTable(rightDiv)
    
      details1Div = parent.addDiv(style="border-width: 1px; border-color: black; clear:both; margin:0px; padding:0px;")
      details1Div.append('<br/>')
      if havePointlessReport:
        self.pointlessreport.Details(details1Div, usefold=False, elementscores=False,
                                     all=True, open1=True)
      
      #The following is to return the html to doing one item per line
      parent.addDiv(style="width:95%; clear:both;")

  # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  def addPointlessSummary(self, parent=None):
    spacegroupDiv = parent.addDiv(
      style="text-align:center;margin:0px auto; padding:3px; \
            line-height:100%;border:1px solid black;")
    spacegroupDiv.addText(text='Space group determination',style="font-size:130%;")
    self.pointlessreport.MainMessages(spacegroupDiv)
    self.pointlessreport.Errors(spacegroupDiv)   #  report any fatal errors

  # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  def addPointlessReport(self):
    self.pointlessreport.MainMessages(self)

  # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  def addCtruncateReports(self, parent=None):
    for ctruncatereport in self.ctruncatereports:
      ctruncate_report.ctruncate_report(xmlnode=ctruncatereport, jobStatus='nooutput')
      ctruncatereport.addCtruncateReport(parent)

  # . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  def addTruncateWilson(self, parent=None):
    WilsonDiv = parent.addDiv(
      style="text-align:center;margin:0px auto; padding:1px;")
    WilsonDiv.addText(text='Wilson plot',style="font-weight:bold; font-size:130%;")
    self.ctruncatereports[0].CtruncateWilson(WilsonDiv)

  # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  def addFreerReports(self, freerxml, parent=None):
    """
    Cases:
    Status 0, Validity True:  all OK
    Status 1, Validity True:  failed due to symmetry mismatch
    Status 1, Validity False: failed due to cell mismatch
    """
    if freerxml != None:
      freeStatus = int(freerxml.select('status'))
      validity = 'True'
      freeRmessage = []
      OK = True
      if freerxml.haspath('ObsFreeCellComparison'):
        validity = freerxml.select('ObsFreeCellComparison/validity')

      printDetails = False

      if freeStatus== 0:
        # All OK, success, but possibly due to overriding the test
        freefraction = '0.05'   # default fraction in freerflag program
        if freerxml.haspath('ObsFreeCellComparison'):
          # Extending FreeR set
          freeRmessage.append(colourText('<p>A free-R set has been copied (and extended)</p>', 'green'))
        else:
          if freerxml.haspath('FreeRfraction'):
            freefraction = freerxml.select('FreeRfraction')
          freeRmessage.append(colourText('<p>A free-R set has been created, fraction of the data = '+\
                                         freefraction+'</p>', 'green'))
        if validity == 'False':
          # cell check was overridden
          printDetails = True
          freeRmessage.append(colourText(
            '<p><b>WARNING: the discrepancy between the unit cell of the extended FreeR set and the observed data has been overridden</b></p>',
            'red'))
          freeRmessage.append(colourText(
            '<p><b>Did you mean to accept this?</b></p>',
            'red'))
          OK = False
      else:
        # Not OK
        OK = False
        # basic message
        message = '<p>'+\
           'WARNING: the FreeR set has not been created, because the input FreeR set is incompatible with the new data'+\
           '<br/>An input FreeR set for copying or extending must match the current data in cell and Laue group'+\
           '<br/>You should create an appropriate FreeR set in a separate task, or if you are confident it is OK, activate the cell-test override in "Additional options"'
        freeRmessage.append(colourText(message+'</p>', 'red'))
        printDetails = True

      if printDetails and freerxml.haspath('ObsFreeCellComparison'):
        #print 'ObsFreeCellComparison'
        obs = "Observed data: SG "+freerxml.select('ObsFreeCellComparison/SGnameObserved')+\
              " Cell: "+freerxml.select('ObsFreeCellComparison/cellObserved')
        free = "FreeR data: SG "+freerxml.select('ObsFreeCellComparison/SGnameFreeR')+\
               " Cell: "+freerxml.select('ObsFreeCellComparison/cellFreeR')
        diff = "Cell difference: "+\
               freerxml.select('ObsFreeCellComparison/CellDifference')+"&#197;"+\
               ", maximum acceptable resolution for free-R extension: "+\
               freerxml.select('ObsFreeCellComparison/MaxAcceptableResolution')+"&#197;"
        if validity == 'True':
          message = colourText('The datasets belong to incompatible Laue groups',
                                     'red', fontstyle='italic', fontsize="110%")
        else:
          message = colourText('The datasets have incompatible unit cells',
                                     'red', fontstyle='italic', fontsize="110%")
          
        freeRmessage.append(message)
        freeRmessage.append(colourText('<br/>'+obs+'<br/>'+free+'<br/>'+diff, 'red'))
          
      if len(freeRmessage) > 0:
        place = parent
        if not OK:
          place = parent.addDiv(
            style="width:90%;border: 2px solid red; clear:both; margin:3px; padding:6px;")
  
        for message in freeRmessage:
          #print 'line: ', message
          place.append(message)

############################################################################
if __name__ == "__main__":

  report = aimless_pipe_report(xmlFile = sys.argv[1],jobStatus="Finished" )
  tree= report.as_etree()
  #print etree.tostring(tree,pretty_print=True)
  report.as_html_file(fileName='./test-pipeline.html')
  if len(report.errorReport())>0: print 'ERRORS:',r.errorReport()
  
