# Normally would use xpath (http://www.w3schools.com/xpath/) to access the program output but
# I've added some convenience functions (haspath(),ifselect(),select() etc) to tidy up the Python code
# So here if the program output has a TwinWarning append some text to the report.  append() parses
# the text as xml - if that fails it tries adding <p> tag around text and creates a Generic() python
# object automatically and appends that.
#


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

from aimless_pipe_utils import *

# - - - - - - - - - - - - - - - - -
class pointless_report(Report):
  TASKNAME='pointless'

  def __init__(self,xmlnode=None,jobInfo={},jobStatus=None,**kw):
    Report.__init__(self,xmlnode=xmlnode,jobInfo=jobInfo,**kw)

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

    if self.errorReport().maxSeverity()>SEVERITY_WARNING:
      print 'FAILED instantiating Pointless report generator'
      self.errorReport().report()
      return

    # Testing
    #    if self.xmlnode.haspath('POINTLESS'):
    #      print "has POINTLESS"
    #    if self.xmlnode.haspath('POINTLESS/BestSolution'):
    #      print "has POINTLESS/BestSolution"
    #    if self.xmlnode.haspath('BestSolution'):
    #      print "has BestSolution"

    # 'nooutput' mode would be used by another report class that wanted
    # to use some method(s) from this class for its own report
    if jobStatus is not None and jobStatus.lower() == 'nooutput':
      return

    # Comes here for report on Pointless subtask
    fail = self.Errors(self)

    if fail == False:
      self.justPointless(self)

  # - - - - - - - - - - - - - - - - -
  def justPointless(self, parent=None):
    parent.addText(text='POINTLESS', style='font-size: 150%;')
    displayFile(self.fileroot, parent,
                ['job_1/log.txt', './log.txt'], 'Show log file')
    summaryDiv = parent.addDiv(\
      style="width:100%;border-width: 1px; border-color: black; clear:both; margin:0px; padding:0px;")
    self.keyText(summaryDiv)
    
    mainDiv = parent.addDiv(\
      style="width:100%;border-width: 1px; border-color: black; clear:both; margin:0px; padding:0px 0px 10px 0px;")
    
    leftDiv = mainDiv.addDiv(style="width:47%;float:left;text-align:center;margin:0px; padding:0px; line-height:100%; font-size:100%;border:1px solid black;")
    rightDiv = mainDiv.addDiv(style="width:48%;float:left;text-align:center;margin:0px; padding:10px;border:1px solid black;")
    
    self.twinWarning(leftDiv)
    self.BestSolutionType(leftDiv)
    self.BestReindex(leftDiv)
    self.CopyMessage(leftDiv)
    
    self.ElementScoresTable(rightDiv)
    self.Details(self, usefold=False, elementscores=False, all=True)


  # - - - - - - - - - - - - - - - - -
  def MainMessages(self,parent=None):
    """ Main messages, for different types of Pointless runs """

#    print "MainMessages.parent", parent
#    print parent.xmlnode
#    print parent.xmlnode.tag

    # not all calls here will do anything
    self.twinWarning(parent)
