"""
     qtgui/downloadPdb.py: CCP4MG Molecular Graphics Program
     Copyright (C) 2001-2008 University of York, CCLRC
     Copyright (C) 2009-2010 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.
"""
import sys
import os
from PyQt4 import QtGui,QtCore
import MGSimpleDialog

def setup_proxies():
  import urllib2
  from global_definitions import PM

  proxy_uri = PM('download_preferences').get('http_proxy')
  user =  PM('download_preferences').get('http_user')
  passwd =  PM('download_preferences').get('http_password')

  if proxy_uri == "":
    return None

  proxy = urllib2.ProxyHandler({'http': proxy_uri})

  proxy_auth_handler = urllib2.HTTPBasicAuthHandler()

  # No idea if this is correct
  if user != "":
    proxy_auth_handler.add_password(None, uri=proxy_uri, user=user, passwd=passwd)

  opener = urllib2.build_opener(proxy, proxy_auth_handler)
  return opener


class downloadPdbCore(QtCore.QObject):
    def __init__(self):
       QtCore.QObject.__init__(self)
       self.interrupt_dl = False

    def downloadMain(self,url=None,finishedSignal="DownloadFinished"):
      import urllib2
      if not url: url = self.url
      if not url:
        self.emit(QtCore.SIGNAL("Error"),'No pdb to download' )
        #self.progressBar.reset()
        self.emit(QtCore.SIGNAL("ProgressBarRangeChanged"),0,100)
        self.emit(QtCore.SIGNAL("ProgressChanged"),0)
        return
      import tempfile
      self.localFile = tempfile.mkstemp()
      #print 'downloadPdb.download localFile',self.localFile
      try:
        opener = setup_proxies()
        if opener:
      	  dl = opener.open(url)
        else:
      	  dl = urllib2.urlopen(url)
      except:
        
        exc_type, exc_value,exc_tb = sys.exc_info()[:3]
        sys.stderr.write(str(exc_type)+'\n')
        sys.stderr.write(str(exc_value)+'\n')
        self.emit(QtCore.SIGNAL("Error"),'Error opening url '+ str(url)+'\nPlease check that you have internet connection.\nand that the pdb id is valid.\nAlso the data may not exist on the server.')
        return
      try:
      	info = dl.info()
      	contentLength = -1
      	for h in info.headers:
	      if h.find('Content-Length:')>-1:
		      cl = h.split(':')[1].strip()
		      try:
			      contentLength = int(cl)
                              self.emit(QtCore.SIGNAL("ProgressBarRangeChanged"),0,100)
		      except:
                              self.emit(QtCore.SIGNAL("ProgressBarRangeChanged"),0,0)
                              self.emit(QtCore.SIGNAL("ProgressChanged"),0)
			      contentLength = -1
		      break
	readBytes = 0
	buffer = ""
	read = dl.read(100)
	while len(read)>0 and not self.interrupt_dl:
		os.write(self.localFile[0],read)
		buffer = buffer + read
		readBytes = readBytes + len(read)
		pc =  int(float(readBytes)/contentLength * 100)
		if contentLength>-1:
        	        self.emit(QtCore.SIGNAL("ProgressChanged"),pc)
		read = dl.read(100)
      	dl.close()
        if not self.interrupt_dl:
	  fname = self.localFile[1]
          os.close(self.localFile[0])
          self.emit(QtCore.SIGNAL("ProgressBarRangeChanged"),0,100)
          self.emit(QtCore.SIGNAL("ProgressChanged"),0)
          print "Emitting",finishedSignal,"from",QtCore.QThread.currentThread(); sys.stdout.flush()
          self.emit(QtCore.SIGNAL(finishedSignal),fname)
          # Just in case
          self.interrupt_dl = False
        self.interrupt_dl = False
      
      except:
        self.interrupt_dl = False
	print "Error gettting",url
        exc_type, exc_value = sys.exc_info()[:2]
        print exc_type
        print exc_value
        os.close(self.localFile[0])
        # Is this thread-safe?
        #self.emit(QtCore.SIGNAL("Error"),'Error getting file '+ str(self.dataID.text())+'\n'+ str(exc_value) )
        self.emit(QtCore.SIGNAL("Error"),'Error getting file'+ str(exc_value) )
        self.emit(QtCore.SIGNAL("ProgressBarRangeChanged"),0,100)
        self.emit(QtCore.SIGNAL("ProgressChanged"),0)
        #self.progressBar.reset()

