import sys
import os, atexit, signal, traceback
from urllib import unquote_plus
import ConfigParser
import logging
import logging.handlers
try:
    from ESL import ESLconnection
    # from ESL_test import ESLconnection
except ImportError:
    print 'We need ESL installed.'
    sys.exit(1)

from datetime import datetime
import smtplib

from paste.util.converters import aslist

# We don't know which version of python we might be using...
try:
    from email.mime.text import MIMEText
except ImportError:
    from email.MIMEText import MIMEText
    
from threading import Thread

from sqlalchemy import create_engine, and_, desc
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
from sqlalchemy.pool import NullPool

from mako.template import Template

import ldap

# This is only needed because we are SCPing...
import subprocess

from setuptools import Command

# For testing purposes only...
sys.path.append('/Users/jmesquita/Documents/Programacao/ppdi/ppdi')
sys.path.append('/home/fsdeveloper/ppdi')

from ppdi.model import Base, Conference, ConferenceAction, ModeratorPin



LEVELS = {'debug': logging.DEBUG,
          'info': logging.INFO,
          'warning': logging.WARNING,
          'error': logging.ERROR,
          'critical': logging.CRITICAL}


def parseEventDate(e):
    """Parse the event date"""
    event_date = getUnquotedHeader(e, 'Event-Date-Local')
    if event_date is not None:
        # Check the python version, because strptime does not exist in it.
        if sys.version_info[2] < 5:
            spl = event_date.split('-')
            year = int(spl[0])
            month = int(spl[1])
            spl2 = spl[2].split(' ')
            day = int(spl2[0])
            spl3 = spl2[1].split(':')
            hour = int(spl3[0])
            minutes = int(spl3[1])
            seconds = int(spl3[2])
            event_date = datetime(year=year, month=month, day=day, hour=hour, minute=minutes, second=seconds)
        else:
            event_date = datetime.strptime(event_date, '%Y-%m-%d %H:%M:%S')
            
    return event_date

def copyFileSftp(config, f, host):
    """Copy the file from server using SFTP"""
    log = logging.getLogger('copyFileSftp')
    try:
        cmd = 'scp %s@%s:%s %s' % (config.get('mp3', 'ssh_user'), host, f, config.get('mp3', 'store_from'))
        log.info('Executing command: %s' % cmd)
        retcode = subprocess.call(cmd, shell=True)
        if retcode != 0:
            raise Exception('Could not complete execution because child returned %d' % retcode)
    except OSError, e:
        raise e
    return

def transcodeFile(config, f):
    """Transcode the file to MP3"""
    log = logging.getLogger('transcodeFile')
    try:
        filename = f.split('/').pop()
        cmd = '%s -V2 %s %s' % (config.get('mp3', 'lame'), os.path.join(config.get('mp3', 'store_from'),filename), os.path.join(config.get('mp3', 'store_to'), filename[:-3] + 'mp3'))
        log.info('Executing command: %s' % cmd)
        retcode = subprocess.call(cmd, shell=True)
        if retcode != 0:
            raise Exception('Could not complete execution because child returned %d' % retcode)
    except OSError, e:
        raise e
    return

def sendEmail(config, f, confObj, owner_obj):
    log = logging.getLogger('sendEmail')
    """Send the email"""
    subject_tmpl = Template(config.get('email', 'subject'), input_encoding='utf-8', output_encoding='utf-8')
    email_tmpl = Template(filename=config.get('email', 'template'), input_encoding='utf-8', output_encoding='utf-8')
    email_from = config.get('email', 'from')

    # Authenticate the user!
    Base = config.get('ldap', 'base')
    
    Scope = ldap.SCOPE_SUBTREE
    Filter = "(&(objectClass=user)(sAMAccountName="+owner_obj.username+"))"
    Attrs = ["displayName", "mail"]

    # Set the LDAP timeout for the connection.
    ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, config.getint('ldap', 'timeout'))

    for Server in aslist(config.get('ldap','hosts'), sep=','):
        Server = 'ldap://' + Server
        log.info('Connecting to server: %s' % Server)
        l = ldap.initialize(Server)
        l.protocol_version = 3
        l.set_option(ldap.OPT_REFERRALS, 0)
        try:
            l.simple_bind_s(config.get('ldap', 'username'), config.get('ldap', 'password'))
            user = l.search_ext_s(Base, Scope, Filter, Attrs, timeout=10)
            Name,Attrs = user[0]
            Name,Attrs = user[0]
            email_to = None
            displayName = None
            if hasattr(Attrs, 'has_key') and Attrs.has_key('mail'):
                email_to = Attrs['mail'][0]
            else:
                log.warning('User %s has not email set. Not sending email.' % owner_obj.username)
                return
            if hasattr(Attrs, 'has_key') and Attrs.has_key('displayName'):
                displayName = Attrs['displayName'][0]

            msg = MIMEText(email_tmpl.render(displayName=displayName,
                            email_to=email_to,
                            conf_name=confObj.name,
                            conf_recording=confObj.recording,
                            url=config.get('http', 'root')+'/main/reports/report_detail/'+confObj.id,
                            conf_date=confObj.ended), 'html')
            msg['Subject'] = subject_tmpl.render(displayName=displayName,
                                            email_to=email_to,
                                            conf_name=confObj.name,
                                            conf_recording=confObj.recording,
                                            conf_date=confObj.ended)
            msg['From'] = email_from
            msg['To'] = email_to

            if config.getboolean('email', 'internal_server'):
                log.debug(msg.as_string())
                p = subprocess.Popen(config.get('email', 'command'), stdin=subprocess.PIPE, shell=True)
                p.communicate(input=msg.as_string())
                p.stdin.close()
                log.debug('Message sent.')
            else:
                s = smtplib.SMTP(config.get('email', 'server'), config.getint('email', 'port'))
                s.ehlo()
                s.starttls()
                s.ehlo()
                s.login(config.get('email', 'username'), config.get('email', 'password'))
                s.sendmail(email_from,[email_to],msg.as_string())
                s.quit()
            return
        except ldap.SERVER_DOWN, e:
            log.warning('Server %s is down!' % Server)

            if aslist(config.get('ldap', 'hosts'), sep=',').pop() in Server:
                # We are the last server, so ...
                log.critical('All LDAP servers are down. Last server tried was: %s. Not sending email.' % Server)
                raise(e)
            else:
                continue
        except ldap.LDAPError, e:
            log.critical('Critical error while connecting to ldap %s. Error: %s' % (Server, e))
            raise(e)

        # If we get here, it means that we authenticated just fine. Break the loop.
        break