#    if self.xmlnode.haspath('BestSolution'):
#      print "MainMessages parent has BestSolution"
    self.BestSolutionType(parent)
    self.BestReindex(parent)
    self.CopyMessage(parent)

  # - - - - - - - - - - - - - - - - -
  def solutionWarning(self,parent=None):
    if self.xmlnode.haspath('SolutionWarning'):
      solutionwarning = html_linebreak(self.xmlnode.select('SolutionWarning'))
      parent.append('<div style="color:red">'+solutionwarning+'</div>')

  # - - - - - - - - - - - - - - - - -
  def extraLatticeWarning(self, parent=None, addTrailer=True):
    if self.xmlnode.haspath('ExtraLatticeCentering'):
      #warning = self.xmlnode.select('ExtraLatticeCentering/Message')
      warning = self.xmlnode.select('ExtraLatticeCentering/Message')

      warning = colourText(warning, 'red', '110%')
      if addTrailer:
        warning += colourText(
          "(See details of possible lattice centering under 'Details of space group determination' below)",
          'red')
      warning = html_linebreak(warning)
      parent.append(warning)
      #parent.append('<div style="color:red">'+warning+'</div>')
      
  # - - - - - - - - - - - - - - - - -
  def setFileRoot(self, fileroot):
    ''' set file root from superior script '''
    self.fileroot = fileroot
    
  # - - - - - - - - - - - - - - - - -
  def keyText(self,parent=None):
    if self.xmlnode.haspath('BestSolutionType'):
      solutionmessage = html_linebreak(self.xmlnode.select("SolutionMessage"))
      parent.append(solutionmessage)
      self.solutionWarning(parent)

      stotalprob = self.xmlnode.select("BestSolution/TotalProb")
      sconfidence = self.xmlnode.select("BestSolution/Confidence")
      solstring = "Solution probability: %s,   Confidence %s" % (stotalprob, sconfidence)
      if self.xmlnode.haspath('ResolutionUsed'):
        testresolution = self.xmlnode.select("ResolutionUsed/ResolutionHigh")
        solstring += "   (high resolution limit for symmetry testing %s&#197;)" % testresolution

      parent.append(solstring)

    self.extraLatticeWarning(parent)

    if self.xmlnode.haspath('BestReindex'):
      source = ""
      if self.xmlnode.haspath("BestReindex/HKLREF"):
        source = self.xmlnode.select("BestReindex/HKLREF")
        #print "has BestReindex/HKLREF", source
      elif self.xmlnode.haspath("BestReindex/XYZIN"):
        source = self.xmlnode.select("BestReindex/XYZIN")

      if source is not None:
        parent.append("Reindex operator to match reference data from "+source+
                      ": "+self.xmlnode.select("BestReindex/ReindexOperator")+
                      ", probability "+self.xmlnode.select("BestReindex/Likelihood"))
      else:
        parent.append("<em>Alternative indexing comparisons to first file</em>")
        filenames   =  self.xmlnode.xpath("BestReindex/Filename")
        reindexops  =  self.xmlnode.xpath("BestReindex/ReindexOperator")
        likelihoods =  self.xmlnode.xpath("BestReindex/Likelihood")
        
        table = parent.addTable()

        numbers = []
        fnames = []
        reindexs = []
        lklihoods = []
        for i in range(len(filenames)):
          numbers.append(i+2)
          fnames.append(filenames[i].text)
          reindexs.append(reindexops[i].text)
          lklihoods.append( likelihoods[i].text)

        table.addData(title="File", data=numbers)
        table.addData(title="Filename", data=fnames)
        table.addData(title="Likelihood", data=lklihoods)
        table.addData(title="Reindex operator", data=reindexs)

      if self.xmlnode.haspath('ResolutionUsed'):
        testresolution = self.xmlnode.select("ResolutionUsed/ResolutionHigh")
        parent.append("High resolution limit for symmetry testing %sA" % testresolution)

    else:
      # No BestReindex element, probably no alternative index to test
      if self.xmlnode.haspath("ReflectionFile[@stream='HKLREF']"):
        hklreffile = self.xmlnode.xpath0("ReflectionFile[@stream='HKLREF']")
        aindx = self.xmlnode.xpath0("AlternativeIndexing").text
        # blank if no alternative indexing
        if self.xmlnode.xpath0("AlternativeIndexing").text is None:
          s = 'No alternative indexing to test relative to reference file '+\
              hklreffile.get('name')
          parent.append(s)

    self.CopyMessage(parent)

    self.AlternativeIndexWarning(parent)

  # - - - - - - - - - - - - - - - - -
  def keyTextMerged(self,parent=None):
    # for analysis of merged data

    if self.xmlnode.haspath('SquaredFs'):
      if self.xmlnode.select('SquaredFs') == 'true':
        parent.append('NOTE: Input amplitudes (F) were squared to intensities (I) for analysis')

    #print 'cellpath', self.xmlnode.xpath0('ReflectionFile/cell')
    #print 'cell', self.formatCell(self.xmlnode.xpath0('ReflectionFile/cell'), astext=True)
    #print 'SGpath', self.xmlnode.select('ReflectionFile/SpacegroupName')
    cell = self.xmlnode.xpath0('ReflectionFile/cell')
    #print 'cell', type(cell), cell
    parent.append("Unit cell: "+self.formatCell(cell, astext=True))
    parent.append("Space group: "+self.xmlnode.select('ReflectionFile/SpacegroupName'))
    
    self.extraLatticeWarning(parent)

    self.CopyMessage(parent)

    self.AlternativeIndexWarning(parent)

  # - - - - - - - - - - - - - - - - -
  def Details(self,parent=None, usefold=True, elementscores=True,
              all=False, open1=False):
    """    Folded details    """

    if usefold:
      fold = parent.addFold(label="Details of space group determination",
                            brief='SpaceGroupDetails')
    else:
      fold = parent.addDiv(
        style="padding:10px 0px 0px 0px;")
      fold.addText(text="Details of space group determination", style="font-size:120%;")

    self.IndexScores(fold, open1=open1)
    self.ExtralatticeScores(fold)
    if elementscores: self.ElementScores(fold, open1=open1)
    self.LaueGroupScores(fold, open1=open1)
    self.ZoneScores(fold, open1=open1)
    self.SpaceGroupScores(fold, open1=open1)
    self.TestDataDetails(fold, open1=open1)
    if all:
      self.AdditionalGraphs(fold)

  # - - - - - - - - - - - - - - - - -
  def isFatalError(self):
    # True if there is a FatalErrorMessage
    if self.xmlnode.haspath('FatalErrorMessage'):
      return True
    return False

  # - - - - - - - - - - - - - - - - -
  def isTwinWarning(self):
    if self.xmlnode.haspath('TwinWarning'):
      return True
    return False
      
  # - - - - - - - - - - - - - - - - -
  def Errors(self,parent=None):
    fail = False
    if self.xmlnode.haspath('FatalErrorMessage'):
      message = self.xmlnode.select('FatalErrorMessage')
      message = html_linebreak(message)
      parent.append(message)
      fail = True
    if self.xmlnode.haspath('FatalErrorMessage2'):
      message = self.xmlnode.select('FatalErrorMessage2')
      message = html_linebreak(message)
      parent.append(message)
      fail = True
    return fail
  # - - - - - - - - - - - - - - - - -
  def twinWarning(self,parent=None):
    if self.xmlnode.haspath('TwinWarning'):
      parent.append('<div style="color:red">'+
                    self.xmlnode.select('TwinWarning')
                    + '<br/>\n' + 
                   'Rough estimated twin fraction:'+
                    self.xmlnode.select("TwinFraction")+'</div>' )

  # - - - - - - - - - - - - - - - - -
  def AlternativeIndexWarning(self, parent=None):
    # add warning message if the output data has an alternative indexing and there if no reference
    if self.xmlnode.haspath('NumberPossibleReindexing'):
      nreindex = self.xmlnode.select('NumberPossibleReindexing')
      if not ((self.xmlnode.haspath("ReflectionFile[@stream='HKLREF']")) or \
             (self.xmlnode.haspath("ReflectionFile[@stream='XYZIN']"))):

        alternativelist = self.xmlnode.xpath('PossibleReindexing')
        allcellssame = True
        reindexingoperators = ""
        reindexingoperatorsanddiffs = ""
        notfirst = False
        
        for alternative in alternativelist:
          operator = alternative.select('ReindexOperator')
          celldiff = alternative.select('CellDiff')
          differentcell = (alternative.select('DifferentCell') == 'true')
          #print 'alternatives ', operator, celldiff, differentcell, alternative.select('DifferentCell')
          if celldiff != '0.00':
            allcellssame = False
          if notfirst:
            reindexingoperators += ", "
            reindexingoperatorsanddiffs += ", "
          notfirst = True
          reindexingoperators += operator
          reindexingoperatorsanddiffs += operator+" ("+celldiff+")"
          
        if allcellssame:
          message1 = "NOTE: the final selected symmetry has alternative indexing schemes, but no reference data has been given"
          reindexingoperators = "Possible alternative indexing operators: " + reindexingoperators
        else:
          message1 = "NOTE: the final selected symmetry and cell have alternative indexing schemes, but no reference data has been given"
          reindexingoperators = "Possible alternative indexing operators (with cell differences in A): "+reindexingoperatorsanddiffs

        message2 = "If you already have a matching dataset, you should choose it as a reference set to get consistent indexing"
        parent.append('<div style="color:blue"><br/>'+message1+'<br/>'+reindexingoperators+'<br/>'+message2+'</div>')
    
  # - - - - - - - - - - - - - - - - -
  def BestSolutionType(self,parent=None):
    # Dependent on a program output parameter create a Table object and call addData() to load the table
    # Here the append() method is passed the table object.
    
