#I love Alex

# To run the code type the following into the command prompt 
# in the EC_521_ML folder type python test1.py. 
import keras as keras
import time
import datetime
from keras.models import Sequential
from keras.layers import Dense
import numpy as np 

seed = 7
np.random.seed(seed)

# *************************************************************************
#**************** This part of the code formats the data ******************
#**************************************************************************

# This is where we will load the data-set 
# Assuming we will load from csv... 
# dataset = np.loadtxt(...)
theData = np.load("Data.npy")
theLabels = np.load("Labels.npy")
theData = np.reshape(theData, (len(theLabels), 128))
# Split the data set into training and testing here: 
# [[packet, packet, packet, packet, packet, packet label]
#  [ packet packet packet packet packet,    packet label]]
# trainData = theData[0:len(theData)-1000] # np.random.choice(theData, len(theData) -1000)
count = 0
trainData = np.array([])

for data in theData:
  trainData = np.append(trainData, np.append(data, theLabels[count]))
  count += 1

trainData = np.reshape(trainData, (len(theLabels), 129))

idxTrain = np.random.choice(len(trainData), len(trainData)-1000)
idxTest = np.random.choice(len(trainData), 1000)

testData = trainData[idxTest,:]
trainData = trainData[idxTrain,:] 
trainLabels = trainData[:, 128:]
trainLabels = keras.utils.to_categorical(trainLabels, num_classes=3)
trainData = trainData[:,0:128]
testLabels = testData[:,128:]
testData = testData[:,0:128]

#print(trainLabels)
#test = dataset[:]

#************************************************************************
#************************************************************************

#************************************************************************
#************** This part of the code makes the CNN *********************
#************************************************************************

# Create the model here: 
neuralNetModel = Sequential()
numInputs = 128 
# neuralNetModel = load_model('weight1.h5')
# This should create a sequential model that accepts ? inputs and
# has a signle hidden layer with 1000 nodes. The dense command makes it a 
# fully connected graph. We have 1 output node one for our first model
# that does binary classification. 


# ******************* Instructions ***************************
# The following are the things you can tune within the model: 
# nH1 is equal to the nodes in the hidden layer 1.
testNumber = 0 
activationList = ["sigmoid","relu","softmax"]
nH1 = 0
logFile = open("Test_result2s.txt","a+")
progStartTime = str(datetime.datetime.now())
# logFile.write("Test started at %s \r\n" % progStartTime)
# for activation_type in activationList:
# 	logFile.write("\r\n")
# 	logFile.write("------------------------------------------------------ \r\n")
# 	logFile.write("Changing Activation to %s \r\n" % activation_type)
# 	logFile.write("------------------------------------------------------ \r\n")
# 	logFile.write("\r\n")
# 	activation1 = activation_type
# 	for x in range(1,51):
# 		testNumber = testNumber +1
# 		print ("Running Test Number %d out of 150" % testNumber)
# 		nH1 = nH1 + 100 # default is 200
# 		# activation1 = activation_type
startTime = time.time()
# nH2 = 3000
#	Results: at 200 acc = 50.75%
#			 at 300 acc = 47.94%
#			 at 100 acc = 26.35%
#			 at 2000 acc = 61.04% 
#			 at 3000 acc = 63.16%
#			 at 30000 acc = 31.83%	#time taken ~= 100s
#			 at 5000 acc = 51.86%
# 			 at 4000 acc = 59.62%
# 			 at 3500 acc = 56.56%
# print("nh1 is ",nH1)
# Too many nodes will overfit the training set. Too little nodes and you wont 
# be capturing all the features. 
# The more nodes the longer it will take to run. So be forewarned. 
# ****************** End Instruction ****************************
# neuralNetModel.add(Dense(nH1, input_dim=numInputs, activation='relu'))
neuralNetModel.add(Dense(3000, input_dim=numInputs, activation="sigmoid"))
# neuralNetModel.add(Dense(nH1, input_dim=numInputs, activation='softmax'))
# 

neuralNetModel.add(Dense(3, activation="sigmoid")) 
# This command compiles the model
neuralNetModel.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])


# ***************** Instruction ************************** 
# The following are the things you can change in the neural net
# The number of Epochs of training. The more epochs the more you overfit the 
# the training set. Too little epochs and you will not capture enough features. 
# sizeBatch is how many training values does the model train on at once. 
# the batch size is always less then the actual number of data. The smaller the 
# batchSize the fewer features you are training against at once. Speeds up or slows down 
# your model 
numEpochs = 20
sizeBatch = 500
# ***************** End Instruction **************************
# The following command will train the model on some data: 
neuralNetModel.fit(trainData, trainLabels, epochs=numEpochs, batch_size=sizeBatch)

# Find predictions on some test set 
# predictions = model.predict(test) 
endTime = time.time()
# ******************* Instruction **************************************
# The metric you are going to try and increase is accuracy. 
# If you can get it to 60 or 70 then we have succeeded and just save the weights. 
# ******************** End Instruction ********************************
scores = neuralNetModel.evaluate(trainData, trainLabels)
print("\n%s: %.2f%%" % (neuralNetModel.metrics_names[1], scores[1]*100))
print("Saving Weights: ")
# print(("Weights" + str(datetime.datetime.now())[0:10]+str(datetime.datetime.now())[11:16]+".h5"))
now = datetime.datetime.now()
# print(str(now.isoformat()))
filename ="Weights_"+ (now.strftime("%Y_%m_%d_%H_%M"))+".h5"
neuralNetModel.save_weights(filename)
# neuralNetModel.save_weights("Weights" + str(datetime.datetime.now())[0:10]+str(datetime.datetime.now())[11:16]+".h5")


#ogFile.write("%d. nH1 = %d, activation = %s ,epoch = %d, BatchSize = %d, Results: 	acc: %.2f%% Time taken: %.2fs\r\n" %(testNumber, nH1 ,activation1, numEpochs, sizeBatch,(scores[1]*100),(endTime-startTime)))

# logFile.write("\r\n")
# logFile.write("------------------------------------------------------ \r\n")
# logFile.write("Ran total %d tests. \r\n" %testNumber)
# logFile.write("\r\n")
progEndTime = (datetime.datetime.now())
progRunTime = endTime-startTime
# logFile.write("Test ended at %s \r\n"% progEndTime)
# logFile.write("------------------------------------------------------ \r\n")
# logFile.write("\r\n")
# logFile.close()
print("Test Run Time was %s \r\n" %progRunTime) 



	