import sys,os
import BaseHTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
from PyQt4 import QtCore
import CCP4Modules

DEFAULT_PORT = 43434

from SocketServer import ThreadingMixIn
from BaseHTTPServer import HTTPServer

class MultiThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    pass

def makeServer(port):
      HandlerClass = CHTTPRequestHandler
      ServerClass  = MultiThreadedHTTPServer
      Protocol     = "HTTP/1.0"
      server_address = ('127.0.0.1',port )
      HandlerClass.protocol_version = Protocol
      try:
        httpd = ServerClass(server_address, HandlerClass)
      except:
        return None
      else:
        return httpd

def testServer(port):
      import httplib
      ret = True
      try:
        h = httplib.HTTPConnection('127.0.0.1',port,timeout=3)
        h.connect()
      except:
        ret=False
      print 'testServer',port,h,ret
      try:
        h.close()
      except:
        pass
      return ret

class CHTTPServerThread(QtCore.QThread):

    insts = None

    def __init__(self,parent=None,parentDir=None,port=None):
      if parent is None: parent = CCP4Modules.QTAPPLICATION()
      QtCore.QThread.__init__(self,parent)
      self.setObjectName('HTTPServer')
      CHTTPServerThread.insts = self
      self.port = None
      if port is not None:
        self.defaultPort = port
      else:
        self.defaultPort = '43434'
      self.parentDir = parentDir
      import threading
      
      self.dbThread = CCP4Modules.DBSERVER()

    def quitServer(self):
      self.dbThread.queue.put("ShutdownSignal")
      #sys.__stdout__.write('Try to shut down server cleanly\n');sys.__stdout__.flush()
      self.httpd.shutdown()

    def run(self):
      # Code from http://www.linuxjournal.com/content/tech-tip-really-simple-http-server-python
      # Using this short script so that it will only serve localhost

      if self.parentDir is not None: os.chdir(self.parentDir)
      self.httpd =  makeServer(self.defaultPort)  
      if self.httpd is None: self.httpd = makeServer(0)
      
      if self.httpd is not None:
           sa = self.httpd.socket.getsockname()
           f = CCP4Modules.PRINTHANDLER().getFileObject(thread='HTTPServer',name='HTTPServer')
           f.write( "CCP4i2 starting HTTP server on "+str( sa[0])+ " port "+str(sa[1])+'\n' )
           print "CCP4i2 starting HTTP server on "+str( sa[0])+ " port "+str(sa[1])+'\n'
           self.port = sa[1]
           self.httpd.serve_forever()
      return

import CCP4DbApi

