'''Tool for interacting with the model that is generated by elevation_NN.py.
Adam Forland RRCC, Data_Lab
'''

import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from keras.models import load_model


# Backend class loads the data and the model
class backend:
    
    # Load the data and normalize it for the network.
    def load_data():
        all_data_raw = np.load('../data/lookoutMt.npy')
        all_data = []
        
        # Remove data that is too low. (Broken points)
        for i in range(np.shape(all_data_raw)[0]):
            if all_data_raw[i][2] < 6000:
                continue
            else:
                all_data.append(all_data_raw[i])
        
        # All that data, not normalized
        all_data = np.array(all_data)
        
        # Normalize the domain space
        x_train = all_data[:, :2]
        x_train_lat = (all_data[:, 0:1] - np.min(all_data[:, 0:1]))/(np.max(all_data[:, 0:1]) -  np.min(all_data[:, 0:1])) 
        x_train_long = (all_data[:, 1:2] - np.min(all_data[:, 1:2]))/(np.max(all_data[:, 1:2]) -  np.min(all_data[:, 1:2]))
        
        print("Lat min:",  np.min(all_data[:, 0:1]), "lat max",  np.max(all_data[:, 0:1]))
        print("Lat min:",  np.min(all_data[:, 1:2]), "lat max",  np.max(all_data[:, 1:2]))

        # Final collection of the normalized data
        x_train = np.append(x_train_lat, x_train_long, axis=1)
        
        # Pull the elevation values off of all_data
        z = all_data[:, 2:]

        z_MAX = np.max(z)  # Collect the min and max for inverse for the elevation
        z_MIN = np.min(z) 
         
        lat_max = 39.7465277778
        lat_min = 39.7446759259

        long_min = -105.241805556
        long_max = -105.237361111

        val1 = (39.7456275855 - lat_min)/(lat_max - lat_min)
        val2 = (-105.241826522 - long_min)/(long_max-long_min)

        # Normalize the elevations
        # z = (z - np.min(z))/(np.max(z)-np.min(z))

        return(x_train, z, val1, val2)

    # Load the model that we trained
    def load_model():
        model = load_model('../data/models/e1_lambda_model_4000_Jul-13-2018.h5')
        return(model)


# Class for tools that the user can use to evaluate the network.
class user_evaluation:

    # Return one elevation for a given (normalized) lat,long.
    def test_one(location, model, MIN, MAX):
        return(((model.predict(np.array([[0.99, 0.99]]))) * (MAX - MIN)) + MIN)

    def batch_test():
        all_raw_training_data = np.load('../data/training_data/theM_10m.npy')  
        small_step = np.load('../data/validation_data/theM_1m.npy')  
        model = load_model('../data/models/e1_lambda_model_4000_Jul-13-2018.h5')
       
        # Cut the elevations that are too low
        training_step = []
        for i in range(np.shape(all_raw_training_data)[0]):
            if all_raw_training_data[i][2] < 3000:
                continue
            else:
                training_step.append(all_raw_training_data[i])
        
        training_step = np.array(training_step)

        lat_max = np.max(training_step[:, 0:1])
        lat_min = np.min(training_step[:, 0:1])

        long_max = np.max(training_step[:, 1:2])
        long_min = np.min(training_step[:, 1:2])

        info = []
        for i in range(np.shape(small_step)[0]):
            val1 = (small_step[i][0] - lat_min)/(lat_max - lat_min)
            val2 = (small_step[i][1] - long_min)/(long_max-long_min)
            z_pre = model.predict(np.array([[val1, val2]]))       
            diff = small_step[i][2] - z_pre
            info.append(diff)

        bar, bins = np.histogram(info, bins=100)
        plt.bar(bins[:-1], bar, width=10)
        plt.show()

# Class for tools that the network architect can use for evaluation
class network_evaluation:

    # Compute the differences between the given points and the network.
    def Error_assessment(model, x_train, z):
        z = model.predict(x_train)  # Calculate this difference

        # Plot the points and the predicted values. 
        fig = plt.figure()
        ax = fig.add_subplot(111, projection='3d')

        ax.scatter(x_train.T[:][0], x_train.T[:][1], z, c='g', marker='o')

        ax.set_xlabel('Latitude')
        ax.set_ylabel('Longitude')
        ax.set_zlabel('Elevation')

        plt.show()


# Running the methods.
x_train, z, LatN, LongN = backend.load_data()
model = backend.load_model()

#print(model.predict(np.array([[LatN,LongN]])))
#user_evaluation.batch_test()


#elevation = user_evaluation.test_one(1, model, MIN, MAX)
#print(elevation[0][0])

network_evaluation.Error_assessment(model, x_train, z)



