import h5py
import numpy as np
import tensorflow as tf
import math
import pandas as pd
from numpy import genfromtxt

def load_dataset():
    train_dataset = h5py.File('datasets/train_signs.h5', "r")
    train_set_x_orig = np.array(train_dataset["train_set_x"][:]) # your train set features
    train_set_y_orig = np.array(train_dataset["train_set_y"][:]) # your train set labels

    test_dataset = h5py.File('datasets/test_signs.h5', "r")
    test_set_x_orig = np.array(test_dataset["test_set_x"][:]) # your test set features
    test_set_y_orig = np.array(test_dataset["test_set_y"][:]) # your test set labels

    classes = np.array(test_dataset["list_classes"][:]) # the list of classes
    
    train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0]))
    test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0]))
    
    return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, classes

def loading_source_new():
    trainsource_set_x_orig1=pd.read_csv('datasets-sa/trainfeatures-source-0-9.csv',header=None)
    trainsource_set_y_orig1=pd.read_csv('datasets-sa/trainlabels-source-0-9.csv',header=None)
    #trainsource_set_x_orig1=pd.read_csv('datasets-sa/resnet18-cfar100-features10class.csv',header=None)
    #trainsource_set_y_orig1=pd.read_csv('datasets-sa/resnet18-cfar100-labels10class.csv',header=None)
    
    
    
    return trainsource_set_x_orig1, trainsource_set_y_orig1

def loading_sketch():
    features_train=pd.read_csv('train_sketch_features.csv',header=None)
    labels_train=pd.read_csv('train_sketch_labels.csv',header=None)
    features_test=pd.read_csv('test_sketch_features.csv',header=None)
    labels_test=pd.read_csv('test_sketch_labels.csv',header=None)
    
    return features_train, labels_train, features_test, labels_test

def loading_clipart():
    features_train=pd.read_csv('train_clipart_features.csv',header=None)
    labels_train=pd.read_csv('train_clipart_labels.csv',header=None)
    features_test=pd.read_csv('test_clipart_features.csv',header=None)
    labels_test=pd.read_csv('test_clipart_labels.csv',header=None)
    
    return features_train, labels_train, features_test, labels_test



def loading_target1():
    features_train=pd.read_csv('datasets-sa/trainfeatures-target-cfar-0-4.csv',header=None)
    labels_train=pd.read_csv('datasets-sa/trainlabels-target-cfar-0-4.csv',header=None)
    features_test=pd.read_csv('datasets-sa/testfeatures-target-cfar-0-4.csv',header=None)
    labels_test=pd.read_csv('datasets-sa/testlabels-target-cfar-0-4.csv',header=None)
    
    return features_train, labels_train, features_test, labels_test

def loading_target2():
    features_train=pd.read_csv('datasets-sa/trainfeatures-target-imagenet-8-12.csv',header=None)
    labels_train=pd.read_csv('datasets-sa/trainlabels-target-imagenet-8-12.csv',header=None)
    features_test=pd.read_csv('datasets-sa/testfeatures-target-imagenet-8-12.csv',header=None)
    labels_test=pd.read_csv('datasets-sa/testlabels-target-imagenet-8-12.csv',header=None)
    
    return features_train, labels_train, features_test, labels_test

def loading_target3():
    features_train=pd.read_csv('datasets-sa/trainfeatures-target-imagenet-15-19.csv',header=None)
    labels_train=pd.read_csv('datasets-sa/trainlabels-target-imagenet-15-19.csv',header=None)
    features_test=pd.read_csv('datasets-sa/testfeatures-target-imagenet-15-19.csv',header=None)
    labels_test=pd.read_csv('datasets-sa/testlabels-target-imagenet-15-19.csv',header=None)
    
    return features_train, labels_train, features_test, labels_test
                       
    
    
def loading_train_test():
    train_feature_500_target=pd.read_csv('datasets-sa/trainfeatures500-target.csv',header=None)
    train_label_500_target=pd.read_csv('datasets-sa/trainlabels500-target.csv',header=None)
    test_feature_200_target=pd.read_csv('datasets-sa/testfeatures200-target.csv',header=None)
    test_label_200_target=pd.read_csv('datasets-sa/testlabels200-target.csv',header=None)
    
    return train_feature_500_target, train_label_500_target, test_feature_200_target, test_label_200_target 
    


def random_mini_batches(X, Y, mini_batch_size = 64, seed = 0):
    """
    Creates a list of random minibatches from (X, Y)
    
    Arguments:
    X -- input data, of shape (input size, number of examples)
    Y -- true "label" vector (containing 0 if cat, 1 if non-cat), of shape (1, number of examples)
    mini_batch_size - size of the mini-batches, integer
    seed -- this is only for the purpose of grading, so that you're "random minibatches are the same as ours.
    
    Returns:
    mini_batches -- list of synchronous (mini_batch_X, mini_batch_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

def convert_to_one_hot(Y, C):
    Y = np.eye(C)[Y.reshape(-1)].T
    return Y


def predict(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("float", [12288, 1])
    
    z3 = forward_propagation_for_predict(x, params)
    p = tf.argmax(z3)
    
    sess = tf.Session()
    prediction = sess.run(p, feed_dict = {x: X})
        
    return prediction

def forward_propagation_for_predict(X, parameters):
    """
    Implements the forward propagation for the model: LINEAR -> RELU -> LINEAR -> RELU -> LINEAR -> SOFTMAX
    
    Arguments:
    X -- input dataset placeholder, of shape (input size, number of examples)
    parameters -- python dictionary containing your parameters "W1", "b1", "W2", "b2", "W3", "b3"
                  the shapes are given in initialize_parameters

    Returns:
    Z3 -- the output of the last LINEAR unit
    """
    
    # Retrieve the parameters from the dictionary "parameters" 
    W1 = parameters['W1']
    b1 = parameters['b1']
    W2 = parameters['W2']
    b2 = parameters['b2']
    W3 = parameters['W3']
    b3 = parameters['b3'] 
                                                           # Numpy Equivalents:
    Z1 = tf.add(tf.matmul(W1, X), b1)                      # Z1 = np.dot(W1, X) + b1
    A1 = tf.nn.relu(Z1)                                    # A1 = relu(Z1)
    Z2 = tf.add(tf.matmul(W2, A1), b2)                     # Z2 = np.dot(W2, a1) + b2
    A2 = tf.nn.relu(Z2)                                    # A2 = relu(Z2)
    Z3 = tf.add(tf.matmul(W3, A2), b3)                     # Z3 = np.dot(W3,Z2) + b3
    
    return Z3
    