class downloadMultipleACs(MGSimpleDialog.MGSimpleDialog,downloadPdbCore):
   FileSaved = QtCore.pyqtSignal(str)
   DownloadedAllFiles  = QtCore.pyqtSignal()
   def InterruptAndClose(self):
      self.interrupt_dl = True
      self.progressBar.setRange(0,100)
      self.progressBar.setValue(0)
      self.Close()

   def __init__(self,parent=None):
      MGSimpleDialog.MGSimpleDialog.__init__(self,parent)
      self.interrupt_dl = False
      self.setWindowTitle(self.tr("Download multiple Accession Codes"))
      layout = QtGui.QVBoxLayout()
      self.progressBar = QtGui.QProgressBar()
      self.progressBar.setRange(0,100)
      self.progressBar.setValue(0)
      self.connect(self,QtCore.SIGNAL("ProgressChanged"),self.progressBar.setValue)
      self.connect(self,QtCore.SIGNAL("ProgressChanged"),self.progressBar.update)
      self.connect(self,QtCore.SIGNAL("ProgressChanged"),self.update)
      self.connect(self,QtCore.SIGNAL("ProgressBarRangeChanged"),self.progressBar.setRange)
      self.textLabel = QtGui.QLabel()
      self.connect(self,QtCore.SIGNAL("LabelTextChanged"),self.textLabel.setText)
      dialog_buttons = QtGui.QDialogButtonBox()
      ok_button = dialog_buttons.addButton(self.tr("Download"),QtGui.QDialogButtonBox.AcceptRole)
      cancel_button = dialog_buttons.addButton(QtGui.QDialogButtonBox.Cancel)
      self.connect(dialog_buttons,QtCore.SIGNAL("accepted()"),self.download)
      self.connect(cancel_button,QtCore.SIGNAL('clicked()'),self.InterruptAndClose)
      layout.addWidget(self.progressBar)
      layout.addWidget(self.textLabel)
      layout.addWidget(dialog_buttons)
      self.setLayout(layout)
      self.title = "Download multiple accession codes"
      self.CreateMenuEntry()
      self.Close()
      self.files = []
      self.directory = None
      import UtilityThread
      self.FileSaved.connect(self.loadSavedFile)
      self.DownloadedAllFiles.connect(self.Close)
      self.downloadThread = UtilityThread.UtilityThread(self.downloadFiles)

   def loadSavedFile(self,fname):
      from global_definitions import MAINWINDOW
      print "Saved",str(fname.toUtf8())
      MAINWINDOW().openFile(str(fname.toUtf8()),use_current_style=1,show_wizard_choices=0)

   def setDirectory(self,directory):
      self.directory = directory

   def setFiles(self,files):
      self.files = files
      if len(files) < 1:
         self.textLabel.setText('')
         return
      text = 'Download accession codes: '
      for f in files[:-1]:
         text = text + f + ', '
      text = text + files[-1]
      text = text[:100]
      if len(text) == '100':
        text = text + '...'
      self.textLabel.setText(text)

   def downloadFiles(self):
      import re
      import shutil
      site = 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=nuccore'
      id = '&id=34577062,24475906'
      
      site_suffix = '&rettype=fasta&retmode=text'
      
      for i,f in zip(range(len(self.files)),self.files):
         self.emit(QtCore.SIGNAL("ProgressBarRangeChanged"),0,0)
         self.emit(QtCore.SIGNAL("ProgressChanged"),0)
         url = site+'&id='+f+site_suffix
         #print url; sys.stdout.flush()
         print self.tr("Downloading "+f+". "+str(i+1)+" of "+str(len(self.files)))
         self.emit(QtCore.SIGNAL("LabelTextChanged"),self.tr("Downloading "+f+". "+str(i+1)+" of "+str(len(self.files))))
         self.downloadMain(url)
         fname = self.localFile[1]
         #print fname
         if self.directory != None:
           shutil.copy2(fname,os.path.abspath(os.path.join(self.directory,f+'.fasta')))
         else:
           shutil.copy2(fname,os.path.abspath(f+'.fasta'))
         os.unlink(fname)
         print self.tr("Download of "+f+" complete. "+str(i+1)+" of "+str(len(self.files)))
         self.emit(QtCore.SIGNAL("LabelTextChanged"),self.tr("Download of "+f+" complete. "+str(i+1)+" of "+str(len(self.files))))
         if self.directory != None:
           self.FileSaved.emit(os.path.abspath(os.path.join(self.directory,f+'.fasta')))
         else:
           self.FileSaved.emit(os.path.abspath(f+'.fasta'))
      self.DownloadedAllFiles.emit()

   def download(self):
      self.progressBar.reset()
      self.progressBar.setRange(0,0)
      self.progressBar.setValue(0)
      self.interrupt_dl = False
      self.downloadThread.start()

