#!/usr/bin/env python
# -*- coding: utf-8 -*-
#    TOMUSS: The Online Multi User Simple Spreadsheet
#    Copyright (C) 2008-2011 Thierry EXCOFFIER, Universite Claude Bernard
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    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 General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#    Contact: Thierry.EXCOFFIER@bat710.univ-lyon1.fr

import tomuss_init
import time
import sys
import os
import glob
import BaseHTTPServer
from . import abj
from . import configuration
from . import utilities
from . import document
from .files import files
from . import ticket
from . import sender

if False:
    from . import deadlock
    deadlock.start_check_deadlock()

warn = utilities.warn

running = True
current_time = time.time()

class FileProxy(object):
    def __init__(self, f):
        self.file = f
        self.closed = False
    def close(self):
        warn(str(self.file), what="debug")
        self.file.close()
        self.closed = True
    def write(self, t):
        self.file.write(t)
    def flush(self):
        self.file.flush()
    def __str__(self):
        return str(self.file)

class MyRequestBroker(utilities.FakeRequestHandler):

    def send_file(self, name):
        # print self.headers
        if name not in files:
            return
        s = files[name]
        self.send_response(200)
        if s.name and len(s) != 0:
            self.send_header('Content-Length', len(s))
        self.send_header('Content-Type', s.mimetype)
        if 'UNCACHED' in name:
            self.send_header('Cache-Control', 'no-cache')
        else:
            self.send_header('Cache-Control',
                             'max-age=%d' % configuration.maxage)
        if name.endswith('.gz'):
            self.send_header('Content-Encoding', 'gzip')
        self.end_headers()
        sender.append(self.wfile, str(s), keep_open=False)
        self.do_not_close_connection()

    def log_time(self, action, start_time=None):
        if start_time is None:
            start_time = self.start_time
        now = time.time()
        logs.write('%f %g %s\n' % (start_time, now - start_time, action))
        logs.flush()
        if sender.live_status:
            try:
                t = self.ticket.ticket.split('-')
                if len(t) == 3:
                    t = t[1]
                else:
                    t = ''
                t += '/' + self.ticket.user_name
                tt = self.ticket.access_right()
            except:
                t = 'N'
                tt = ''
                    
            year = ''
            semester = ''
            if action in ('pageaction', 'pagenew', 'pageresume',
                          'page_load_time', 'pagerewrite', 'end_of_load',
                          'answer_page'
                          ):
                if action == 'pageaction':
                    action = '*' + self.path.split('/')[7] + '*'
                elif action == 'page_load_time':
                    action += '(%.1fs)' % (now - start_time)
                year = str(self.the_year)
                semester = self.the_semester
            elif action == 'abjaction':
                action = '+' + self.path.split('/')[7] + '+'
            elif action == 'static-file':
                action = '_' + self.path.split('/')[1] + '_'
            try:
                ue = self.the_ue
            except:
                ue = ''
            sender.send_live_status(
                 '<script>d(%s,"%s","%s",%6.4f,"%s","%s",%s,%s);</script>\n' %
                 (utilities.js(ticket.client_ip(self)),
                  t,
                  tt,
                  now - start_time,
                  action, year, utilities.js(semester),
                  utilities.js(ue)))

    def do_GET_real(self):
        if self.path.startswith('/PROFILE_THIS_URL/'):
            self.path = self.path.replace('/PROFILE_THIS_URL/', '/')
            self.do_profile = True
        else:
            self.do_profile = False

        # APACHE make a mess with %2F %3F and others
        # so we encode them with $2F $3F...
        self.path = self.path.replace("$", "%")

        if ticket.client_ip(self) in configuration.banned_ip:
            self.send_file('bad.png')
            self.log_time('static-file')
            return

        if (self.path.startswith('/files/' + configuration.version)
            or self.path != '/' and self.path[1:] in files
            ):
            name = self.path.split("/")[-1]
            if name in files:
                self.send_file(name)
                self.log_time('static-file')
            return

        if self.path.startswith('/status/'):
            # No authentication because it is the way to see if server works
            self.send_response(200)
            self.send_header('Cache-Control', 'no-cache')
            self.send_header('Cache-Control', 'no-store')
            self.send_header('Content-Type', 'image/png')
            self.end_headers()
            self.wfile.write(files['ok.png'])
            self.log_time('status')
            return

        if configuration.regtest and self.path == '/stop':
            global running
            self.send_response(200)
            self.send_header('Cache-Control', 'no-cache')
            self.send_header('Cache-Control', 'no-store')
            self.send_header('Content-Type', 'text/plain')
            self.end_headers()
            self.wfile.write('stopped')
            running = False
            return

        the_ticket, self.the_path = ticket.get_ticket_string(self)
        self.ticket = ticket.get_ticket_objet(the_ticket, self)
        warn('ticket=%s' % str(self.ticket)[:-1])
        warn('the_path=%s' % str(self.the_path))

        self.the_file = self.wfile

        if plugin.dispatch_request(self, manage_error=False) is None:
            # An unauthenticated dispatch was done
            return

        if not self.ticket:
            # XXX : If Answer is an image : no redirect
            if len(self.the_path) > 4:
                try:
                    int(self.the_path[3])     # Page number
                    float(self.the_path[4])   # Request number
                    self.log_time('ticket-not-fine-for-image')
                    warn('Ticket not fine for image', what="auth")
                    # DO NOT MAKE AN ANSWER.
                    # THe BROWSER MUST UNDERSTAND THAT CONNECTION IS BROKEN
                    return
                except:
                    # Not an image, may be a page option
                    warn('Ticket not fine for not an image', what="auth")

        # Don't want to be blocked by authentication
        if authentication.ok(self):
            plugin.dispatch_request(self)

    def do_GET(self):
        global current_time
        self.start_time = time.time()
        if self.start_time - current_time > configuration.unload_interval:
            current_time = self.start_time
            document.remove_unused_tables() # Not in a thread : avoid problems
        try:
            self.do_GET_real()
        except: # IOError
            user_name = self.__dict__.get('ticket', '')
            if not user_name:
                user_name = ''
            if not isinstance(user_name, str):
                user_name = user_name.user_name

            utilities.send_backtrace('',
                                     subject = 'BUG TOMUSS ('
                                     + self.path + ') ' + user_name
                                     )
            try:
                if 'the_file' in self.__dict__:
                    self.wfile = self.the_file
                if 'plugin' in self.__dict__:
                    if self.plugin.mimetype == 'image/png':
                        self.wfile.write(files['bug.png'])
                    else:
                        self.wfile.write('There is a bug')
                else:
                    self.send_file('bug.png')
            except:
                pass

