"""
     qtgui/statusGui.py: CCP4MG Molecular Graphics Program
     Copyright (C) 2001-2008 University of York, CCLRC
     Copyright (C) 2009-2011 University of York
     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.
"""
from PyQt4 import QtGui,QtCore
from global_definitions import *
import mgWidgets,guiUtils
import os

nameFilters = [ "Status file (*.pkl)", "Editable picture definition file (*.mgpic.py)"]

#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------
class guiRestore( QtGui.QDialog):
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------

    def addFilters(self,filters):
      self.filedialog.addFilters(filters)
      
    def addFilter(self,filter):
      self.filedialog.addFilter(filter)
      
    def filters(self):
      return self.filedialog.filters(filters)
      
    def setNameFilters(self,filters):
      self.filedialog.setNameFilters(filters)
      

    def __init__(self,parent=None):
      super(guiRestore,self).__init__(parent)
      import mgWidgets
      #self.setAttribute(QtCore.Qt.WA_MacMetalStyle)
      self.setObjectName('dialogRestore')
      self.setWindowTitle(self.tr("Restore status and/or view file(s)"))
      #self.setModal(True)
      layout = QtGui.QVBoxLayout()

      frame = QtGui.QFrame()
      frame.setFrameStyle(QtGui.QFrame.Box)
      frame_layout = QtGui.QVBoxLayout()
      #self.remove = QtGui.QCheckBox('Remove all currently loaded objects',self)
      #frame_layout.addWidget(self.remove)
      line_layout = QtGui.QHBoxLayout()
      line_layout.addWidget(QtGui.QLabel('Restore'))
      self.restore_status = QtGui.QCheckBox('display status',self)
      line_layout.addWidget(self.restore_status)
      self.restore_view = QtGui.QCheckBox('view',self)
      line_layout.addWidget(self.restore_view)
      line_layout.addStretch(5)
      self.preview_widget = QtGui.QLabel()
      self.preview_widget.setText('PREVIEW')
      self.preview_widget.setFixedHeight(100)
      line_layout.addWidget(self.preview_widget)
      frame_layout.addLayout(line_layout)
      
      frame.setLayout(frame_layout)
      layout.addWidget(frame)

      self.restore_status.setChecked(1)
      self.restore_view.setChecked(1)
       
      filedialog = mgWidgets.MGFileDialog(self)
      layout.addWidget(filedialog)
      self.filedialog = filedialog.getFileDialog()
      
      self.filedialog.setFileMode(self.filedialog.ExistingFiles)
      #self.filedialog.setDirectory(proj_dir)

      self.connect(self.filedialog,QtCore.SIGNAL("currentChanged(const QString)"),self.updatePreview)

      self.filedialog.setNameFilters(nameFilters)

      #self.setSidebar()        
          
      self.setLayout(layout)
      self.connect(self.filedialog, QtCore.SIGNAL('filesSelected (const QStringList&)'), self.handleSelection)

#-------------------------------------------------------------------
    def updatePreview(self,filename_=''):
#-------------------------------------------------------------------
       filename = unicode(str(filename_.toUtf8()),'utf-8')
       if filename.endswith('.pkl') and os.path.exists(filename[:-4]):
         pixmap = QtGui.QPixmap(filename[:-4]).scaledToHeight(100)
         self.preview_widget.setText('')
         self.preview_widget.setPixmap(pixmap)
       else:
         self.preview_widget.setText('No preview available')

#-------------------------------------------------------------------
    def getFileName(self):
#-------------------------------------------------------------------
        if len(self.filedialog.selectedFiles()) > 0:
          if not os.path.isdir(self.filedialog.selectedFiles()[0]):
            return self.filedialog.selectedFiles()[0]
        return None


#-------------------------------------------------------------------
    def handleSelection(self,selectedFiles,restore_status=-1):
