#!/usr/bin/python
#
#
import os
from flask import Flask, request, url_for, render_template, redirect
import bokeh.plotting
import bokeh.resources
import bokeh.models
import ystockquote    # get quotes for notable tech stocks
from datetime import datetime, timedelta # doing math for "the last 30 days"
import collections  # to sort the ystockquote dictionary by date

# globals for bokeh - this generates javascript & css for inline graphs
js_resources = bokeh.resources.INLINE.render_js()
css_resources = bokeh.resources.INLINE.render_css()

# declare application instance
app = Flask(__name__)

# more-or-less template for the elasticsearch indices
elastic_d = {
    "index" : "",
    "size" : "0"
}

# fetch_data(symbol, number of days of history) - return a dictionary of arrays.
# Each k, v is a column - 'k' is the column name, 'v' is the array of data
# The output from here is intended to be an input to bokeh.plotting.ColumnDataSource()
def fetch_data(sym, days):
    # get last <N> days of data
    dt = datetime.today()
    yymmdd_now = "%04d-%02d-%02d" % (dt.year, dt.month, dt.day)
    dt = dt -timedelta(days=days)
    yymmdd_then = "%04d-%02d-%02d" % (dt.year, dt.month, dt.day)

    # get historical quotes
    data = ystockquote.get_historical_prices(sym, yymmdd_then, yymmdd_now)

    # initialize key/value return, order the yahoo data return (by date)
    all_data = []
    ordered_data = collections.OrderedDict(sorted(data.iteritems()))

    # transform data into column format - building arrays as we go along.
    # The ".setdefault()" stuff is to say that all_data{'random_key'} is an array when
    # it is first referenced/created.
    all_data = {}
    for date, stats in ordered_data.iteritems():
        # date_string is used for the data in the "Hover" bubble, date_epoch for plotting
        all_data.setdefault('date_string', []).append(date)
        all_data.setdefault('date_epoch', []).append(datetime.strptime(date,'%Y-%m-%d'))
        all_data.setdefault('symbol', []).append(sym)
        for datum, d_value in stats.iteritems():
            all_data.setdefault(datum,[]).append(d_value)

    return all_data

syms = [
    {'sym' : "IBM", 'line_color': "blue", 'fill_color': "blue"},
    {'sym' : "AAPL", 'line_color': "red", 'fill_color': "red"},
    {'sym' : "MSFT", 'line_color': "green", 'fill_color': "green"},
    {'sym' : "FB", 'line_color': "orange", 'fill_color': "orange"},
    {'sym' : "HP", 'line_color': "purple", 'fill_color': "purple"},
    {'sym' : "VZ", 'line_color': "blue", 'fill_color': "white"}
]

def generate_plot(**kwargs):
    days = 15
    if 'days' in kwargs:
        days = kwargs['days']

    hover = bokeh.models.HoverTool(
        tooltips = [
            ("Sym:", "@symbol"), ("Date", "@date_string"), ("Price", "$y{$0,0.000}")
        ]
    )

    p = bokeh.plotting.figure(
        tools=['pan', 'box_zoom', 'reset', 'save', hover], 
        title='Major Tech Stocks - Last %d Days' % (days),
        width = 1000, 
        x_axis_type = 'datetime',
        x_axis_label = 'Date', y_axis_label='Price US$')

    for l_sym in syms:
        sym_data = fetch_data(l_sym['sym'],  days)
        source = bokeh.plotting.ColumnDataSource(data=sym_data)
        # all data is in the columns - just select which column for the Y axis
        p.line('date_epoch', 'High', source=source,
               legend=l_sym['sym'], line_color=l_sym['line_color'])
        p.circle('date_epoch', 'High', source=source,
               legend=l_sym['sym'], line_color=l_sym['line_color'],
               fill_color=l_sym['fill_color'], size=8)
    return p

@app.route('/', methods=['GET'])
def index():
    p = generate_plot(days=15)
    script, div = bokeh.embed.components(p)
    return render_template('graph.html',
                           script=script,
                           div=div,
                           js_resources=js_resources,
                           css_resources=css_resources)

if __name__ == '__main__':
    port = int(os.getenv('PORT', 5010))
    if port == 5010:
        debug = True  # running locally
    else:
        debug = False
    app.run(debug=debug, host='0.0.0.0', port=port)
