#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Ren Zhang @ ryanzjlib dot gmail dot com

from keras.layers.core import Dense
from keras.layers.recurrent import LSTM
from keras.models import Sequential
from sklearn.preprocessing import MinMaxScaler
import numpy as np
import math
import os

DATA_DIR = "../data"

data = np.load(os.path.join(DATA_DIR, "LD_250.npy"))

STATELESS = False

NUM_TIMESTEPS = 20
HIDDEN_SIZE = 10
BATCH_SIZE = 96  # 24 hours (15 min intervals)
NUM_EPOCHS = 5

# scale the data to be in the range (0, 1)
data = data.reshape(-1, 1)
scaler = MinMaxScaler(feature_range=(0, 1), copy=False)
data = scaler.fit_transform(data)

# transform to 20 inputs -> 10 label format
X = np.zeros((data.shape[0], NUM_TIMESTEPS))
Y = np.zeros((data.shape[0], NUM_TIMESTEPS))
for i in range(len(data) - NUM_TIMESTEPS - NUM_TIMESTEPS):
    X[i] = data[i:i + NUM_TIMESTEPS].T
    Y[i] = data[i + NUM_TIMESTEPS:i + NUM_TIMESTEPS + NUM_TIMESTEPS].T

# reshape X to three dimensions (samples, timesteps, features)
X = np.expand_dims(X, axis=2)
Y = np.expand_dims(Y, axis=2)

sp = int(0.7 * len(data))
Xtrain, Xtest, Ytrain, Ytest = X[0:sp], X[sp:], Y[0:sp], Y[sp:]
print(Xtrain.shape, Xtest.shape, Ytrain.shape, Ytest.shape)

model = Sequential()
model.add(
    LSTM(
        HIDDEN_SIZE,
        stateful=False,
        activation = 'tanh',
        batch_input_shape=(BATCH_SIZE, NUM_TIMESTEPS, 1),
        return_sequences = True
        )
    )

model.add(Dense(1))

model.compile(
    loss="mean_squared_error",
    optimizer="adam",
    metrics=["mean_squared_error"]
    )

model.summary()

# stateful
# need to make training and test data to multiple of BATCH_SIZE
train_size = (Xtrain.shape[0] // BATCH_SIZE) * BATCH_SIZE
test_size = (Xtest.shape[0] // BATCH_SIZE) * BATCH_SIZE
Xtrain, Ytrain = Xtrain[0:train_size], Ytrain[0:train_size]
Xtest, Ytest = Xtest[0:test_size], Ytest[0:test_size]
print(Xtrain.shape, Xtest.shape, Ytrain.shape, Ytest.shape)
for i in range(NUM_EPOCHS):
    print("Epoch {:d}/{:d}".format(i+1, NUM_EPOCHS))
    model.fit(Xtrain, Ytrain, batch_size=BATCH_SIZE, epochs=1,
              validation_data=(Xtest, Ytest),
              shuffle=False)

pred = model.predict(Xtest, batch_size = BATCH_SIZE)

def smape(y_true, y_pred):
    '''
        calculate the symmetric mean absolute percentage error

        see: https://en.wikipedia.org/wiki/Symmetric_mean_absolute_percentage_error

    '''
    denominator = (np.abs(y_true) + np.abs(y_pred)) / 200.0
    diff = np.abs(y_true - y_pred) / denominator
    diff[denominator == 0] = 0.0
    return np.nanmean(diff)

print(smape(Ytest.flatten(), pred.flatten()))