#-------------------------------------------------------------------
      if restore_status<0: restore_status = int(self.restore_status.isChecked())

      for item in selectedFiles:
        self.status_file = str(item.toUtf8())
        
        if restore_status and os.path.splitext(self.status_file)[1] == '.pkl':
          rv = HISTORY().get_status_data_files(filename=self.status_file)
          #print 'from  HISTORY().get_status_data_files',rv
          if rv[0]<0:
             QtGui.QMessageBox.warning(self,'Error reading status file',rv[1])
          elif not rv[0]:
            # No problems - just load the status file
            self.loadStatusFile(self.status_file)
            self.accept()
            self.close() #Is this necessary? Do we get here?

          else:
            self.hide()
            lostGui = lostFilesGui(self,self.status_file)
            rv = lostGui.exec_()
            if rv == QtGui.QDialog.Accepted:
            
              objList,fileDefn = lostGui.getFiles()
              status =  HISTORY().edit_status_data_files(self.status_file,1,objList,fileDefn)
              self.loadStatusFile(status=status)
              
              retval = QtGui.QMessageBox.question(self,
                  'Save status file',                              
                  'Save the status with new data file names?\n',
                   QtGui.QMessageBox.Save|QtGui.QMessageBox.Cancel)
              if retval == QtGui.QMessageBox.Cancel: return
              
              saveGui = guiSaveStatus(self)
              title = 'Save updated status from file: '+os.path.split(self.status_file)[1]
              saveGui.setWindowTitle(title)
              saveGui.fileDialog.selectFile(self.status_file)
              rv = saveGui.exec_()
              self.accept()
              self.close()
              
            #self.connect(self.lostFiles,QtCore.SIGNAL('apply'),self.applyFoundFiles)
            #self.connect(self.lostFiles,QtCore.SIGNAL('closed'),self.Close)
        else:
          rv = self.loadStatusFile(self.status_file)
          self.accept()
          self.close()
           
#-------------------------------------------------------------------
    def loadStatusFile(self,file='',status={},restore_status=-1,restore_view=-1,remove=-1):
#-------------------------------------------------------------------
      if restore_status<0: restore_status = int(self.restore_status.isChecked())
      if restore_view<0: restore_view = int(self.restore_view.isChecked())
      self.emit(QtCore.SIGNAL('filesSelected'),file,status,restore_status,restore_view,remove)

#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------
class guiSaveStatus(QtGui.QDialog):
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------

  def __init__(self,parent=None,saved_status=None):
    QtGui.QDialog.__init__(self,parent)
    self.saved_status = saved_status
    self.draw()


#-------------------------------------------------------------------
  def draw(self):
#-------------------------------------------------------------------

    self.setWindowTitle(self.tr('Save current status'))
    layout = QtGui.QGridLayout()


    file = mgWidgets.MGFileDialog(self)
    self.fileDialog = file.getFileDialog()
    self.fileDialog.setFileMode(QtGui.QFileDialog.AnyFile)
    self.fileDialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
    self.fileDialog.setConfirmOverwrite(False)

    filter_list = []

    #formats = QtGui.QImageWriter.supportedImageFormats()
    # We use ccp4mg's image handling stuff for now. Maybe for ever?


    self.fileDialog.setNameFilters(nameFilters)

    self.connect(self.fileDialog, QtCore.SIGNAL('fileSelected(const QString&)'),self.saveFile)

    """
    children = self.fileDialog.findChildren(QtGui.QPushButton,"")
    for child in children:
      if child.text() == self.tr("&Save"):
        self.connect(child, QtCore.SIGNAL('pressed()'),self.saveFile)
    """
    layout.addWidget(file,1,0,1,2)
    self.setLayout(layout)
    
#-------------------------------------------------------------------
  def saveFile(self):
#-------------------------------------------------------------------
    file = self.fileDialog.selectedFiles()
    if not file: return
    file = str(file[0].toUtf8())
    filt = str(self.fileDialog.selectedNameFilter().toUtf8())
    filtsQt = self.fileDialog.nameFilters()
    filts = []
    for f in filtsQt:
      _filt = str(f.toUtf8())
      if "(*" in _filt:
        _filt = _filt[_filt.find("(*")+2:]
        if ")" in _filt:
          _filt = _filt[:_filt.rfind(")")]
          filts.append(_filt)
    hasSuffix = False
    for f in filts:
      if file.endswith(f):
        hasSuffix = True
    if not hasSuffix and "(*" in filt:
      filt = filt[filt.find("(*")+2:]
      if ")" in filt:
        filt = filt[:filt.rfind(")")]
        if not file.endswith(filt):
          file = file + filt
    self.emit(QtCore.SIGNAL('filesSelected'),file,self.saved_status)

    #print 'guiSaveStatus.saveFile accept'
    self.accept()


#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------
class lostFilesGui(QtGui.QDialog):
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------

    
#-------------------------------------------------------------------
  def __init__(self,parent=None,status_file = '',lost=[],defn={}):
