#!/usr/bin/env python

import json
import os
import optparse

import argweaver
from argweaver.bottle import get
#from argweaver.bottle import HTTPResponse
from argweaver.bottle import request
from argweaver.bottle import response
from argweaver.bottle import run
from argweaver.bottle import static_file
from argweaver.bottle import template
from argweaver.db import ArgDB
from argweaver.db import ArgLayoutDB
from argweaver.db import SitesDB

from rasmus import util


o = optparse.OptionParser(
    description="""
Web server for hosting ARGs and sites for visualization and analysis.
""")
o.add_option("-a", "--arg", action="append", default=[])
o.add_option("-s", "--sites", action="append", default=[])
o.add_option("-l", "--layout", action="append", default=[])
o.add_option("-p", "--port", type="int", default=8080)
o.add_option("", "--pub", action="store_true")


conf, args = o.parse_args()

#=============================================================================
# constants


BASE_DIR = os.path.dirname(os.path.dirname(__file__))
STATIC_DIR = os.path.join(BASE_DIR, 'argserver/static')
TEMPLATES_DIR = os.path.join(BASE_DIR, 'argserver/templates')


#=============================================================================
# functions


def parse_region(region):
    chrom, region = region.split(":")
    tokens = region.split("-")
    if len(tokens) != 2:
        raise Exception("bad region format")
    start = int(tokens[0])
    end = int(tokens[1])
    return chrom, start, end


#=============================================================================
# routes


# get one tree
@get('/tree/:pos')
def get_tree(pos=0):
    chrom, pos = pos.split(":")
    pos = int(pos)

    callback = request.query.get("callback", "jsonp_callback")

    try:
        return (callback + "('" +
                json.dumps(smc_db.get_trees(chrom, pos, pos).next()) + "');")
    except:
        return ""


# get one tree and spr
@get('/tree-spr/:pos')
def get_tree_spr(pos=0):
    chrom, pos = pos.split(":")
    pos = int(pos)

    callback = request.query.get("callback", "jsonp_callback")

    try:
        result = [smc_db.get_trees(chrom, pos, pos).next()]
        end = result[0]["end"]
        result.append(smc_db.get_sprs(chrom, end, end+1).next())
    except:
        result = []

    return callback + "('" + json.dumps(result) + "');"


# get a region of trees and sprs
@get('/trees/:region')
def get_trees(region=""):
    chrom, start, end = parse_region(region)
    callback = request.query.get("callback", "jsonp_callback")

    result = []
    result.extend(smc_db.get_trees(chrom, start, end))
    result.extend(smc_db.get_sprs(chrom, start, end))
    result.sort(key=lambda x: (x["start"], 1) if "start" in x
                else (x["pos"], 0))

    return callback + "('" + json.dumps(result) + "');"


# get a region of sprs
@get('/sprs/:region')
def get_sprs(region=""):
    chrom, start, end = parse_region(region)
    callback = request.query.get("callback", "jsonp_callback")

    result = list(smc_db.get_sprs(chrom, start, end))

    return callback + "('" + json.dumps(result) + "');"


# get a region of sprs
@get('/sites/:region')
def get_sites(region=""):
    chrom, start, end = parse_region(region)
    callback = request.query.get("callback", "jsonp_callback")

    result = []

    if sites_db:
        for pos, col in sites_db.get_sites(chrom, start, end, arg_names):
            result.append({"pos": pos, "col": col})

    return callback + "('" + json.dumps(result) + "');"


# get a layout of the ARG for a region
@get('/arg-layout/:region')
def get_arg_layout(region=""):
    chrom, start, end = parse_region(region)
    callback = request.query.get("callback", "jsonp_callback")
    result = [{"block": block, "leafLayout": leaf_layout}
              for block, leaf_layout in layout_db.get_layout(
                  chrom, start, end)]
    return callback + "('" + json.dumps(result) + "');"


# get static files
@get('/static/<filename:re:.*>')
def get_static_file(filename):
    return static_file(filename, root=STATIC_DIR)


# home page
@get('/<position:re:|pos/.*>')
def get_home(position):
    if position and position.startswith('pos/'):
        position = position[4:]
    else:
        position = 'chr:1-1000'
    host = "%s://%s" % (request.urlparts.scheme,
                        request.urlparts.netloc)
    context = {
        'host': host,
        'position': position
    }
    return template(TEMPLATES_DIR + '/index.html', context)


# get argtrack.js
@get('/argtrack.js')
def get_argtrack():
    response.headers['Content-Type'] = 'text/javascript'
    host = "%s://%s" % (request.urlparts.scheme,
                        request.urlparts.netloc)
    return template(TEMPLATES_DIR + '/argtrack.js',
                    {"host": host})

#=============================================================================

# read ARGs
util.tic("reading ARGs...")
smc_db = None
for smc_file in conf.arg:
    if smc_file.endswith(".db"):
        smc_db = ArgDB().connect(smc_file)
    else:
        if not smc_db:
            smc_db = ArgDB().connect(":memory:")
        smc_db.add_smc_file(smc_file)
arg_names = smc_db.get_names() if smc_db else []
util.toc()


# read sites
util.tic("reading sites...")
sites_db = None
for sites_file in conf.sites:
    if sites_file.endswith(".db"):
        sites_db = SitesDB().connect(sites_file)
    else:
        if not sites_db:
            sites_db = SitesDB().connect(":memory:")
        sites_db.add_sites_file(sites_file)
util.toc()


# read ARG layout
util.tic("reading ARG lauouts...")
layout_db = ArgLayoutDB()
for layout_file in conf.layout:
    layout_db.add_layout_file(layout_file)
util.toc()


if conf.pub:
    run(host='', port=conf.port)
else:
    run(host='localhost', port=conf.port)
