#!/usr/bin/env python

import cherrypy
import smtplib
import urllib
import simplejson
import gdata.service
import os
import sys
from subprocess import Popen, PIPE
from cherrypy.lib.static import serve_file
from recaptcha.client import captcha

import youtomb.db

import youtomb.web.view
from youtomb.web.view import View

ADMINISTRATORS = ['youtomb@mit.edu']
SMTP_SERVER = 'localhost'
RRD_DIRECTORY = os.path.join(os.path.expanduser("~"), "run/youtomb/rrd/")

def db(): return youtomb.db.Database()

class Feeds(View):
    def __init__(self, parent):
        super(self.__class__,self).__init__()
        self.parent = parent
    
    @cherrypy.expose
    @cherrypy.tools.mako(filename="/feeds.mako")
    def index(self):
        return {}
    
    @cherrypy.expose
    @cherrypy.tools.jsonify()
    def statistics(self):
        return self.parent.statistics()
    
    @cherrypy.expose
    @cherrypy.tools.jsonify()
    def video(self, site, id):
        return self.parent.v(site, id)
    
    @cherrypy.expose
    @cherrypy.tools.jsonify()
    def video_stats(self, artifact_id):
        sql = ("SELECT UNIX_TIMESTAMP(timestamp)*1000 AS time, num_views, num_ratings, avg_rating FROM snapshots WHERE artifact_id = %s AND num_views IS NOT NULL ORDER BY time")
        rows = db().allrows(sql, (artifact_id,))
        num_views = map(lambda r: (r['time'], r['num_views']), rows)
        num_ratings = map(lambda r: (r['time'], r['num_ratings']), rows)
        avg_rating = map(lambda r: (r['time'], r['avg_rating']), rows)
        return {'num_views': num_views, 'num_ratings': num_ratings, 'avg_rating': avg_rating}

class Parts(View):
    def __init__(self, parent):
        super(self.__class__,self).__init__()
        self.parent = parent
    
    @cherrypy.expose
    @cherrypy.tools.mako(filename="/parts/latest_scans.mako")
    @cherrypy.tools.caching(delay=10)
    def latest_scans(self):
        return {'scans': self.parent.get_recent_scans()}

