import pandas as pd
import numpy as np
import tensorflow as tf
import math
import neural_network_steps as nn

"""
The following code was adapted from a Coursera Deep Learning Specialization 
which I used to prepare myself to do classification part of the project
"""

#Loads the datasets from the csv files specified by the file names
def load_dataset(trainfile, validfile, testfile, CEfile):

    train_data = np.loadtxt(trainfile, delimiter = ',', skiprows = 1 )
    test_data = np.loadtxt(testfile, delimiter = ',', skiprows = 1 )
    valid_data = np.loadtxt(validfile, delimiter=',', skiprows=1)
    CE_data = np.loadtxt(CEfile, delimiter=',', skiprows=1)

    train_data = np.transpose(train_data)
    test_data = np.transpose(test_data)
    valid_data = np.transpose(valid_data)
    CE_data = np.transpose(CE_data)

    train_set_x = train_data[0:12][:]
    train_set_y = train_data[12][:]

    test_set_x = test_data[0:12][:]
    test_set_y = test_data[12][:]

    valid_set_x = valid_data[0:12][:]
    valid_set_y = valid_data[12][:]

    CE_set_x = CE_data[0:12][:]
    CE_set_y = CE_data[12][:]


    return train_set_x, train_set_y, valid_set_x, valid_set_y, test_set_x, test_set_y, CE_set_x, CE_set_y


#Predicts the labels for input data using the parameters trained by the model
def predict(X, n_x, parameters):
    W1 = tf.convert_to_tensor(parameters["W1"])
    b1 = tf.convert_to_tensor(parameters["b1"])
    W2 = tf.convert_to_tensor(parameters["W2"])
    b2 = tf.convert_to_tensor(parameters["b2"])
    W3 = tf.convert_to_tensor(parameters["W3"])
    b3 = tf.convert_to_tensor(parameters["b3"])

    params = {"W1": W1,
              "b1": b1,
              "W2": W2,
              "b2": b2,
              "W3": W3,
              "b3": b3}

    x = tf.placeholder(tf.float32, name="X", shape=[n_x, None])

    z3 = nn.forward_propagation(x, 1.0, params)
    p = tf.argmax(z3)

    with tf.Session() as sess:
        prediction = sess.run(p, feed_dict={x: X})

    return prediction

#Randomly shuffles the data into minibatches to feed the model
def random_mini_batches(X, Y, mini_batch_size, seed):
    """
    Creates a list of random minibatches from (X, Y)
    """

    m = X.shape[1]  # number of training examples
    mini_batches = []
    np.random.seed(seed)

    # Step 1: Shuffle (X, Y)
    permutation = list(np.random.permutation(m))
    shuffled_X = X[:, permutation]
    shuffled_Y = Y[:, permutation].reshape((Y.shape[0], m))

    # Step 2: Partition (shuffled_X, shuffled_Y). Minus the end case.
    num_complete_minibatches = math.floor(m / mini_batch_size)  # number of mini batches of size mini_batch_size in your partitionning

    for k in range(0, num_complete_minibatches):
        mini_batch_X = shuffled_X[:, k * mini_batch_size: k * mini_batch_size + mini_batch_size]
        mini_batch_Y = shuffled_Y[:, k * mini_batch_size: k * mini_batch_size + mini_batch_size]
        mini_batch = (mini_batch_X, mini_batch_Y)
        mini_batches.append(mini_batch)

    # Handling the end case (last mini-batch < mini_batch_size)
    if m % mini_batch_size != 0:
        mini_batch_X = shuffled_X[:, num_complete_minibatches * mini_batch_size: m]
        mini_batch_Y = shuffled_Y[:, num_complete_minibatches * mini_batch_size: m]
        mini_batch = (mini_batch_X, mini_batch_Y)
        mini_batches.append(mini_batch)

    return mini_batches

#Converts the labels of the data into the format needed for softmax function
def convert_to_one_hot(Y, C):
    Y = np.eye(C)[Y.reshape(-1)].T
    return Y