class downloadMultiplePdbs(MGSimpleDialog.MGSimpleDialog,downloadPdbCore):
   FileSaved = QtCore.pyqtSignal(str)
   DownloadedAllFiles  = QtCore.pyqtSignal()
   def InterruptAndClose(self):
      self.interrupt_dl = True
      self.progressBar.setRange(0,100)
      self.progressBar.setValue(0)
      self.Close()

   def __init__(self,parent=None):
      MGSimpleDialog.MGSimpleDialog.__init__(self,parent)
      self.interrupt_dl = False
      self.setWindowTitle(self.tr("Download multiple pdbs"))
      layout = QtGui.QVBoxLayout()
      self.progressBar = QtGui.QProgressBar()
      self.progressBar.setRange(0,100)
      self.progressBar.setValue(0)
      self.connect(self,QtCore.SIGNAL("ProgressChanged"),self.progressBar.setValue)
      self.connect(self,QtCore.SIGNAL("ProgressChanged"),self.progressBar.update)
      self.connect(self,QtCore.SIGNAL("ProgressChanged"),self.update)
      self.connect(self,QtCore.SIGNAL("ProgressBarRangeChanged"),self.progressBar.setRange)
      self.textLabel = QtGui.QLabel()
      self.connect(self,QtCore.SIGNAL("LabelTextChanged"),self.textLabel.setText)
      dialog_buttons = QtGui.QDialogButtonBox()
      ok_button = dialog_buttons.addButton(self.tr("Download"),QtGui.QDialogButtonBox.AcceptRole)
      cancel_button = dialog_buttons.addButton(QtGui.QDialogButtonBox.Cancel)
      self.connect(dialog_buttons,QtCore.SIGNAL("accepted()"),self.download)
      self.connect(cancel_button,QtCore.SIGNAL('clicked()'),self.InterruptAndClose)
      layout.addWidget(self.progressBar)
      layout.addWidget(self.textLabel)
      layout.addWidget(dialog_buttons)
      self.setLayout(layout)
      self.title = "Download multiple pdbs"
      self.CreateMenuEntry()
      self.Close()
      self.files = []
      self.directory = None
      import UtilityThread
      self.FileSaved.connect(self.loadSavedFile)
      self.DownloadedAllFiles.connect(self.Close)
      self.downloadThread = UtilityThread.UtilityThread(self.downloadFiles)

   def loadSavedFile(self,fname):
      from global_definitions import MAINWINDOW
      print "Saved",str(fname.toUtf8())
      MAINWINDOW().openFile(str(fname.toUtf8()),use_current_style=1,show_wizard_choices=0)

   def setDirectory(self,directory):
      self.directory = directory

   def setFiles(self,files):
      self.files = files
      if len(files) < 1:
         self.textLabel.setText('')
         return
      text = 'Download pdbs: '
      for f in files[:-1]:
         text = text + f + ', '
      text = text + files[-1]
      text = text[:100]
      if len(text) == '100':
        text = text + '...'
      self.textLabel.setText(text)

   def downloadFiles(self):
      import re
      import shutil
      from global_definitions import PM
      site = PM('download_preferences').get('preferred_site')
      com =  PM('download_preferences').get(site+'_Download_PDB')
      for i,f in zip(range(len(self.files)),self.files):
         self.emit(QtCore.SIGNAL("ProgressBarRangeChanged"),0,0)
         self.emit(QtCore.SIGNAL("ProgressChanged"),0)
         url = re.sub('PDBID',f.lower(),com)
         #print url; sys.stdout.flush()
         self.emit(QtCore.SIGNAL("LabelTextChanged"),self.tr("Downloading "+f+". "+str(i+1)+" of "+str(len(self.files))))
         self.downloadMain(url)
         fname = self.localFile[1]
         #print fname
         if self.directory != None:
           shutil.copy2(fname,os.path.abspath(os.path.join(self.directory,f+'.pdb')))
         else:
           shutil.copy2(fname,os.path.abspath(f+'.pdb'))
         os.unlink(fname)
         self.emit(QtCore.SIGNAL("LabelTextChanged"),self.tr("Download of "+f+" complete. "+str(i+1)+" of "+str(len(self.files))))
         if self.directory != None:
           self.FileSaved.emit(os.path.abspath(os.path.join(self.directory,f+'.pdb')))
         else:
           self.FileSaved.emit(os.path.abspath(f+'.pdb'))
      self.DownloadedAllFiles.emit()

   def download(self):
      self.progressBar.reset()
      self.progressBar.setRange(0,0)
      self.progressBar.setValue(0)
      self.interrupt_dl = False
      self.downloadThread.start()