class Front(View):
    def __init__(self):
        super(self.__class__,self).__init__()
        self.feeds = Feeds(self)
        self.parts = Parts(self)
        
    @cherrypy.expose
    @cherrypy.tools.mako(filename="/about.mako")
    def about(self):
        return {}

    def get_recent_scans(self, copyright_only=False):
        sql = ("SELECT *, id AS artifact_id FROM artifacts")
        if copyright_only:
            sql += " WHERE status LIKE 'down:copyright%%'"
        sql += " ORDER BY timestamp DESC LIMIT 10"
        return db().allrows(sql)
    
    def get_artifact_status_stats(self):
        return db().allrows("SELECT * FROM artifacts_status_count WHERE count > 0 ORDER BY count DESC")
    
    def get_artifact_active_stats(self):
        return db().allrows("SELECT * FROM artifacts_active_count WHERE count > 0 ORDER BY count DESC")

    @cherrypy.expose
    @cherrypy.tools.mako(filename="/front.mako")
    def index(self):
        return {'scans': self.get_recent_scans(copyright_only=True),
                'count': dict(map(dict.values, self.get_artifact_active_stats())),
                }

    @cherrypy.expose
    @cherrypy.tools.mako(filename="/browse.mako")
    def browse(self, status="down", sort="freshness", direction="down", page=1, count=20):
        sql = "SELECT *, id AS artifact_id FROM artifacts WHERE status LIKE %s"
        args = (status+"%",)
        sql_direction = "DESC"
        if direction == "up":
            sql_direction = "ASC"
        if sort == "freshness":
            sql += " ORDER BY timestamp "+sql_direction
        elif sort == "views":
            sql += " ORDER BY num_views "+sql_direction
        elif sort == "rating":
            sql += " AND avg_rating IS NOT NULL ORDER BY avg_rating "+sql_direction+", num_views "+sql_direction
        sql += " LIMIT %s OFFSET %s"
        args += (int(count), int(count)*(int(page)-1))
        
        videos = db().allrows(sql, args)
        return {'videos': videos,
                'count': len(videos),
                'categories': db().allrows("SELECT DISTINCT category FROM artifacts WHERE category IS NOT NULL ORDER BY category"),
                'query': {
                    'status': status,
                    'sort': sort,
                    'direction': direction,
                    'page': page,
                    'count': count},
                'claimants': map(lambda x: {'name': x['status'][15:],
                                            'count': x['count']},
                    db().allrows("SELECT * FROM artifacts_status_count WHERE status LIKE 'down:copyright:%%' ORDER BY count DESC"))
                }
    
    @cherrypy.expose
    @cherrypy.tools.mako(filename="/results.mako")
    def search(self, preset=None, page=1, count=50, **kwargs):
        sql = None
        if preset == "toprated":
            sql = "SELECT *, id AS artifact_id FROM artifacts LEFT JOIN snapshots ON artifacts.last_snapshot = snapshots.id ORDER BY avg_rating DESC, num_views DESC LIMIT %s"
            args = (int(count),)
        elif preset == "mostviewed":
            sql = "SELECT *, id AS artifact_id FROM artifacts LEFT JOIN snapshots ON artifacts.last_snapshot = snapshots.id ORDER BY num_views DESC LIMIT %s"
            args = (int(count),)
        elif preset == "latestdown":
            sql = "SELECT *, id AS artifact_id FROM artifacts LEFT JOIN snapshots ON artifacts.last_snapshot = snapshots.id WHERE (active = 'copyright' or active = 'inactive') ORDER BY timestamp DESC LIMIT %s"
            args = (int(count),)
        elif kwargs.get('q'):
            # TODO(quentin) Build up query here
            sql = "SELECT *, id AS artifact_id FROM artifacts_search WHERE MATCH (`title`,`user`,`category`,`tags`,`description`) AGAINST (%s) LIMIT %s OFFSET %s"
            args = (kwargs['q'], int(count)+1, (int(page)-1)*int(count))
        if sql is not None:
            videos = db().allrows(sql, args)
            next_page = False
            if len(videos) > int(count):
                videos = videos[:-1]
                next_page = True
            return {'videos': videos,
                    'next_page': next_page,
                    'query': {
                        'q': kwargs['q'],
                        'page': int(page),
                        'count': int(count)
                        }
                    }
        else:
            return {'error': "Could not parse query"}

    @cherrypy.expose
    @cherrypy.tools.mako(filename="/video.mako")
    def v(self, site, id):
        artifact = db().onerow("SELECT * FROM artifacts WHERE site_id = %s AND external_id = %s", (db().site_id_for_name(site), id))
        current_snapshot = db().onerow("SELECT * FROM snapshots WHERE snapshots.id = %s", (artifact["last_snapshot"]))
                
        params = {'artifact': artifact,
                  'current_snapshot': current_snapshot,
                  'thumbnails': db().allrows("SELECT * FROM media WHERE rel = 'thumbnail' AND artifact_id = %s", (artifact["id"],))
                  }
        return params

    @cherrypy.expose
    @cherrypy.tools.mako(filename="/video.mako")
    def youtube(self, id):
        return self.v('YouTube', id)

    @cherrypy.expose
    @cherrypy.tools.mako(filename="/embed.js.mako")
    def embed(self, site, id):
        params = self.v(site, id)
        params['snapshot']['external_id']    = params['artifact']['external_id']
        params['snapshot']['time_published'] = params['artifact']['time_published']
        return params

    @cherrypy.expose
    @cherrypy.tools.mako(filename="/statistics.mako")
    def statistics(self):
        staleness = db().onerow("SELECT timestampdiff(second, time_updated, now()) AS staleness FROM artifacts WHERE active='active' AND first_snapshot IS NOT NULL AND time_updated > 0 ORDER BY time_updated ASC LIMIT 1")["staleness"]
        status_stats=self.get_artifact_status_stats()
        count=dict(map(dict.values, self.get_artifact_active_stats()))
        return {'staleness': staleness,
                'status_stats': status_stats,
                'count': count,
                }
                
    @cherrypy.expose
    def staleness_png(self, time=None):
        rrdfile = os.path.join(RRD_DIRECTORY, "statistics.rrd")
        cherrypy.response.headers['Content-Type'] = 'image/png'
        command = ('rrdtool', 'graph', '-', "--imgformat", "PNG", "--logarithmic", "DEF:staleness="+rrdfile+":staleness:AVERAGE", "LINE:staleness#FF0000:Staleness (seconds)")
        if time is not None:
            command += ('--start', 'end-'+time)
        return Popen(command, stdout=PIPE).communicate()[0]
    
    @cherrypy.expose
    @cherrypy.tools.mako(filename="/contact.mako")
    def contact(self):
        pubkey = file(os.path.join(base_dir, 'recaptcha.pubkey')).read()
        return {'captcha': captcha.displayhtml(pubkey)}
    
    @cherrypy.expose
    @cherrypy.tools.mako(filename="/contact.mako")
    @cherrypy.tools.caching(on=False)
    def contactSend(self, name, email, message, **kwargs):
        pubkey = file(os.path.join(base_dir, 'recaptcha.pubkey')).read()
        privkey = file(os.path.join(base_dir, 'recaptcha.privkey')).read()
        challenge = kwargs['recaptcha_challenge_field']
        response = kwargs['recaptcha_response_field']
        status = captcha.submit(challenge, response, privkey, cherrypy.request.remote.ip)
        if not status.is_valid:
            return {'submitMsg': 'Are you really a human?  Try again.',
                    'captcha': captcha.displayhtml(pubkey)}

        session = smtplib.SMTP(SMTP_SERVER)
        message = "From: %s <%s>\r\nTo: %s\r\nSubject: YouTomb Contact Form\r\n\r\nMessage sent by %s:\r\n%s" % (name, email, ', '.join(ADMINISTRATORS), cherrypy.request.remote.ip, message)
        smtpresult = session.sendmail(email, ADMINISTRATORS, message)
        return {'submitMsg': "Message sent.",
                'captcha': captcha.displayhtml(pubkey)}
    
    @cherrypy.expose
    def kamikaze(self):
        global server
        server._exit(True)
        return "Exiting front.py"

dev = False

base_dir = os.path.dirname(__file__)
if __name__=="__main__":
    static_dir = os.path.join(base_dir, 'static')

    app = cherrypy.tree.mount(Front(), '/' if dev else '/youtomb.fcgi',
        {'/':         {'tools.staticdir.root': static_dir,
                       'tools.staticfile.root': static_dir,},
        '/static':    {'tools.staticdir.on': True,
                       'tools.staticdir.dir': static_dir},
        '/thumbnail': {'tools.staticdir.on': True,
                       'tools.staticdir.dir': '/mit/freeculture/youtomb/archive/thumbnail'}
        })
    if len(sys.argv) > 1:
        conf_file = sys.argv[1]
    else:
        conf_file = os.path.join(base_dir, 'dev.conf' if dev else 'main.conf')
    app.merge(conf_file)
    cherrypy.config.update(conf_file)

    if dev:
        cherrypy.server.quickstart()
        cherrypy.engine.start()
        cherrypy.engine.block()
    else:
        cherrypy.server.unsubscribe()
        cherrypy.engine.start()
        from flup.server.fcgi import WSGIServer
        server = WSGIServer(app)
        server.run()
