
"""
     CCP4ContainerView.py: CCP4 GUI Project
     Copyright (C) 2011 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.
"""

"""
     Liz Potterton Jan 2011 - CContainerView - autogenerated GUI
"""


from PyQt4 import QtGui,QtCore
from CCP4ErrorHandling import *
from CCP4Config import DEVELOPER
from CCP4Modules import  WEBBROWSER,PROJECTSMANAGER


#-----------------------------------------------------------------
class CContainerView(QtGui.QFrame):
#-----------------------------------------------------------------

  WIDTH = 600

  SEPERATOR_TEXT = { 'inputData' : 'Input data',
                   'outputData' : 'Output data',
                   'controlParameters' : 'Control parameters' }

  ERROR_CODES = { 101 : { 'description' : 'Attempting to set invalid container'  },
                  102 : { 'severity' : SEVERITY_WARNING,
                        'description' : 'Attempting to set container without data order information'},
                  103 : { 'description' : 'Unrecognised error attempting to create widget for:' },
                  104 : { 'description' : 'Error attempting to update widget from model for:' },
                  105 : {'description' : 'Internal error handing file - no task container' },
                  106 : { 'description' : 'Error attempting to update model from widget for:' },
              }

  def __init__(self,parent=None,charWidth=10,container=None,projectId=None,jobId=None,folderAttributes=None):
    QtGui.QFrame.__init__(self,parent)
    self._showOutputData = False
    self._container = container
    self._projectId = projectId
    self._jobId = jobId
    import CCP4TaskWidget
    if folderAttributes is None:
      self.folderAttributes = CCP4TaskWidget.CFolderAttributes()
    else:
      self.folderAttributes =folderAttributes
    self.grid = QtGui.QVBoxLayout()
    #layout.setSizeConstraint(QtGui.QLayout.SetMinAndMaxSize)
    self.charWidth = charWidth
    self.vLayout = None
    self.tabWidget = None
    self.lastRow=-1

    self.setStyleSheet('QFrame [isValid="false"] { border: 1px solid red; }')
    
    #self.draw()

  def taskName(self):
    header = self._container.getHeader()
    if header is not None:
      return str(header.pluginName)
    else:
      return None

  def title(self):
    name = self._container.objectName()
    if name in ['inputData','controlParameters']:
      return ['Input','Control parameters'][['inputData','controlParameters'].index(name)]
    else:
      return name

  def isEditor(self):
    return False

  def setProjectId(self,projectId):
    self._projectId = projectId

  def projectId(self):
    return self._projectId

  def jobId(self):
    return self._jobId

  def jobNumber(self):
    if self._jobId is None:
      return None
    else:
      return PROJECTSMANAGER().db().getJobInfo(self._jobId,mode='jobnumber')

  def setJobId(self,jobId):
    self._jobId = jobId

  def setMessage(self,text=None,parameter=None):
    pass
  
  def getContainer(self):
    return self._container
  
  def setContainer(self,value):
    self._container = value
    
  container = property(getContainer,setContainer)
    

  def setFollowJobId(self,jobId,force=True):
    self._container.guiAdmin.followFrom = jobId
    widget = self.getWidget('followFrom')
    if widget is not None:
      widget.updateInputFiles(jobId,self._projectId,force)
      widget.updateViewFromModel()

  def getWidget(self,name):
    w = self.findChild(QtGui.QWidget,name)
    #print 'CContainerView.getWidget',name,w
    return w

  def setDefaultParameters(self):
    pass

  def setDefaultFiles(self):
    pass
  
  def draw(self):
    import CCP4Container,CCP4Widgets,CCP4Data,CCP4File
    myException = CException()
    import CCP4DataManager
    #print 'CContainerView.draw',self._container

    # Beware screwing up dataOrder
    keyList = []
    keyList.extend(self._container.dataOrder())
    if self._container.objectName() == 'inputData':
      if self.folderAttributes.attribute(attribute='editable',folderFunction='inputData'):
        keyList.insert(0,'followFrom')
      keyList.insert(0,'jobTitle')
    for name in keyList:
      if name in ['jobTitle','followFrom']:
        model=self._container.parent().guiAdmin.__getattr__(name)
      else:
        model=getattr(self._container,name)
      if isinstance(model,CCP4Container.CContainer):
        if (self._showOutputData or model.objectName() != 'outputData') and not model.objectName() in ['guiAdmin']:
          if self.tabWidget is None:
            self.tabWidget = QtGui.QTabWidget(self)
          tab = CContainerView(self,charWidth=self.charWidth,container=model,projectId=self.projectId(),jobId=self.jobId(),folderAttributes=self.folderAttributes)
          tab.draw()
          self.tabWidget.addTab(tab,tab.title())
      else:
        widget = None
        qualifiers = {}
        if not self.folderAttributes.attribute(attribute='editable',folderFunction=model.objectName()):
          qualifiers['editable']=False
        qualifiers.update(model.qualifiers())
        if DEVELOPER():
           widget = CCP4DataManager.DATAMANAGER().widget(model=model,parentWidget=self,name=name,qualifiers=qualifiers)
        else:
          try:
            widget = CCP4DataManager.DATAMANAGER().widget(model=model,parentWidget=self,name=name,qualifiers=qualifiers)
          except CException as e:
            myException.extend(e)
          except:
            myException.append(self.__class__,103,'Data object: '+name)
        
        #print 'CContainerViewer.draw',name,model.__class__,widget,qualifiers
        if widget is not None:
          widget.setObjectName(name)
          self.lastRow = self.lastRow+1
          if isinstance(model,CCP4Data.CList):
            line_layout = QtGui.QVBoxLayout()
          else:
            line_layout = QtGui.QHBoxLayout()
          line_layout.setSpacing(0)
          line_layout.setContentsMargins(0,0,0,0)
          if not isinstance(model,(CCP4File.CDataFile,CCP4Data.CFollowFromJob)):
            if isinstance(model,CCP4Data.CList):
              line_layout = QtGui.QVBoxLayout()
            else:
              line_layout = QtGui.QHBoxLayout()
            line_layout.setSpacing(0)
            line_layout.setContentsMargins(0,0,0,0)
            labelText = qualifiers.get('guiLabel',None)
            if labelText is None or labelText is NotImplemented: labelText = name
            label = QtGui.QLabel(labelText,self)
            label.setMinimumWidth(100)
            if isinstance(model,CCP4Data.CBoolean):
              line_layout.addWidget(widget)
              line_layout.addWidget(label)
            else:
              widget.setMaximumWidth(CContainerView.WIDTH-116)
              widget.setMinimumWidth(CContainerView.WIDTH-116)
              line_layout.addWidget(label)
              line_layout.addWidget(widget)
            charWidth =  model.qualifiers('charWidth')
            if charWidth is not NotImplemented and charWidth>0:
              line_layout.addStretch(0.5)
            else:
               line_layout.addStretch(5)
            if self.vLayout is None:
              self.vLayout = QtGui.QVBoxLayout()
              self.vLayout.setSpacing(0)
              self.vLayout.setContentsMargins(0,0,0,0)
            self.vLayout.addLayout(line_layout)
          else:
            #widget.setMaximumWidth(CContainerView.WIDTH-16)
            widget.setMinimumWidth(CContainerView.WIDTH-16)
            if hasattr(self,'vLayout') and self.vLayout is not None:
              self.vLayout.addWidget(widget)
          widget.updateViewFromModel()
    if self.vLayout is not None: self.vLayout.addStretch(1)
    if self.vLayout is not None: self.grid.addLayout(self.vLayout)
    if self.tabWidget is not None: self.grid.addWidget(self.tabWidget)
    self.setLayout(self.grid)
 
    return myException

  def visibleFolder(self):
    return str(self.tabWidget.tabText(self.tabWidget.currentIndex()))

  def setVisibleFolder(self,title=None,index=None):
    if index is None:
      for ii in range(self.tabWidget.count()):
        if title == str(self.tabWidget.tabText(ii)):
          index = ii
          break
    if index is not None:
      self.tabWidget.setCurrentIndex(index)

    
  def updateViewFromModel(self):
    rv = CErrorReport()
    import CCP4Widgets
    widgetList = self.findChildren(CCP4Widgets.CViewWidget)
    for widget in widgetList:
      try:
        widget.updateViewFromModel()
      except:
        rv.append(self.__class__,104,str(widget.objectName()))
    return rv

  def updateModelFromView(self,textOnly=False):
    rv = CErrorReport()
    import CCP4Widgets
    widgetList = self.findChildren(CCP4Widgets.CViewWidget)
    #print 'CContainerView.updateModelFromView',widgetList
    for widget in widgetList:
      try:
        if textOnly:
          widget.updateModelFromText()
        else:
          widget.updateModelFromView()
      except:
        rv.append(self.__class__,106,str(widget.objectName()))
    return rv

  def saveData(self,fileName,projectName=None,jobNumber=None):
    #print 'CTaskViewer.saveData',fileName
    container = self.container()
    if container is None:
      e = CException(self.__class__,105,fileName)
      e.warningMessage()
      return

    import CCP4File
    f = CCP4File.CI2XmlDataFile(fullPath=fileName)
    cHeader =  self.container().getHeader()
    if cHeader is not None:  f.header.set(cHeader)
    f.header.setCurrent()
    f.header.function = 'PARAMS'
    if projectName is not None: f.header.project.set(projectName)
    if jobNumber is not None: f.header.jobId.set(jobNumber)
    
    bodyEtree = self.container().getEtree()
    f.saveFile(bodyEtree=bodyEtree)
 
  def validate(self):
    pass
  
  
  def isValid(self):
    import CCP4Widgets
    widgetList = self.findChildren(CCP4Widgets.CViewWidget)
    invalidList = []
    for widget in widgetList:
      if widget.isValid is not None and not widget.isValid:
        if getattr(widget,'model',None) is not None:
          #print 'CTaskWidget.isValid',widget.model.objectName(),widget.isValid
          invalidList.append(widget.model.objectName())
        else:
          invalidList.append(str(widget))
    return invalidList

  def fix(self):
    # Dummy method to be reimplemented in sub-class
    # Called after user clicks run button and before validate()
    # Probably should be used mostly to ensure that if there are
    # possible alternate input files then only one has a set value
    # (this is to prevent unused files being recorded in database)

    return CErrorReport()
  
  def saveToXml(self,fileName=None,jobInfo={}):
    self.updateModelFromView()
    import CCP4File
    if fileName is None:
        fileName = PROJECTSMANAGER().makeFileName(jobId=self._jobId,mode='JOB_INPUT')

    jobInfo = {}
    if self._jobId is not None:
      try:
        jobInfo =  PROJECTSMANAGER().db().getJobInfo(jobId=self._jobId,mode=['taskname','jobnumber','projectname','status','projectid'])
      except:
        pass
      
    f = CCP4File.CI2XmlDataFile(fullPath=fileName)
    cHeader =  self.container.getHeader()
    if cHeader is not None:  f.header.set(cHeader)
    f.header.setCurrent()
    f.header.function = 'PARAMS'
    f.header.jobId.set(self._jobId)
    f.header.projectId.set(self._projectId)
    if jobInfo.get('jobnumber',None) is not None: f.header.jobNumber.set(jobInfo['jobnumber'])
    if jobInfo.get('projectname',None) is not None: f.header.projectName.set(jobInfo['projectname'])

    bodyEtree = self._container.getEtree()       
    from lxml import etree
    f.saveFile(bodyEtree=bodyEtree)
    #print 'CContainerView.saveToXml DONE',fileName,jobInfo
    
  def resetJobCombos(self):
    import CCP4Widgets
    #print 'CTabTaskWidget.resetJobCombos'
    widgetList = self.findChildren(CCP4Widgets.CDataFileView)
    for widget in widgetList:
      widget.loadJobCombo()
      widget.updateJobCombo()
      widget.updateModelFromView()

  def taskValidity(self):
    return CErrorReport()

  def setMessage(self,text='',parameter=None):
    return
    if text is None: text = ''
    self.message.setText(text)
    self.messageStack.append([parameter,text])
    #print 'setMessage',text,parameter,self.messageStack
    
  def unsetMessage(self,parameter=None):
    return
    if len(self.messageStack)==0: return
    if self.messageStack[-1][0] == parameter:
      del self.messageStack[-1]
    else:
      delFrom = None
      for ii in range(len(self.messageStack)-2,-1,-1):
        if self.messageStack[ii][0] == parameter:
          delFrom = ii
      if delFrom is not None:
        #print 'unsetMessage deleting multi levels of stack',self.messageStack,delFrom
        del self.messageStack[delFrom:-1]

    #print 'unsetMessage',parameter,self.messageStack
    if len(self.messageStack)>0:
        self.message.setText(self.messageStack[-1][1])

  def updateMessage(self,text='',parameter=None):
    return
    for ii in range(len(self.messageStack)):
      if self.messageStack[ii][0] == parameter:
        if text is None: text = ''
        self.messageStack[ii][1] = text
    if len(self.messageStack)>0:
      self.message.setText(self.messageStack[-1][1])
    #print 'updateMessage',text,parameter,self.messageStack