if __name__ == "__main__":
    utilities.display_stack_on_kill()
    
    if 'regtest' in sys.argv:
        configuration.regtest = True
    if 'regtest_sync' in sys.argv:
        configuration.regtest_sync = True
    configuration.regtest_bug1 = 'regtest-bug1' in sys.argv
    from . import regtestpatch
    regtestpatch.do_patch()
    from . import plugin # AFTER from . import regtestpatch???
    from . import plugins
    plugins.load_types()
    document.table(0, 'Dossiers', 'config_table', None, None)
    document.table(0, 'Dossiers', 'config_acls', None, None)

    if 'checker' in sys.argv:
        from . import tablestat
        from .TEMPLATES import _ucbl_
        configuration.do_not_display = ()
        for table in tablestat.les_ues(2009,'Automne', true_file=True):
            warn(table.ue)
            _ucbl_.student_add_allowed(table)
        sys.exit(0)

    utilities.init()
        
    if 'recompute_the_ue_list' in sys.argv:
        from . import teacher
        print teacher.all_ues(compute=True)
        sys.exit(0)

    from . import authentication
    authentication.run_authentication()

    server = BaseHTTPServer.HTTPServer(("0.0.0.0",
                                        configuration.server_port),
                                       MyRequestBroker)
    warn('Database:' + configuration.db)
    warn('Backup Database:' + configuration.backup + configuration.db)
    warn("Server Ready on:" + configuration.server_url)

    utilities.mkpath(os.path.join("LOGS", "TOMUSS"))
    logs = open(os.path.join("LOGS", "TOMUSS",
                             str(time.localtime()[0]) +".times"), "a")

    plugins.plugins_tomuss()
    document.table(0, 'Dossiers', 'config_plugin', None, None)
    plugins.generate_data_files()
    document.start_threads()

    authentication.authentication_redirect = configuration.server_url
    utilities.StaticFile._url_ = authentication.authentication_redirect

    utilities.start_new_thread_immortal(sender.send_thread, (True,))

    for i in range(3):
        utilities.start_new_thread_immortal(sender.send_thread, ())

    utilities.start_new_thread_immortal(sender.live_status_send_thread, ())

    document.table(0, 'Dossiers', 'config_home', None, None)
    document.table(0, 'Dossiers', 'config_cache', None, None)
    
    from . import display
    display.init()

    # While there is an updating table, there is many messages
    # Wait the end of the flow
    while utilities.filename_to_bufferize is not None:
        time.sleep(0.1)
    print '\n\n\n' +'*'*78
    print utilities._("MSG_tomuss_start"
                      ) % (configuration.server_url + '/=super.user')
    if configuration.regtest:
        regtest = 'regtest'
    else:
        regtest = ''
    for url, port, year, semester, host in configuration.suivi.servers():
        print '\t./suivi.py %d %s %d' % (year, semester, port), regtest
    print '*'*78 + '\n\n'

    # Translation of old files to new format
    for filename in glob.glob(os.path.join(configuration.db,
                                           'Y*', 'S*', 'abjs.py')):
        conv_year, conv_semester = filename.split(os.path.sep)[-3:-1]
        print 'Start translation of', filename
        abj.Abjs(int(conv_year[1:]), conv_semester[1:])

    if 'profile' in sys.argv:
        # To profile a single URL and not the full server.
        # Put PROFILE_THIS_URL just before the ticket:
        #    http://192.168.0.1:8888/PROFILE_THIS_URL/=ticket/stats
        import cProfile
        try:
            cProfile.run("while running: server.handle_request()", "xxx.prof")
        except KeyboardInterrupt:
            import pstats
            ps = pstats.Stats('xxx.prof')
            ps.strip_dirs().sort_stats('cumulative').print_stats()
    else:
        while running:
            server.handle_request()
        
    utilities.stop_threads()