#    print parent
#    if self.xmlnode.haspath('BestSolution'):
#      print "BestSolutionType parent has BestSolution"

    if self.xmlnode.haspath('BestSolutionType'):
      solutionmessage = html_linebreak(self.xmlnode.select("SolutionMessage"))
      parent.append(solutionmessage)
      self.solutionWarning(parent)

      parent.append('<br/> Solution type: '+
                    self.xmlnode.select("BestSolutionType") )
      table = parent.addTable( select = "//BestSolution", transpose=True, style="margin: 0 auto;border:1px solid orange;" )
      for title,select in [ [ "Group name" , "GroupName" ],
                            [ "Reindex" , "ReindexOperator" ],
                            [ "Space group confidence" , "Confidence" ],
                            [ "Laue group confidence" , "LGconfidence" ],
                            [ "Laue group probability" , "LGProb" ],
                               [ "Systematic absence probability" , "SysAbsProb" ] ] :
        table.addData( title=title , select = select )
  # - - - - - - - - - - - - - - - - -
  def BestReindex(self,parent=None):
    # -- Indexing relative to reference file --
    if self.xmlnode.haspath('//BestReindex'):
      if self.xmlnode.ifselect("//XYZIN",False):
        parent.append('Reference reflection list generated from coordinate file'+ self.xmlnode.select("//XYZIN")+'<br/>' + \
                    'Space group '+self.xmlnode.select("//BestReindex/RefSpaceGroup") )

      else:
          if self.xmlnode.haspath("//BestReindex/RefSpaceGroup"):
            if self.xmlnode.select("//BestReindex/RefSpaceGroup") is not None:
              parent.append('Determining best alternative indexing relative to reference file: ' + 
                        '<br/> ' + self.xmlnode.select("//BestReindex/HKLREF") + '<br/>' + 
                        'Space group '+ self.xmlnode.select("//BestReindex/RefSpaceGroup")  )
          else:
            parent.append('Determining best alternative indexing relative to first input file: ')

      # xpath0 returns just the first item that satisfies the criteria
      tablenode = self.xmlnode.xpath0("BestReindex")
      if tablenode is not None:
        table = parent.addTable(select="BestReindex")
        for title,select in [ [ "File number", "Filenumber" ],
                              [ "Reindex operator" , "ReindexOperator" ],
                              [ "Confidence" , "Confidence" ],
                              [ "Likelihood" , "Likelihood" ],
                              [ "CC" , "CC" ]] :
          table.addData(tablenode , title=title , select = select )

  # - - - - - - - - - - - - - - - - -
  def AxialGraphs(self,parent=None):
    # Select only axial graphs
    # Add a Graph - add a table of data and plot instructions to the graph

    # Loop over all Graph tables in the program output and add to the GraphGroup
    # The plotting instructions are provided as xml text

    self.Graphs(parent, select="AxialReflections")

  # - - - - - - - - - - - - - - - - -
  def Graphs(self,parent=None, select=None):
    # Select only specified graphs
    # Add a Graph - add a table of data and plot instructions to the graph
    # Loop over all Graph tables in the program output and add to the GraphGroup
    # The plotting instructions are provided as xml text
    if select is None: return

    graphXmlnodeList = self.xmlnode.xpath("CCP4Table[@groupID='Graph']")

    for graphXmlnode in graphXmlnodeList:
      idt = graphXmlnode.select("@id")
      if idt.find(select) >= 0:
        graph = parent.addFlotGraph( xmlnode=graphXmlnode, title=graphXmlnode.select("@title") )
        graph.addTable( select="data", headers = 'headers' )
        graph.addPlot(  select= "plot" )

  # - - - - - - - - - - - - - - - - -
  def CopyMessage(self,parent=None):
    if self.xmlnode.haspath('CopyMessage'):
      parent.append(html_linebreak(self.xmlnode.select('CopyMessage')) + '<br/>\n')

  # - - - - - - - - - - - - - - - - -
  def TestDataDetails(self,parent=None, open1=False):

    fold = parent.addFold(label="Details of test data (in Pointless)", brief='TestData',
                          initiallyOpen=open1)
    merged = "False"
    # data is merged if "ReflectionData/NumberObservations" is absent,
    #  or if "ReflectionData/Merged" = True
    if self.xmlnode.haspath("//MergedData"):
      merged = self.xmlnode.select("//MergedData")

    if not (self.xmlnode.haspath("ReflectionData/NumberObservations")):
      merged = "True"

    if merged == "False":
      fold.append("Summary of unmerged test reflection data")

      table = fold.addTable( select = "//POINTLESS/ReflectionData", transpose=False )
      for title,select in [ [ "Max resolution", "ResolutionHigh" ],
                            [ "Nreflections", "NumberReflections" ],
                            [ "NObservations", "NumberObservations" ],
                            [ "Nparts", "NumberParts" ],
                            [ "Nbatches", "NumberBatches" ],
                            [ "Ndatasets", "NumberDatasets" ] ]:
        table.addData( title=title , select = select )

      # list of run data
      runlist = self.xmlnode.xpath("ReflectionData/Dataset/Run")
      table2 = fold.addTable()

      # List of data wanted
      for title,select in [["DatasetName", "Datasetname"],
                           ["RunNumber", "number"],
                           ["Batch range", "BatchRange"],
                           ["Phi range", "PhiRange"],
                           ["Excluded batches", "ExcludedBatches"]]:
        datalist = []
        for run in runlist:  # loop runs
          if select == 'BatchRange' or select == 'PhiRange':
            formattedRange = formatRange(run.select(select))
            #print "Range", formattedRange
            datalist.append(formattedRange)
          else:
            datalist.append(run.select(select))

        table2.addData( title=title , data = datalist )

    if (merged == "True") or self.xmlnode.haspath("ReflectionData/MergedData"):
      fold.append("Summary of merged test reflection data")
      table3 = fold.addTable(select="ReflectionData")
      for title,select in [ [ "Max resolution", "ResolutionHigh" ],
                            [ "Nreflections", "NumberReflections" ]]:
        table3.addData( title=title , select = select )

  # - - - - - - - - - - - - - - - - -
  def ExtralatticeScores(self, parent=None):
    if self.xmlnode.haspath('ExtraLatticeCentering'):
      fold = parent.addFold(label="Warning of possible lattice centering",
                            brief='ExtraLatticeCentering',
                            initiallyOpen=True)
      self.extraLatticeWarning(fold, addTrailer=False)
      meanE2absent = self.xmlnode.select("ExtraLatticeCentering/MeanE2absent")
      possiblelattice = self.xmlnode.select("ExtraLatticeCentering/LatticeType")
      #print "possiblelattice, meanE2absent", possiblelattice, meanE2absent
      text = "Mean(E^2) for reflections which would be missing in a lattice of type "+\
             possiblelattice
      text += " is "+ meanE2absent + " instead of the ideal value 1.0"
      fold.append(text)
      self.Graphs(fold, select="LatticeCentering")

  # - - - - - - - - - - - - - - - - -
  def ElementScores(self,parent=None, open1=False):
    if self.xmlnode.haspath("//BestSolutionType"):
      fold = parent.addFold(label="Scores for each symmetry element",
                            brief='SymmetryElements',
                            initiallyOpen=True)
      fold.append("Lattice group name "+\
                  self.xmlnode.select("LatticeSymmetry/LatticegroupName"))
      if self.xmlnode.haspath("LatticeSymmetry/LatticeReindex"):
        fold.append("Reindex operator from input to lattice: "+\
                    self.xmlnode.select("LatticeSymmetry/LatticeReindex"))

      table = fold.addTable(select="//ElementScores")
      for title,select in [["Likelihood", "Element/Likelihood"],
                           ["CC", "Element/CC"],
                           ["R", "Element/R"],
                           ["", "Element/ElementScoreStars"],
                           ["Symmetry", "Element/SymmetryElementString"]]:
        table.addData( title=title , select = select )

  # - - - - - - - - - - - - - - - - -
  def shortsym(self,symstring):
    if symstring.count('{') < 2:
        # only one operator, leave unchanged
        return symstring
    # otherwise remove the second opreator
    f = symstring.rsplit('{')
    return f[0]+'{'+f[1]
  # - - - - - - - - - - - - - - - - -
  def ElementScoresTable(self,parent=None):
    # short form for embedding in other div
    if self.xmlnode.haspath("//BestSolutionType"):
      parent.addText(text="Scores for each symmetry element", style="font-size:120%;")
      parent.append("Lattice group name "+\
                  self.xmlnode.select("LatticeSymmetry/LatticegroupName"))
      if self.xmlnode.haspath("LatticeSymmetry/LatticeReindex"):
        parent.append("Reindex operator from input to lattice: "+\
                    self.xmlnode.select("LatticeSymmetry/LatticeReindex"))

      xlikelihoods = self.xmlnode.xpath("//ElementScores/Element/Likelihood")
      xCCs = self.xmlnode.xpath("//ElementScores/Element/CC")
      xRs = self.xmlnode.xpath("//ElementScores/Element/R")
      xstars = self.xmlnode.xpath("//ElementScores/Element/ElementScoreStars")
      xsymmetries = self.xmlnode.xpath("//ElementScores/Element/SymmetryElementString")

      likelihoods = []
      CCs = []
      Rs = []
      stars = []
      symmetries = []
      for i in range(len(xCCs)):
        likelihoods.append(xlikelihoods[i].text)
        CCs.append(xCCs[i].text)
        Rs.append(xRs[i].text)
        stars.append(xstars[i].text)
        # Abbreviate symmetry element to fit
        symmetries.append(self.shortsym(xsymmetries[i].text))

      #print "syms", symmetries
      table = parent.addTable()
      table.addData(title="Likelihood", data=likelihoods)
      table.addData(title="CC", data=CCs)
      table.addData(title="R", data=Rs)
      table.addData(title="", data=stars)
      table.addData(title="Symmetry", data=symmetries)

  # - - - - - - - - - - - - - - - - -
  def LaueGroupScores(self,parent=None, open1=False):
    if self.xmlnode.haspath("//LaueGroupScoreList"):
      fold = parent.addFold(label="Scores for each Laue group", brief='Laue group',
                            initiallyOpen=open1)
      note = 'Accept flags: ">", accepted; "=" original accepted; "-" original rejected<br/>'+\
             'Dcell: maximum cell difference in degrees'
      fold.append(note)
      table = fold.addTable(select="//LaueGroupScoreList")
      for title,select in [["Accept", "LaueGroupScore/LaueGroupScoreString"],
                           ["Group", "LaueGroupScore/LaueGroupName"],
                           ["", "LaueGroupScore/LaueGroupScoreStars"],
                           ["Lklhd", "LaueGroupScore/Likelihood"],
                           ["NetZ CC", "LaueGroupScore/NetZCC"],
                           ["ZCC+", "LaueGroupScore/ZCC_plus"],
                           ["ZCC-", "LaueGroupScore/ZCC_minus"],
                           ["CC", "LaueGroupScore/CC"],
                           ["R", "LaueGroupScore/R"],
                           ["Dcell", "LaueGroupScore/CellDelta"],
                           ["Reindex", "LaueGroupScore/ReindexOperator"]]:
        table.addData( title=title , select = select )

  # - - - - - - - - - - - - - - - - -
  def ZoneScores(self,parent=None, open1=False):
    if self.xmlnode.haspath("//ZoneScoreList"):
      fold = parent.addFold(label="Systematic absence analysis for each zone",
                            brief='Absences', initiallyOpen=open1)

      zonelauegroups = self.xmlnode.xpath("ZoneScoreList/ZoneLaueGroup")

      for zlg in zonelauegroups:  # loop Laue groups (usually only 1)
        fold.append("Systematic absence analysis for each zone, Laue group "+\
                    zlg.select("@name"))

        # list of zones in group
        zonenodelist = zlg.xpath("Zone")

        stars = []
        missing = False
        empty = False

        for znode in zonenodelist:          # loop zones
          nobs = znode.select("Nobs")

          if znode.haspath("MissingData"):
            # Case 1, systematic missing data
            stars.append("Missing")
            missing = True
          elif (int(nobs) == 0):
            # Case 2, no observations
            stars.append("Empty")
            empty = True
          else:
            # Case 3, data found and used
            stars.append(znode.select("ZoneScoreStars"))

          # end loop zones

        message = ""
        if empty:
          message += "'Empty' means no observations for this zone<br/>"
        if missing:
          message += \
            "'Missing' means data for this zone are systematically absent,"+\
            " may have been removed previously"
        if message != "":
          fold.append(message)

        # table for zones in this group
        table = fold.addTable(xmlnode=zlg)
        table.addData(title="Zone", select="Zone/ZoneType")
        table.addData(title="PeakHeight", select="Zone/PeakHeight")
        table.addData(title="SD", select="Zone/SDPkHt")
        table.addData(title="", data=stars)
        table.addData(title="Probability", select="Zone/Prob")
        table.addData(title="Nobs", select="Zone/Nobs")
        table.addData(title="ReflectionCondition", select="Zone/Condition")

      # end loop Laue groups

      self.AxialGraphs(fold)

  # - - - - - - - - - - - - - - - - -
  def SpaceGroupScores(self,parent=None, open1=False):
    if self.xmlnode.haspath("//SolutionMessage"):
      fold = parent.addFold(label="Scores for possible space groups",brief='SpaceGroupScores',
                            initiallyOpen=open1)

      fold.append("<p>"+self.xmlnode.select("SolutionMessage")+"</p>")

      msg = " 'Reindex' is the operator to convert from the input hklin frame to the standard spacegroup frame.<br/>"+\
            " 'TotalProb' is a total probability estimate (unnormalised)<br/>"+\
            " 'SysAbsProb' is an estimate of the probability of the space group from observed systematic absences.<br/>"+\
            " 'Conditions' are the reflection conditions (absences)"
      fold.append(msg)


      table = fold.addTable(select="//SpacegroupList")
      for title,select in [["Spacegroup", "Spacegroup/SpacegroupName"],
                           ["ITnumber", "Spacegroup/SGnumber"],
                           ["TotalProb", "Spacegroup/TotalProb"],
                           ["SysAbsProb", "Spacegroup/SysAbsProb"],
                           ["Reindex", "Spacegroup/ReindexOperator"],
                           ["Conditions", "Spacegroup/Condition"]]:
        table.addData( title=title , select = select )

  # - - - - - - - - - - - - - - - - -
  def IndexScores(self,parent=None, open1=False):
    if self.xmlnode.haspath("//IndexScores"):
      fold = parent.addFold(label="Alternative index scores",brief='IndexScores',
                            initiallyOpen=open1)
      if self.xmlnode.ifselect("XYZREF",False):
        fold.append('Reference reflection list generated from coordinate file'+ \
                    self.xmlnode.select("XYZREF")+'<br/>' + \
                    'Space group '+self.xmlnode.select("XYZREFspacegroup") )

      else:
        if self.xmlnode.haspath("//BestReindex/RefSpaceGroup"):
          if self.xmlnode.select("//BestReindex/RefSpaceGroup") is not None:
            fold.append('Determining best alternative indexing relative to reference file: ' + \
                        self.xmlnode.select("//BestReindex/HKLREF") + '<br/>' + \
                        'Space group '+ self.xmlnode.select("//BestReindex/RefSpaceGroup")  )
        else:
            fold.append('Determining best alternative indexing relative to first input file: ')            

      fold.append('Possible reindex operators: '+ self.xmlnode.select("//AlternativeIndexing") )

      # there may be multiple IndexScores blocks
      tablenodes = self.xmlnode.xpath("IndexScores")  # list of blocks
      if tablenodes is not None:
        for tablenode in tablenodes:
          table = fold.addTable(select="IndexScores")
          for title,select in [ [ "Reindex operator" , "Index/ReindexOperator" ],
                                [  "Likelihood" , "Index/Likelihood" ],
                                [ "CC" , "Index/CC" ] ] :
            table.addData(tablenode , title=title , select = select )


  # - - - - - - - - - - - - - - - - -
  def AdditionalGraphs(self,parent=None):
    """ Resolution and twinning graphs"""
    id1 = "Resolution estimate from Pointless"
    id2 = "L-test"
    if (self.xmlnode.haspath("//CCP4Table[@id='"+id1+"']")) or \
       (self.xmlnode.haspath("//CCP4Table[@id='"+id2+"']")):
      fold = parent.addFold(label="Resolution analysis for score cutoff and twinning",
                            brief='Cutoff/Twin',
                            initiallyOpen=True)

      leftDiv = fold.addDiv(style="width:47%;float:left;text-align:left;margin:0px; padding:0px; line-height:100%; font-size:100%;")
      rightDiv = fold.addDiv(style="width:48%;float:left;text-align:left;margin:0px; padding:10px;")
      self.ResolutionGraphs(leftDiv, idt=id1)
      self.TwinningGraphs(rightDiv, idt=id2)
    
  # - - - - - - - - - - - - - - - - -
  def ResolutionGraphs(self,parent=None, idt=None):
    if idt is None: return
    if self.xmlnode.haspath("//CCP4Table[@id='"+idt+"']"):
      self.Graphs(parent, select=idt)

    if self.xmlnode.haspath('CutoffMessage'):
      s = self.xmlnode.select('CutoffMessage') + "\n"
      s += "Highest resolution used : "+\
           self.xmlnode.select('ResolutionUsed/ResolutionHigh')+"A\n"
      s += " Estimate from I/sigI  > " + self.xmlnode.select('IovSigCutoff')+\
           " : " + self.xmlnode.select('ResolutionHighIovsigI') + "A\n"
      s += " Estimate from CC(1/2) > " + self.xmlnode.select('CCHalfCutoff')+\
               " : " + self.xmlnode.select('ResolutionHighCCHalf') + "A\n"
      parent.append(html_linebreak(s))
  # - - - - - - - - - - - - - - - - -
  def TwinningGraphs(self,parent=None, idt=None):
    if idt is None: return
    self.Graphs(parent, select=idt)

    if self.xmlnode.haspath('TwinWarning'):
      s = self.xmlnode.select('TwinWarning')+"\n"+\
          " Estimated fraction: "+self.xmlnode.select('TwinFraction')
      parent.append(html_linebreak(s))
  # - - - - - - - - - - - - - - - - -
  def formatCell(self, cellxml, astext=False):
    # astext = False, return list[[a,b,c,][alpha,beta,gamma]
    # astext = True,  return plain text
    a = cellxml.select('a')
    b = cellxml.select('b')
    c = cellxml.select('c')
    alpha = cellxml.select('alpha')
    beta = cellxml.select('beta')
    gamma = cellxml.select('gamma')
    if astext:
      return a+b+c+alpha+beta+gamma
    else:
      return [[a,b,c],[alpha,beta,gamma]]


############################################################################
if __name__ == "__main__":
#  report = PointlessReport(xmlFile = os.path.join(os.environ['CCP4I2_TOP'],'test','report_test','gam_1.xml' ))

  report = pointless_report(xmlFile = sys.argv[1] )
  tree= report.as_etree()
  #  print etree.tostring(tree,pretty_print=True)
  report.as_html_file(fileName='./test.html')