class downloadPdb(MGSimpleDialog.MGSimpleDialog,downloadPdbCore):
     
    def saveFile(self,sfname=''):
      import os,shutil,MGApplication
      from global_definitions import MAINWINDOW
      #print 'downloadPdb.saveFile sfname ',sfname
      if not os.path.splitext(sfname)[1]: sfname = sfname+'.pdb'
      fname = self.localFile[1]
      shutil.copy2(fname,sfname)
      '''
      This is not working - use createMolData instead
      event = QtGui.QFileOpenEvent(sfname)
      app = MGApplication.QtApp()
      app.flush()
      app.postEvent(app,event)
      '''
      if hasattr(self,"fileDialog") and hasattr(self.fileDialog,"close"):
        self.fileDialog.close()
        del self.fileDialog
      MAINWINDOW().openFile(sfname,use_current_style=1,show_wizard_choices=0)
      self.Close()

    def saveDownloadedFile(self,fname=''):
      print "saveDownloadedFile"; sys.stdout.flush()
      self.emit(QtCore.SIGNAL("LabelTextChanged"),self.tr("Download  complete"))
      self.dataID.setDisabled(0)
      import os
      if not os.path.exists(fname) or not int(os.stat(fname).st_size)>10:
        self.emit(QtCore.SIGNAL("Error"),'No file downloaded for '+str(self.dataID.text())+'\nIs there a PDB entry with this name?')
        self.resetSelection()
        return
      defaultFileName =  str(self.dataID.text())+'.pdb'
      #print 'saveDownloadedFile.defaultFileName',defaultFileName
      import mgWidgets
      self.fileDialog = mgWidgets.MGSaveFileDialog(self,filters=["Model coordinate files (*.pdb )"], defaultFileName=defaultFileName)
      self.connect(self.fileDialog,QtCore.SIGNAL('save'),self.saveFile)
      self.fileDialog.show()
        
      
    def download(self):
      import re
      from global_definitions import PM
      pdbid =  str(self.dataID.text()).lower()
      if len(pdbid)<3: return
      self.dataID.setDisabled(1)
      self.textLabel.setText(self.tr("Preparing download of "+pdbid))
      site = PM('download_preferences').get('preferred_site')
      com =  PM('download_preferences').get(site+'_Download_PDB')
      self.url = re.sub('PDBID',pdbid,com)
      print 'download url',self.url
      self.progressBar.reset()
      self.progressBar.setRange(0,0)
      self.progressBar.setValue(0)
      self.emit(QtCore.SIGNAL("LabelTextChanged"),self.tr("Downloading "))
      self.interrupt_dl = False
      self.downloadThread.start()

    def InterruptAndClose(self):
      self.interrupt_dl = True
      self.dataID.setDisabled(0)
      self.progressBar.setRange(0,100)
      self.progressBar.setValue(0)
      self.Close()

    def resetSelection(self):
      self.textLabel.setText('')
      self.progressBar.setValue(0)

    def __init__(self,parent=None):
      MGSimpleDialog.MGSimpleDialog.__init__(self,parent)
      from global_definitions import PM
      self.interrupt_dl = False
      self.setWindowTitle(self.tr("Download coordinates"))

      codeLayout = QtGui.QHBoxLayout()
      pdbLabel = QtGui.QLabel(self.tr("PDB id:"))
      self.dataID = QtGui.QLineEdit()
      self.dataID.setToolTip(self.tr("Enter 4-letter pdb id and press return"))
      codeLayout.addWidget(pdbLabel)
      codeLayout.addWidget(self.dataID)

      self.progressBar = QtGui.QProgressBar()
      self.progressBar.setRange(0,100)
      self.progressBar.setValue(0)
      self.textLabel = QtGui.QLabel()
      self.connect(self,QtCore.SIGNAL("ProgressChanged"),self.progressBar.setValue)
      self.connect(self,QtCore.SIGNAL("ProgressBarRangeChanged"),self.progressBar.setRange)
      self.connect(self,QtCore.SIGNAL("LabelTextChanged"),self.textLabel.setText)


      dialog_buttons = QtGui.QDialogButtonBox()
      ok_button = dialog_buttons.addButton(self.tr("Download"),QtGui.QDialogButtonBox.AcceptRole)
      cancel_button = dialog_buttons.addButton(QtGui.QDialogButtonBox.Cancel)
      help_button = dialog_buttons.addButton(QtGui.QDialogButtonBox.Help)
      self.viewSite = dialog_buttons.addButton('Search '+PM('download_preferences').get('preferred_site')+' database',QtGui.QDialogButtonBox.ActionRole)

      self.connect(dialog_buttons,QtCore.SIGNAL("accepted()"),self.download)
      self.connect(ok_button,QtCore.SIGNAL("clicked()"),self.download)
      self.connect(cancel_button,QtCore.SIGNAL('clicked()'),self.InterruptAndClose)
      self.connect(help_button,QtCore.SIGNAL('clicked()'),self.handleHelp)

      self.connect(self,QtCore.SIGNAL("DownloadFinished"),self.saveDownloadedFile)
      self.connect(self,QtCore.SIGNAL("Error"),self.reportError)
      #self.connect(self.dataID,QtCore.SIGNAL("returnPressed()"),self.download)
      self.connect(self.viewSite,QtCore.SIGNAL("clicked()"),self.viewDatabase)
      self.viewSite.setToolTip('View database search tool in CCP4mg web browser')
      self.viewSite.setAutoDefault(0)

      layout = QtGui.QVBoxLayout()
      layout.addLayout(codeLayout)
      layout.addWidget(self.progressBar)
      layout.addWidget(self.textLabel)
      layout.addWidget(dialog_buttons)
      self.setLayout(layout)
      
      import UtilityThread
      self.downloadThread = UtilityThread.UtilityThread(self.downloadMain)
      
      self.setWindowModality(QtCore.Qt.ApplicationModal)

    def handleHelp(self):
       from global_definitions import HELPBROWSER
       HELPBROWSER().loadMgHelp('atom_typing.html#downloading')

    def details(self):
      from global_definitions import PREFERENCESWINDOW
      PREFERENCESWINDOW().loadNewWidget('download_preferences')

    def reportError(self,message=''):
      QtGui.QMessageBox.warning(self,'Error downloading PDB',message)
      self.dataID.setDisabled(0)
      self.progressBar.reset()
      self.progressBar.setRange(0,100)
      self.progressBar.setValue(0)

    def viewDatabase(self):
       from global_definitions import PM, HELPBROWSER
       site = PM('download_preferences').get('preferred_site')
       HELPBROWSER().loadFile(PM('download_preferences').get(site+'_Search'))