def postRecordingThread(config, f, confObj, host, ownerObj):
    """Process the post recording details"""
    log = logging.getLogger('postRecordingThread')
    try:
        if config.getboolean('mp3', 'use_ssh'):
            copyFileSftp(config, f, host)
            
        transcodeFile(config, f)
        #sendEmail(config, f, confObj, ownerObj)
    except Exception, e:
        log.critical('Could not process the thread because:\n%s' % traceback.format_exc())
        raise
    return

def getUnquotedHeader(e, h):
    """Return the unquoted header, checking for null"""
    log = logging.getLogger('getUnquotedHeader')
    hs = e.getHeader(h)
    if hs is not None:
        hs = unquote_plus(hs)
    return hs

def configureLogging(config):
    """Configure logging"""
    # create logger
    logger = logging.getLogger("")
    logger.setLevel(LEVELS.get(config.get('logging', 'level'), logging.NOTSET))
    # create console handler and set level to debug
    try:
        ch = logging.handlers.RotatingFileHandler(os.path.join(config.get('logging', 'path'), 'conf_tracker.log'))
    except ConfigParser.NoOptionError:
        ch = logging.handlers.RotatingFileHandler(os.path.join('/var/log', 'conf_tracker.log'))
    
    ch.setLevel(logging.DEBUG)
    # create formatter
    formatter = logging.Formatter("%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(message)s")
    # add formatter to ch
    ch.setFormatter(formatter)
    # add ch to logger
    logger.addHandler(ch)
    
    if config.getboolean('logging', 'stdout'):
        ch = logging.StreamHandler()
        ch.setLevel(LEVELS.get(config.get('logging', 'level'), logging.NOTSET))
        ch.setFormatter(formatter)
        logger.addHandler(ch)

def delpid(signum=None, frame=None):
    global PIDFILE
    log = logging.getLogger('delpid')
    log.info('Terminating script.')
    os.remove(PIDFILE)
       
def daemonize(pidfile):
    global PIDFILE
    PIDFILE = pidfile
    try:
        pid = os.fork()
        if pid > 0:
            # exit first parent
            sys.exit(0)
    except OSError, e:
        print >>sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror)
        sys.exit(1)

    # decouple from parent environment
    os.chdir("/")
    os.setsid()
    os.umask(0)

    # do second fork
    try:
        pid = os.fork()
        if pid > 0:
            # exit from second parent, print eventual PID before
            print "Daemon PID %d" % pid
            sys.exit(0)
    except OSError, e:
        print >>sys.stderr, "fork #2 failed: %d (%s)" % (e.errno, e.strerror)
        sys.exit(1)

    sys.stdout.flush()
    sys.stderr.flush()
    si = file('/dev/null', 'r')
    so = file('/dev/null', 'a+')
    se = file('/dev/null', 'a+', 0)
    os.dup2(si.fileno(), sys.stdin.fileno())
    os.dup2(so.fileno(), sys.stdout.fileno())
    os.dup2(se.fileno(), sys.stderr.fileno())

    pid = str(os.getpid())
    file(PIDFILE,'w+').write("%s\n" % pid)

    atexit.register(delpid)
    signal.signal(signal.SIGTERM, delpid)
    