# Importing the libraries

import time 
import numpy as np
from tensorflow import keras
from flask import Flask, request, jsonify
from flask_cors import CORS
from keras.preprocessing.sequence import pad_sequences
from keras.preprocessing.text import Tokenizer
import pickle

# Load Tensorflow and Keras Model

print('Loading Model ...')
model = keras.models.load_model('app/model.h5')

# marks prediction model
model1 = pickle.load(open('app/g3_model.pkl', 'rb'))
# pass/fail prediction model
model2 = pickle.load(open('app/passfail_model.pkl','rb'))
# grade prediction model
model3 = pickle.load(open('app/grade_model.pkl','rb'))

print('Model Loaded')

# Enabling Cors
app = Flask(__name__)


SEQUENCE_LENGTH = 300
POSITIVE = "POSITIVE"
NEGATIVE = "NEGATIVE"
NEUTRAL = "NEUTRAL"
SENTIMENT_THRESHOLDS = (0.6, 0.8)
#tokenizer = Tokenizer()

def conbinenegativeWords(comment):
    notWord = 'not'
    conbine = 'false'
    tempWord = []
    FinalText = ''
    x = '0'
    isSet ='false'
    tokens = []
    for eachWord in comment.split():
        if eachWord in notWord:
            if x in '0':
                eachWord = 'ABC'
                x = '1'
                isSet = 'true'
                tokens.append(eachWord)
        else:
            if x in '1':
                tempWord.append(eachWord)
                eachWord = ''
                x = '0'
                tokens.append(eachWord)
                
            else: 
                tokens.append(eachWord)
    if isSet in 'true':
        
        FinalText = " ".join(tokens)
        
        for tem in tempWord:
            
            FinalText = FinalText.replace('ABC','not'+tem)
            
        
    else:
        FinalText = comment
    return FinalText     
    
    




# loading
with open('app/tokenizer.pickle', 'rb') as handle:
    tokenizer = pickle.load(handle)

def decode_sentiment(score, include_neutral=True):
    if include_neutral:        
        label = NEUTRAL
        if score <= SENTIMENT_THRESHOLDS[0]:
            label = NEGATIVE
        elif score >= SENTIMENT_THRESHOLDS[1]:
            label = POSITIVE

        return label
    else:
        return NEGATIVE if score < 0.5 else POSITIVE

#return label, score and Time
def predict(text, include_neutral=True):
    start_at = time.time()
    # Tokenize text
    x_test = pad_sequences(tokenizer.texts_to_sequences([text]), maxlen=SEQUENCE_LENGTH)
    # Predict
    score = model.predict([x_test])[0]
    # Decode sentiment
    label = decode_sentiment(score, include_neutral=include_neutral)

    return {"label": label, "score": float(score),
       "elapsed_time": time.time()-start_at}
       
#Return Only score      
def predict_OnlyAccuracy(text, include_neutral=True):
    start_at = time.time()
    # Tokenize text
    x_test = pad_sequences(tokenizer.texts_to_sequences([text]), maxlen=SEQUENCE_LENGTH)
    # Predict
    score = model.predict([x_test])[0]
    # Decode sentiment
    label = decode_sentiment(score, include_neutral=include_neutral)

    return float(score)


# Test Route
@app.route('/')
def index():
    return "<h1>Review Prediction Flask API !!</h1>"

# Review Prediction Route
@app.route('/review_prediction',methods=['POST'])
def review_prediction():
    '''
    For direct API calls trought request
    '''
    data = request.get_json(force=True)
    start = time.time()
    
    reviewResultsList = []
    
    for var in data['review']:
        reviewResultsList.append(predict(conbinenegativeWords(var)));
	
    # Getting the prediciton
    #prediction_new = predict(conbinenegativeWords(data['review']));
    
    end = time.time()
    
    print('Prediction Time: ',end - start)

    
    return jsonify({"data":data, "result":reviewResultsList})


# Review Prediction Route Get Final value to Tutor
@app.route('/review_prediction_for_tutor',methods=['POST'])
def review_prediction_for_tutor():
    '''
    For direct API calls trought request
    '''
    data = request.get_json(force=True)
    start = time.time()
    
    reviewResultsList = []
    totalScore = 0
    
    for var in data:
        print(var);
        reviewResultsList.append(predict_OnlyAccuracy(conbinenegativeWords(var)));
	
    for item in reviewResultsList:
        totalScore = totalScore + item
    
    finalyPrecentage = (totalScore / len(reviewResultsList)) * 100
    end = time.time()
    
    print('Prediction Time: ',end - start)

    
    return jsonify({"result":finalyPrecentage})

#------------------------- IT18058338 Flask API Routes ------------------------------

@app.route('/predict_quiz_marks', methods=['POST'])
def predict_quiz_marks():
    data = request.get_json(force=True)
    print("json values - marks")
    print(data.values())

    prediction = model1.predict([np.array(list(data.values()))])

    # output = prediction[0]
    output = round(prediction[0],2)
    print(output)
    return jsonify(output)

@app.route('/predict_pass_fail', methods=['POST'])
def predict_pass_fail():
    data = request.get_json(force=True)
    print("json values - status")
    print(data.values())

    prediction = model2.predict([np.array(list(data.values()))])

    output = prediction[0]
    # output = round(prediction[0],2)
    print(output)
    return jsonify(int(output))

@app.route('/predict_grade', methods=['POST'])
def predict_grade():
    data = request.get_json(force=True)
    print("json values - grade")
    print(data.values())

    prediction = model3.predict([np.array(list(data.values()))])

    output = prediction[0]
    print(output)
    return jsonify(str(output))