class CHTTPRequestHandler(SimpleHTTPRequestHandler):
    def log_message(self,format,*args):
      # More programming by stackoverflow...
      # http://stackoverflow.com/questions/10651052/how-to-quiet-simplehttpserver/10651257#10651257
      # The base class code
      '''
      sys.stderr.write("%s - - [%s] %s\n" %
                     (self.address_string(),
                      self.log_date_time_string(),
                      format%args))
      '''
                    
      f = CCP4Modules.PRINTHANDLER().getFileObject(thread='HTTPServer',name='HTTPServer')
      f.write("%s - - [%s] %s\n" %
                     (self.address_string(),
                      self.log_date_time_string(),
                      format%args))
    
    """
    def do_POST(self):
        import cgi
        import re
        form = cgi.FieldStorage(fp=self.rfile, headers=self.headers, \
            environ={'REQUEST_METHOD':'POST', 'CONTENT_TYPE':self.headers['Content-Type'], })
        upfile = form['upfile']
        project = form['project']

        # extract basename of input filename, remove non-alphanumeric characters
        if '\\' in upfile.filename:
            filename = upfile.filename.split('\\')[-1]
        else:
            filename = upfile.filename.split('/')[-1]
        filename = re.sub('[ \t]','-', filename)
        filename = re.sub('[^a-zA-Z0-9_.:-]','', filename)

        data = ''
        while True:
            chunk = upfile.file.read(8192)
            if len(chunk) == 0:
                break
            else:
                data += chunk
        self.send_response(200)
        self.end_headers()

        CHTTPServerThread.insts.emit(QtCore.SIGNAL('insertFileInDBRequest'),(os.path.basename(upfile.filename),data,project.value))

        self.wfile.write('<html><head><title>Upload</title></head><body>\
            <h1>Requested uploaded</h1><br>From: %s<br>To project:%s</body></html>' % \
            (upfile.filename, project.value) )
    """

    #Here I am going to do some hackery to allow the HTTP server to return information about the
    #database
    def do_GET(self):
        #print 'CHTTPRequestHandler.do_GET',self.path
        if not self.path.startswith('/database'):
            #serve files normally
            SimpleHTTPRequestHandler.do_GET(self)
        else:
            from CCP4Modules import HTTPSERVER
            dbQueue = HTTPSERVER().dbThread.queue
            
            tokens = self.path.split('?')
            tokensDict = {}
            for token in tokens:
                splitToken = token.strip().split('=')
                if len(splitToken) == 1: tokensDict[splitToken[0]] = True
                else: tokensDict[splitToken[0]] = '='.join(splitToken[1:])
            #print tokensDict
            import json
            
            if len(tokens) == 1:
                docTemplate = '''
                    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
                    <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
                    <head>
                    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
                    <script>
                    var serverName = '__serverName__';
                    var serverAddress = '127.0.0.1:__serverPort__';
                    </script>
                    
                    <!--CCP4i2 javscript and css-->
                    <link rel="stylesheet" type="text/css" href="/report_files/0.1.0/xreport.css"></link>
                    
                    <link rel="stylesheet" type="text/css" href="/report_files/0.1.0/dist/themes/default/style.min.css"></link>
                    
                    <!-- requirejs javascript -->
                    <script src="/report_files/0.1.0/require.min.js" data-main="/report_files/0.1.0/mainApp"></script>
                    
                    <!-- jspimple javascript -->
                    <link rel="stylesheet" type="text/css" href="/report_files/0.1.0/jspimple.css"></link>

                    <!-- jquery-ui javascript and css -->
                    <script src="/report_files/0.1.0/jquery-ui-1.10.4.custom/js/jquery-ui-1.10.4.custom.min.js"></script>
                    <link rel="stylesheet" href="/report_files/0.1.0/jquery-ui-1.10.4.custom/css/ui-lightness/jquery-ui-1.10.4.custom.css"></link>
                    
                    <style>body {font-size:10px;}</style>
                    <title>CCP4i2 Database view</title>
                    </head>
                    <body></body>
                    </html>
                    '''
                import re
                docString1 = re.sub('__serverName__',str(self.server.server_name),docTemplate)
                docString = re.sub('__serverPort__', str(self.server.server_port),docString1)
                self.returnData('text/html', docString)
                db.close()
                return
            
            #Create my own Queue for reading response
            import Queue
            dbRequest = {'responseQueue':Queue.Queue()}
            
            from CCP4DbThread import CDbThread
            if tokens[1] in CDbThread.databaseCalls:
                dbRequest['path'] = self.path
                dbQueue.put(dbRequest)
                response = dbRequest['responseQueue'].get(True, 10)
                if response is None:
                    self.send_response(404)
                    dbRequest['responseQueue'].task_done()
                    return
                else:
                    self.returnData('application/javascript',json.dumps(response))
                    dbRequest['responseQueue'].task_done()
                    return
    
            if 'File' in tokensDict:
                fileId = tokensDict.get('fileId', None)
                jobId = tokensDict.get('jobId', None)
                filePath = tokensDict.get('filePath', None)
                iconType = tokensDict.get('icon', None)
                #print 'Digested:',fileId, jobId, filePath
                if fileId is not None:
                    #Get info about file
                    dbRequest['path'] = '/database?getFileInfo?mode=filetype?fileId='+str(fileId)
                    dbQueue.put(dbRequest)
                    fileType = dbRequest['responseQueue'].get(True, 10)
                    if fileType is None:
                        self.send_response(404)
                        dbRequest['responseQueue'].task_done()
                        return
                    dbRequest['responseQueue'].task_done()
                    dbRequest['path'] = '/database?getFullPath?fileId='+str(fileId)
                    dbQueue.put(dbRequest)
                    fullPath = dbRequest['responseQueue'].get(True, 10)
                    #if 'Download' in tokensDict: self.returnFileAsFile(fileType, )
                    if 'Download' in tokensDict: self.returnFileAsDownload(contentType=fileType, fullPath=fullPath)
                    else: self.returnFileAsData(contentType=fileType, fullPath=fullPath)
                    dbRequest['responseQueue'].task_done()
                    return
            
                elif jobId is not None and filePath is not None:
                    dbRequest['path'] = '/database?jobDirectory?jobId='+str(jobId)
                    dbQueue.put(dbRequest)
                    jobDirectory = dbRequest['responseQueue'].get(True, 10)
                    fullPath = None
                    if filePath.startswith(jobDirectory):
                        fullPath = filePath
                    else:
                        import os
                        fullPath = os.path.join(jobDirectory,filePath)
                    import mimetypes
                    fileType = mimetypes.guess_type(fullPath)[0]
                    #Here apply patches where content type is explicitly known
                    if filePath == 'report.html': fileType = 'application/xhtml+xml'
                    if 'Download' in tokensDict: self.returnFileAsDownload(contentType=fileType, fullPath=fullPath)
                    else: self.returnFileAsData(contentType=fileType, fullPath=fullPath)
                    dbRequest['responseQueue'].task_done()
                    return
                        
                elif iconType is not None:
                    import CCP4Utils
                    import glob
                    import os
                    import CCP4DbApi
                    itype = 0
                    try:
                        itype = CCP4DbApi.FILETYPES_TEXT.index(iconType)
                    except:
                        pass
                    pattern = os.path.join(CCP4Utils.getCCP4I2Dir(), 'qticons','')+CCP4DbApi.FILETYPES_CLASS[itype]+'.*'
                    possibleFiles = glob.glob(pattern)
                    if len(possibleFiles) > 0:
                        import mimetypes
                        fullPath = possibleFiles[0]
                        fileType = mimetypes.guess_type(fullPath)[0]
                        self.returnFileAsDownload(contentType=fileType, fullPath=fullPath)
                    else:
                        self.send_response(404)
                    return
                else:
                    self.send_response(404)
                    return

    def returnFileAsDownload(self, contentType='application/xhtml+xml', fullPath=None):
        if not os.path.isfile(fullPath):
            self.send_response(404)
            return
        with open(fullPath, 'r') as content_file:
            content = content_file.read()
            self.send_response(200)
            self.send_header('Content-type',contentType)
            self.send_header('Content-disposition','attachment;filename='+os.path.split(fullPath)[1])
            self.end_headers()
            self.wfile.write(content)

    def returnFileAsData(self, contentType='application/xhtml+xml', fullPath=None):
        if not os.path.isfile(fullPath):
            self.send_response(404)
            return
        with open(fullPath, 'r') as content_file:
            content = content_file.read()
            self.returnData(contentType, content)

    def returnData(self, contentType=None, data=None):
        if contentType is not None and data is not None:
            self.send_response(200)
            self.send_header('Content-type',contentType)
            self.end_headers()
            self.wfile.write(data)