def createDownloadPM():

    import services
    pm = services.ParamsManager ( 
          name='download_preferences', 
          title='Download options',
          gui=[ 'pdb_header','preferred_site','EBI_Download_PDB','EBI_Search','RCSB_Search','RCSB_Download_PDB','PDBJapan_Download_PDB','PDBJapan_Search','proxy_header','http_proxy','http_user','http_password'],
        default = {
        'preferred_site' : 'EBI',
        'EBI_Search' :  "www.ebi.ac.uk/msd-srv/msdlite/index.html",
        'RCSB_Search': "www.rcsb.org/pdb",
        #'RCSB_Download_PDB': "http://www.rcsb.org/pdb/cgi/export.cgi/PDBID.pdb?job=download;pdbId=PDBID;opt=show;format=PDB;pre=1&compression=gz" ,
        'RCSB_Download_PDB': "http://www.rcsb.org/pdb/cgi/export.cgi/PDBID.pdb?job=download;pdbId=PDBID;opt=show;format=PDB;pre=1" ,
        'EBI_Download_PDB' : 'ftp://ftp.ebi.ac.uk/pub/databases/msd/pdb_uncompressed/pdbPDBID.ent' ,
        'PDBJapan_Download_PDB' : 'ftp://www.pdbj.org/pdb_nc/pdbPDBID.ent',
        'http_proxy': '',
        'http_user': '',
        'http_password': '',
        'PDBJapan_Search' : "pdbjs3.protein.osaka-u.ac.jp/xPSSS/index.html" },
      #'EBI_Download_PDB' : "'http://oca.ebi.ac.uk/oca-bin/send-x-pdb?id=' + pdbid " ,
        definition = {
             'preferred_site' : dict(type=str, label='Preferred download site',style='combobox',menu = ['EBI','RCSB','PDBJapan'],alias= ['EBI','RCSB','PDBJapan']),
             'EBI_Search' : dict(type=str,label='EBI search page',style='lineedit'), 
             'RCSB_Search' : dict(type=str,label='RCSB search page',style='lineedit'), 
             'RCSB_Download_PDB' : dict(type=str,label='RSCB PDB download command',style='lineedit') ,
             'EBI_Download_PDB' : dict(type=str,label='EBI PDB download command',style='lineedit') ,
             'PDBJapan_Download_PDB' : dict(type=str, label='PDBJapan download command',style='lineedit'), 
             'PDBJapan_Search' : dict(type=str,label=' PDBJapan search page',style='lineedit'), 
             'pdb_header': dict(type=str, label='<b>PDB download options</b>', style='label'),
             'proxy_header': dict(type=str, label='<b>HTTP proxy options</b>', style='label'),
             'http_proxy' : dict(type=str, label='HTTP proxy',style='lineedit'), 
             'http_user' : dict(type=str, label='HTTP username',style='lineedit'), 
             'http_password' : dict(type=str, label='HTTP password',style='lineedit')
             },
        help = 'web.html' )
    return pm
