"""
     CCP4DbApi.py: CCP4 GUI Project
     Copyright (C) 2012 STFC

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

# May 2012 Tools to handle import/export of files

from PyQt4 import QtCore,QtGui
from qtgui import CCP4Widgets
from core import CCP4File,CCP4Annotation,CCP4Data
from core.CCP4ErrorHandling import *
from core.CCP4Modules import PROJECTSMANAGER,TASKMANAGER,PREFERENCES
from core.CCP4DataManager import DATAMANAGER

import os

class CExportedFileCombo(CCP4Widgets.CComplexLineWidget):
  
  MODEL_CLASS = CCP4File.CExportedFile
  
  def __init__(self,parent=None,model=None,qualifiers={}):
    CCP4Widgets.CComplexLineWidget.__init__(self,parent,qualifiers=qualifiers)
    self.widget = CCP4Widgets.CComboBox(self)
    self.widget.setEditable(False)
    self.layout().addWidget(self.widget)
    self.fileTypeClass = qualifiers.get('fileTypeClass',None)
    self.before = qualifiers.get('before',None)
    self.projectId = None
    self.setProjectId(qualifiers.get('projectId',None))
    #print 'CExportedFileCombo',qualifiers    
    self.setModel(model)
    self.updateViewFromModel()
    self.connect(self.widget,QtCore.SIGNAL('currentIndexChanged(int)'),self.updateModelFromView0)


  def setProjectId(self,projectId=None):
    self.projectId = projectId
    self.widget.clear()
    if self.projectId is not None: self.load()

  def setValue(self,value):
    #print 'CExportedFileCombo.setValue',value
    expId = value.get('exportId',None)
    if expId is None or expId < 0:
      self.widget.setCurrentIndex(0)
    else:
      indx = self.widget.findData(QtCore.QVariant(expId))
      if indx>=0: self.widget.setCurrentIndex(indx)
    
  
  def load(self):
    exportedFiles = PROJECTSMANAGER().db().getExportFilesByFileType(fileTypeClass=self.fileTypeClass,before=self.before,projectId=self.projectId)
    self.widget.addItem('',QtCore.QVariant(-1))
    for exFile in exportedFiles:
      title = TASKMANAGER().getTitle(exFile['taskname'])
      if len(exFile['exportfilename'])>22:
        self.widget.addItem('..'+exFile['exportfilename'][-20:]+' '+exFile['jobnumber']+' '+title,QtCore.QVariant(exFile['exportid']))
      else:
        self.widget.addItem(exFile['exportfilename']+' '+exFile['jobnumber']+' '+title,QtCore.QVariant(exFile['exportid']))
        
  def getValue(self):
    #print 'CExportedFileCombo.getValue',self.widget.currentIndex(),item,type(item)
    indx = CCP4Data.varToUUID( self.widget.itemData(self.widget.currentIndex()) )
    return { 'exportId' : indx }

  def updateModelFromView0(self,indx):
    self.updateModelFromView()

class CExportedFileListView(CCP4Widgets.CListView):
  
  MODEL_CLASS = CCP4File.CExportedFileList
  def __init__(self,parent,model=None,qualifiers={},**kw):
    qualis = { 
               'editorClassName' : 'CExportedFileCombo',
               'dragType' : 'file_info' 
               }
    qualis.update(qualifiers)
    qualis.update(kw)
    CCP4Widgets.CListView.__init__(self,parent,model=model,qualifiers=qualis,editorQualifiers={'before':qualis.get('before',None)})


class CImportInfo(QtGui.QFrame):

  def __init__(self,parent,model=None,importId=None,importFileName=None,label=None,sourceFileAnnotation=''):
    QtGui.QFrame.__init__(self,parent)
    self.setMinimumWidth(500)
    self.model = model
    self.importId = importId
    if importId is not None:
      importFileInfo = PROJECTSMANAGER().db().getImportFileInfo(importId=importId)
      before = importFileInfo.get('creationtime')
      if importFileInfo.get('annotation',None) is not None:
        sourceFileAnnotation = sourceFileAnnotation + importFileInfo['annotation']
      sourceFileName = importFileInfo['sourcefilename']
    else:
      before = None
      if importFileName is not None:
        sourceFileName = importFileName
      else:
        try:
          sourceFileName = model.getSourceFileName()
        except:
          sourceFileName = model.__str__()
    #print 'CImportInfo',importId,before,sourceFileName
    try:
      self.parent().setWindowTitle('Provenance of file: '+os.path.split(sourceFileName)[1])
    except:
      pass
 
    self.setLayout(QtGui.QVBoxLayout())
    if label is None:
      label = 'Provide info on the origin of the file: '
    else:
      label = 'Provide info on the origin of '+label+' from the file:'
    self.layout().addWidget(QtGui.QLabel(label))
    self.layout().addWidget(QtGui.QLabel(sourceFileName))

    self.annotation = CCP4Annotation.CAnnotation(parent=self)
    self.annotation.text.set(sourceFileAnnotation)
    self.annotationView = DATAMANAGER().widget(model=self.annotation,parentWidget=self, qualifiers = { 'multiLine' : True, 'title' : 'Describe source of this file' } )
    #print 'CImportInfo.__init__',self.annotationView,self.annotationView.model,repr(self.annotation),self.annotation
    self.annotationView.updateViewFromModel()
    self.annotationView.setMaximumHeight(150)
    self.layout().addWidget(self.annotationView)

    self.exportedFiles = CCP4File.CExportedFileList(parent=self)
    self.exportedFilesView = DATAMANAGER().widget(model=self.exportedFiles,parentWidget=self , qualifiers = { 'title' :'Select any previously exported files used to derive this file', 'before' : before } )
    self.exportedFilesView.setMaximumHeight(150)
    self.layout().addWidget(self.exportedFilesView)

  def save(self):
    self.annotationView.updateModelFromView()
    #print 'CImportInfo.save',self.annotation.get('text').__str__()
    if self.importId is not None:
      if self.annotation.isSet():
        anno = self.annotation.get('text').__str__()
      else:
        anno = ''
      PROJECTSMANAGER().db().updateImportFile(importId=self.importId,key='annotation',value=anno)
    else:
      anno = self.annotation.get('text').__str__()
      if len(anno)>0:
        self.model.__dict__['sourceFileAnnotation'] = anno
      
        
class CImportInfoDialog(QtGui.QDialog):
  def __init__(self,parent,model=None,importId=None,importFileName=None,label=None,sourceFileAnnotation=''):
    # Expect input model to be set to a CDataFile if this is called for a freshly imported file
    # for a job that has not yet been run (so no files and importFiles yet saved to db)
    # Expect database importId and importFileName if eiting the import annotation after the
    # job has been run
    #print 'CImportInfoDialog',model,importFileName
    QtGui.QDialog.__init__(self,parent)
    self.setModal(True)
    self.setLayout(QtGui.QVBoxLayout())
    self.showAutoWidget = QtGui.QCheckBox('Show this window automatically when importing a file (can be changed via Preferences)',self)
    self.connect(self.showAutoWidget,QtCore.SIGNAL('toggled(bool)'),self.handleShowAuto)
    self.layout().addWidget(self.showAutoWidget)
    #self.layout().addWidget(QtGui.QLabel('This window accessible from the file icon menu',self))
    if PREFERENCES().AUTO_INFO_ON_FILE_IMPORT:
      self.showAutoWidget.setCheckState(QtCore.Qt.Checked)
    else:
      self.showAutoWidget.setCheckState(QtCore.Qt.Unchecked)
    self.infoWidget = CImportInfo(self,model=model,importId=importId,importFileName=importFileName,label=label,
                                  sourceFileAnnotation=sourceFileAnnotation)
    self.layout().addWidget(self.infoWidget)
    butBox = QtGui.QDialogButtonBox(self)
    self.layout().addWidget(butBox)
    but = butBox.addButton(QtGui.QDialogButtonBox.Ok)
    but.setAutoDefault(0)
    self.connect(but,QtCore.SIGNAL('released()'),self.saveInfo)
    but = butBox.addButton(QtGui.QDialogButtonBox.Cancel)
    but.setAutoDefault(0)
    self.connect(but,QtCore.SIGNAL('released()'),self.close)

  def setProjectId(self,projectId):
    self.infoWidget.exportedFilesView.editor.setProjectId(projectId)

  def saveInfo(self):
    self.infoWidget.save()
    self.close()

  def handleShowAuto(self,auto):
    #print 'CImportInfoDialog.handleShowAuto',auto
    PREFERENCES().AUTO_INFO_ON_FILE_IMPORT = auto
    PREFERENCES().save()

class CManageImportFiles(QtGui.QDialog):
  def __init__(self,parent,projectId):
    QtGui.QDialog.__init__(self,parent)
    self.setModal(False)
    self.projectId = projectId
    self.setLayout(QtGui.QHBoxLayout())
    self.fileList = CImportFileList(self)   
    self.layout().addWidget(self.fileList )
    self.fileList.load(self.projectId)
    butLayout = QtGui.QVBoxLayout()
    for label,connect in [['Edit info',self.editInfo],['Delete',self.deleteFile]]:
      but = QtGui.QPushButton(label,self)
      self.connect(but,QtCore.SIGNAL('released()'),connect)
      butLayout.addWidget(but)
    self.layout().addLayout(butLayout)
    self.importInfoGui = None
    self.deleteFilesGui = None
    self.connect(PROJECTSMANAGER().db(),QtCore.SIGNAL('jobDeleted'),self.fileList.handleJobDeleted)


  def editInfo(self):
    rv = self.fileList.currentSelection()
    if rv is None: return
    importId,fileId,jobId,fileName = rv
    if self.importInfoGui is not None:
      self.importInfoGui.hide()
      self.importInfoGui.deleteLater()
    self.importInfoGui = CImportInfoDialog(self,importFileName=fileName,importId=importId)
    self.importInfoGui.show()
    
  def deleteFile(self):
    rv = self.fileList.currentSelection()
    if rv is None: return
    importId,fileId,jobId,fileName = rv
    #followOnJobs = PROJECTSMANAGER().db().getFollowOnJobs(jobId=jobId)
    jobTree = PROJECTSMANAGER().db().getFollowOnJobs(jobId=jobId)
    delJobId,importFiles,followOnJobs = jobTree
    
    from qtgui import CCP4ProjectViewer
    self.deleteJobGui = CCP4ProjectViewer.CDeleteJobGui(self,projectId=self.projectId,jobIdList=[jobId],jobTreeList=[jobTree], 
                                           label='Delete jobs that use imported file:'+fileName,deleteImportFiles=True)
    self.deleteJobGui.show()

class CImportFileList(QtGui.QTreeWidget):
  def __init__(self,parent):
    QtGui.QTreeWidget.__init__(self,parent)
    self.setColumnCount(5)
    self.setHeaderLabels(['Source file','Saved as','Date','Job number','Task name'])
    self.setColumnWidth(0,200)
    self.setColumnWidth(1,200)
    self.setColumnWidth(2,60)
    self.setColumnWidth(3,60)
    self.setColumnWidth(4,200)
    self.setMinimumWidth(460)
    self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
    self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
    self.projectId = None
    self.connect(PROJECTSMANAGER().db(),QtCore.SIGNAL('importFileDeleted'),self.handleImportFileDeleted)

                          
  def load(self,projectId):
    # This returns list of: ImportId,JobId,FileID,FileTypeId,Filename,Annotation, JobNumber TaskName SourceFileName CreateTime
    #                          0        1       2        3         4           5        6        7         8            9
    self.projectId = projectId
    self.clear()
    fileInfoList = PROJECTSMANAGER().db().getProjectImportFiles(projectId=projectId,ifJobInfo=True)
    for fileInfo in fileInfoList:
      taskTitle = TASKMANAGER().getTitle(fileInfo[7])
      qList = QtCore.QStringList()
      for item in [fileInfo[8],fileInfo[4],fileInfo[9],fileInfo[6],taskTitle]: qList.append(str(item))
      item = QtGui.QTreeWidgetItem(qList)
      item.setData(0,QtCore.Qt.UserRole,QtCore.QVariant(fileInfo[0]))
      item.setData(1,QtCore.Qt.UserRole,QtCore.QVariant(fileInfo[1]))
      item.setData(2,QtCore.Qt.UserRole,QtCore.QVariant(fileInfo[2]))
      treeId=self.addTopLevelItem(item)

  def handleImportFileDeleted(self,args):
    #print 'CImportFileList.handleImportFileDeleted',args
    if self.model().rowCount()==0: return
    modInxList = self.model().match(self.model().index(0,0),QtCore.Qt.UserRole,QtCore.QVariant(args['importId']),1)
    if len(modInxList)==0:
      print 'CImportFileList.handleImportFileDeleted no match to importId',args
    else:
      self.model().removeRow(modInxList[0].row())

  def handleJobDeleted(self,args):
    #print 'CImportFileList.handleJobDeleted',args
    if args['projectId'] == self.projectId: self.load(self.projectId)

    
  def currentSelection(self):
    indices = self.selectionModel().selectedRows()
    #print 'CImportFileList.currentSelection',indices,len(indices)
    if len(indices) == 0: return None
    #print 'CImportFileList.currentSelection row',indices[0].row()
    importId = CCP4Data.varToUUID(indices[0].data(QtCore.Qt.UserRole))
    jobId = CCP4Data.varToUUID(indices[0].sibling(indices[0].row(),1).data(QtCore.Qt.UserRole))
    fileId = CCP4Data.varToUUID(indices[0].sibling(indices[0].row(),2).data(QtCore.Qt.UserRole))
    fileName = indices[0].data().toString().__str__()
    #print 'CImportFileList.currentSelection', fileId,ok
    return importId,fileId,jobId,fileName