#-------------------------------------------------------------------
    QtGui.QDialog.__init__(self,parent)

    hints = []
    if status_file:
      hints.append(os.path.split(status_file)[0])
    if lost:
      objList = lost
      fileDef = defn
    else:
      nLost,objList,fileDef,nFound = HISTORY().get_status_data_files(status_file,hints)
      
    self.setWindowTitle('Find data files loading '+os.path.split(status_file)[1]+'status file')

    layout = QtGui.QGridLayout()

    layout.addWidget(QtGui.QLabel('Cannot find all data files as specified in status file'),0,0,1,5)
    layout.addWidget(QtGui.QLabel('Please give alternative files (or continue without missing files)'),1,0,1,5)

    layout.addWidget(QtGui.QLabel('Saved project/directory alias and filename'),2,0,1,2)
    layout.addWidget(QtGui.QLabel('File to be loaded'),2,2,1,3)
    self.widgets = []
    
    row = 2
    for objname in objList:
      if fileDef.has_key(objname):
        alias,filn,path = fileDef[objname]
        row = row + 1
        self.widgets.append(lostFileWidget(alias,filn,path,layout,row))
        self.widgets[-1].setObjectName(objname)

        self.connect(self.widgets[-1],QtCore.SIGNAL('happy'),self.handleHappyWidget)

    dialog = QtGui.QDialogButtonBox(self)
    button = dialog.addButton(QtGui.QDialogButtonBox.Apply)
    button.setAutoDefault(0)
    self.connect(button,QtCore.SIGNAL('clicked()'),self.Apply)
    button.setToolTip('Load the status file with selected data files')
    button = dialog.addButton(QtGui.QDialogButtonBox.Cancel)
    button.setAutoDefault(0)
    #self.connect(button,QtCore.SIGNAL('clicked()'),self.Close)
    self.connect(button,QtCore.SIGNAL('clicked()'),self,QtCore.SLOT('reject()'))
    button.setToolTip('Cancel loading status file')
    '''
    button = dialog.addButton('Edit projects and aliases',QtGui.QDialogButtonBox.ActionRole)
    button.setToolTip('Add a new directory alias or change the existing ones')
    self.connect(button,QtCore.SIGNAL('clicked()'),self.editAliases)
    '''

    layout.addWidget(dialog,row+1,0,1,5)
    
    self.grid = layout
    self.setLayout(layout)

    
    self.connect(CCP4DATABASE(),QtCore.SIGNAL('directoriesChanged'),self.handleChangedAlias)

#-------------------------------------------------------------------
  def Apply(self):
#-------------------------------------------------------------------
    lost = ''
    for ww in self.widgets:
      if not os.path.exists(str(ww.path.text())):
        lost = lost + str(ww.path.text()) +'\n'

    if lost:
      retval = QtGui.QMessageBox.question(self,
        'Lost data files restoring status',
        'The following data files can not be found..\n'+lost+
        'You can continue to load remaining data files',
        QtGui.QMessageBox.Apply|QtGui.QMessageBox.Cancel)
      if retval == QtGui.QMessageBox.Cancel: return

    self.accept()
    
    #self.emit(QtCore.SIGNAL('apply'))
    
#-------------------------------------------------------------------
  def getFiles(self):
#-------------------------------------------------------------------
    objList = []
    fileDefn = {}
    for ww in self.widgets:
      name = str(ww.objectName())
      objList.append(name)
      fileDefn[name] = ww.getFile()
    return [objList,fileDefn]

#-------------------------------------------------------------------
  def Close(self):
#-------------------------------------------------------------------
    #print 'lostFilesGui.Close'
    self.setResult(QtGui.QDialog.Rejected)
    #self.emit(QtCore.SIGNAL('closed'))
    self.close()

#-------------------------------------------------------------------
  def handleChangedAlias(self,changed_alias=''):
#-------------------------------------------------------------------
    #print 'handleChangedAlias'
    for w in self.widgets:
      w.handleChangedAlias(changed_alias)

      
#-------------------------------------------------------------------
  def editAliases(self):
#-------------------------------------------------------------------
      import ccp4iGui
      editAliasGui = ccp4iGui.ccp4iAliasGui(self)
      editAliasGui.loadAliases()
      rv = editAliasGui.exec_()
      #print 'editAliases rv',rv

  def handleHappyWidget(self,new_path):
    new_path = os.path.split(new_path)[0]
    for ww in self.widgets:
       ww.tryHint(new_path)
       
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------
class lostFileWidget(QtGui.QWidget):
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------
  HAPPY = 3
  NAME = 1
  ALIAS = 0
  PATH = 2

  def __init__(self,alias,filn,path,layout,row):
      QtGui.QWidget.__init__(self)
      self.happy = QtGui.QLabel(self)
      self.happy.setPixmap(guiUtils.loadPixmap('question'))
      layout.addWidget(self.happy,row,lostFileWidget.HAPPY,1,1)
      
      self.filn =  QtGui.QLabel(os.path.split(filn)[1],self)
      self.filn.setToolTip('Name of file')
      layout.addWidget(self.filn,row,lostFileWidget.NAME,1,1)

      if alias == 'FULLPATH': alias = ' '
      self.alias = QtGui.QLabel(alias,self)
      self.alias.setToolTip('Project or directory alias')
      layout.addWidget(self.alias,row,lostFileWidget.ALIAS,1,1)
      
      self.path = QtGui.QLineEdit(self)
      self.path.setToolTip('Current full path name for file')
      self.path.setMinimumWidth(200)
      self.connect(self.path,QtCore.SIGNAL('editingFinished()'),self.setHappy)
      layout.addWidget(self.path,row,lostFileWidget.PATH,1,1)
      self.setFilename(path)
      
      self.browse = QtGui.QPushButton('Browser',self)
      self.browse.setToolTip('Use browser to find file')
      self.browse.setAutoDefault(0)
      self.connect(self.browse,QtCore.SIGNAL('clicked()'),self.openBrowser)
      layout.addWidget(self.browse,row,4,1,1)

