import json
import flask
import datetime
import sys

from collections import Counter
import statsmodels.api as sm
import numpy as np
import matplotlib.pylab as plt


# input is the json data and output is x (a list of datetimes) and y (a list of counts for demand each hour)
def process_input(json_data):
    raw_data = json.load(json_data)
    data = [datetime.datetime.strptime(s[:-12], '%Y-%m-%dT%H') for s in raw_data]
    first = min(data) # earliest datetime
    last = max(data) # latest datetime
    total_hours = (last-first).days*24 + (last-first).seconds//3600
    counts = Counter(data)
    # x is array of datetime objects for the time period covered and y are the counts of logins
    x = [first + datetime.timedelta(hours=k) for k in range(0,total_hours+1)]
    y = [counts[k] for k in x]
    return x, y

# input is a list x, a lists of lists y_array, and a list of strings as the labels
# Each list in y_array will be plotted against x
def plot_series(x, y_array, labels):
    for y_arr, label in zip(y_array, labels):
        plt.plot(x, y_arr, label=label)
        plt.xlabel('Datetime')
        plt.ylabel('Demand')
        plt.title('Models of demand using trends and ARMA')
    plt.gcf().set_size_inches(26,20)
    plt.legend()
    plt.show()

# input is two lists and returns the root mean square error
def rms(y, predict):
    diff = [w1 - w2 for (w1,w2) in zip(y, predict)]
    return np.sqrt(np.mean([x**2 for x in diff]))

def main():
    # Process input data
    app = flask.Flask(__name__)
    app.run()
    #json_data=open('C:/Users/rthomas/Documents/DemandPrediction/demand_prediction.json')
    json_data = open(sys.argv[1])
    x, y = process_input(json_data)

    # I looked at a few different trend lines
    trend_model1 = sm.OLS(y, sm.add_constant(range(len(x)), prepend=True)).fit()
    trend_model2 = sm.GLM(y, sm.add_constant(range(len(x)), prepend=True), family=sm.families.InverseGaussian()).fit()
    trend_model3 = sm.GLM(y, sm.add_constant(range(len(x)), prepend=True), family=sm.families.Gamma()).fit()
    trend_model4 = sm.GLM(y, sm.add_constant(range(len(x)), prepend=True), family=sm.families.Gaussian()).fit()

    rms_list = []

    for trend_model in [trend_model1, trend_model2, trend_model3, trend_model4]:

        trend = trend_model.fittedvalues

        # y1 is y with the trend line (growth over time) removed
        y1 = y - trend
    
        # y2 is y1 with weekly trends removed
        days = [w.weekday() for w in x]
        days_mean = [np.mean([y1[i] for i in range(0,len(y1)) if days[i] == k]) for k in range(7)]
        y2 = [y1[i] - days_mean[days[i]] for i in range(len(y1))]
    
        # y3 is y2 with daily trends removed
        hours = [w.hour for w in x]
        hours_mean = [np.mean([y2[i] for i in range(0,len(y2)) if hours[i] == k]) for k in range(24)]
        y3 = [y2[i] - hours_mean[hours[i]] for i in range(len(y2))]

        trend_y = [days_mean[days[i]] + hours_mean[hours[i]] + trend[i] for i in range(len(trend))]

        # construct an ARMA model on the residuals once all trends have been removed
        arma_model = sm.tsa.ARMA(y3)
        arma_fit = arma_model.fit(order=(6,6))
        arma_res = arma_fit.predict()
        arma_y = [arma_res[i] + trend_y[i] for i in range(len(trend))]

        plot_series(x, [y, trend_y, arma_y], ['Time Series', 'All trends', 'All trends + ARMA'])

        rms_arr = []
        for predict in [trend_y, arma_y]:
            rms_arr.append(rms(y, predict))
            
        rms_list.append(rms_arr)
        
    print rms_list

if __name__ == '__main__':
    main()


#app.config['DEBUG'] = True