#-------------------------------------------------------------------
  def openBrowser(self):
#-------------------------------------------------------------------
    filn = QtGui.QFileDialog.getOpenFileName(self,self.tr('Find file ')+str(self.filn.text()),"","");
    if filn: self.setFilename(str(filn.toAscii())) 
    return

#-------------------------------------------------------------------
  def handleBrowser(self,filn):
#-------------------------------------------------------------------
    #print 'handleBrowser',dirn
    if filn: self.setFilename(str(filn[0])) 
    self.browser.close()
    
#-------------------------------------------------------------------
  def setFilename(self,filn):
#-------------------------------------------------------------------
    self.path.setText(filn)
    self.setHappy()

#-------------------------------------------------------------------
  def setHappy(self):
#-------------------------------------------------------------------
    if os.path.exists(str(self.path.text())):
      self.happy.setPixmap(guiUtils.loadPixmap('happy'))
      self.emit(QtCore.SIGNAL('happy'),str(self.path.text()))
    else:
      self.happy.setPixmap(guiUtils.loadPixmap('question'))

#-------------------------------------------------------------------
  def getFile(self):
#-------------------------------------------------------------------
    path = str(self.path.text())
    # If we have sensible path then update alias and filn to match
    if os.path.exists(path):
      alias = CCP4DATABASE().aliasForDir(os.path.split(path)[0])
      if not alias:
          import string
          alias = string.strip(str(self.alias.text()))
      filn = os.path.split(path)[1]
    else:
      # Still not good path - keep whatever we had
      alias = str(self.alias.text())
      filn = str(self.filn.text())
    if not alias: alias = 'FULLPATH'
    return [ alias, filn, path ]


#-------------------------------------------------------------------
  def handleChangedAlias(self,changed_alias=''):
#-------------------------------------------------------------------
    alias = str(self.alias.text())
    path = CCP4DATABASE().get_project_dir(str(self.alias.text()))
    if path:
      path = os.path.join(path,str(self.filn.text()))
    #if os.path.exists(path):
    self.path.setText(path)
    self.setHappy()

#-------------------------------------------------------------------
  def tryHint(self,new_path):
#-------------------------------------------------------------------
    if os.path.exists(str(self.path.text())): return
    test_path = os.path.join(new_path,str(self.filn.text()))
    if os.path.exists(test_path):
      self.setFilename(test_path)

#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------
class recoverGUI(QtGui.QDialog):
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------

  
#-------------------------------------------------------------------
    def __init__(self,parent):
#-------------------------------------------------------------------
        QtGui.QDialog.__init__(self,parent)
        self.setWindowTitle('Recover status')
        self.setObjectName('recover')

        layout = QtGui.QVBoxLayout()
        layout.addWidget(QtGui.QLabel('Recover program status from'))
        recover_files = HISTORY().getRecoverFiles()
        self.menu = QtGui.QComboBox(self)
        for item in recover_files:
          self.menu.addItem(item)
        layout.addWidget(self.menu)

        buttonBox = QtGui.QDialogButtonBox(self)
        buttonBox.setOrientation(QtCore.Qt.Horizontal)
        button = buttonBox.addButton('Recover',QtGui.QDialogButtonBox.ApplyRole)
        self.connect(button, QtCore.SIGNAL('clicked()'), self.recover)
        button = buttonBox.addButton('Cancel',QtGui.QDialogButtonBox.RejectRole)
        self.connect(button, QtCore.SIGNAL('clicked()'), self.close)
        layout.addWidget(buttonBox)

        self.setLayout(layout)

#-------------------------------------------------------------------
    def recover(self):
#-------------------------------------------------------------------

      self.close()                
      status_label = str(self.menu.currentText())
      DISPLAYTABLE().deleteAllDataObj()
      ret = HISTORY().recover(status_label)
      if ret:
        QtGui.QMessageBox.warning(self,'Error restoring status from '+status_label)
      else:
        DISPLAYTABLE().loadAllDataObj()
        import rebuild
        rebuild.UpdateDisplay()
