##
# Copyright (c) 2021 Xilinx, Inc.
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
# associated documentation files (the "Software"), to deal in the Software without restriction, including 
# without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
# copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to 
# the following conditions: 
# 
# The above copyright notice and this permission notice shall be included in all copies or substantial 
# portions of the Software. 
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
# LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# 
#
#
##
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
import socket
import json,datetime
from bson import json_util,ObjectId
import pymongo
import os, sys, inspect, importlib
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir)
from api import settings
from time import sleep                                                                                 
from api import users
from backend import rabbitmq_config

def myconverter(o):
    if isinstance(o, datetime.datetime):
        return o.__str__()

class WSHandler(tornado.websocket.WebSocketHandler):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.id = "wsocket"
        self.mongo = pymongo.MongoClient(settings.MONGO_URI)
        self.db = self.mongo.xregv

    def open(self):
        print('new connection')
        print('Host: %s' % self.request.host)
        print('Entire uri: %s' % self.request.uri)
        print('Uri path: %s' % self.request.path)
        print('Query path w/o ?: %s' % self.request.query)
        print(self.request.remote_ip)
        query_args = dict(self.request.query_arguments)     
        query_args = {k: v[0].decode("utf-8") for k,v in query_args.items()}
        if query_args.get("socketpath") == "browserhandler":
            uniquekey = query_args.get("uniquekey")
            users.set_user(uniquekey, {"clientconnectionstatus": True})

        self.id = self.request.uri.split("/")
        self.id = self.id[1]

    def on_message(self, message):
        try:
            body= json.loads(message)
            time = datetime.datetime.now()
            time = time.timestamp()
            if ("tabname" in body and body["tabname"].lower() in ["plot","overlay"]) or ("tab" in body and body["tab"].lower() in ["plot","overlay"]):
                self.write_message(json.dumps(self.customisegraphdata(body,time), default=myconverter))
            elif ("tabname" in body and body["tabname"].lower() in ["syswatch"]) or ("tab" in body and body["tab"].lower() in ["syswatch"]):
                self.write_message(json.dumps(self.watchgraph(body,time), default=myconverter))
            elif ( "tab" in body and body["tab"].lower() in ["active_connection"]):                                                                   
                self.write_message(json.dumps(self.checkconnection(body), default=myconverter))
            else:
                self.write_message(json.dumps(self.performancegraph(body,time), default=myconverter))
        except Exception as e:
            print("error", str(e))
            import traceback
            import traceback
            tb = traceback.format_exc()
            print("tb------>>", tb)

    def checkconnection(self, body):
        if "tab" in body:
            newdata = [{"tab": body["tab"], "data": [" message received"]}]
            return newdata
        else:
            return {"error":"Mandatory key missing"}

    def customisegraphdata(self, body, time):
        if "threads" in body:
            finaldata = []
            for i in body["threads"]:
                match = {"tabname":body["tab"]+"_"+body["uid"],"threadname":i["threadname"],"time":{"$gt":float(time)}}
                count = 1
                if "time" in i and i["time"]!= "":
                    time = i['time']
                    match["time"] = {"$gt":float(time)}
                data = list(self.db.overlaydb.find(match).sort([("time", pymongo.ASCENDING)]).limit(count))
                newdata = {"threadname":i["threadname"],"tabname": body["tab"]+"_"+body["uid"], "data": [], "time": time}
                if len(data):
                    newdata["tabname"] = data[0]["tabname"]
                    newdata["time"] = str(data[len(data) - 1]["time"])
                    for x in range(len(data)):
                        if "error" in data[x]:
                            newdata["error"] = data[x]["error"]
                        else:
                            for m in range(len(data[x]["data"])):
                                newdata["data"].append(data[x]["data"][m])
                finaldata.append(newdata)
            return finaldata
        else:
            return {"error":"Mandatory key missing"}

    def watchgraph(self, body, time):
        if "tabname" in body and "threadname" in body:
            match = {"tabname":body["tabname"],"threadname":body["threadname"],"time":{"$gt":float(time)}}
            count = 1
            if "time" in body and body["time"]!= "":
                time = body['time']
                match["time"] = {"$gt":float(time)}
            data = list(self.db.socketdata.find(match).sort([("time", pymongo.ASCENDING)]).limit(count))
            newdata = [{"tabname": body["tabname"], "data": [], "time": time, "threadname": body["threadname"]}]
            if len(data):
                newdata[0]["time"] = str(data[len(data) - 1]["time"])
                for x in range(len(data)):
                    for n in range(len(newdata)):
                        if newdata[n]["threadname"] == data[x]["threadname"]:
                            for m in range(len(data[x]["data"])):
                                newdata[n]["data"].append(data[x]["data"][m])
                            break
                        else:
                            if n == len(newdata)-1:
                                datum = []
                                for m in range(len(data[x]["data"])):
                                    datum.append(data[x]["data"][m])
                                newdata.append({"tabname": data[x]["tabname"], "data": datum, "time": str(data[len(data) - 1]["time"]), "threadname": data[x]["threadname"]})
                    if "error" in data[x]:
                        newdata["error"] = data[x]["error"]
            return newdata
        else:
            return {"error":"Mandatory key missing"}

    def performancegraph(self, body, time):
        if "tab" in body:
            matchnotfound = True
            for i in range(len(rabbitmq_config.queues)):
                if body["tab"] == rabbitmq_config.queues[i]["name"] or ("ddr_efficiency" in body["tab"] and rabbitmq_config.queues[i]["name"] == "ddr_efficiency"):
                    matchnotfound = False
                    match = {"tabname": body["tab"] + "_" + body["uid"], "time": {"$gte": float(time)}}
                    tabname_emptydata = body["tab"] + "_" + body["uid"]
                    if "threadname" in body:
                        threadname_emptydata = body["threadname"]
                    else:
                        threadname_emptydata = rabbitmq_config.queues[i]["config"]["tabname"] + "_" + body["uid"]
                    count = 1
                    if "time" in body and body["time"]!= "":
                        time = body['time']
                        match["time"] = {"$gt":float(time)}
                        count = 100
                    if "threadname" in body:
                        match["threadname"] = {"$in":body["threadname"]}
                    if "thread_createtime" in body:
                        match["thread_createtime"] = {"$in":body["thread_createtime"]}
                    data = list(self.db[rabbitmq_config.queues[i]["config"]["dbname"]].find(match).sort([("time", pymongo.ASCENDING)]).limit(count))
                    newdata = [{"threadname":threadname_emptydata,"tabname": tabname_emptydata, "data": [], "time": time}]
                    if len(data):
                        newdata[0]["time"] = str(data[len(data) - 1]["time"])
                        for x in range(len(data)):
                            if "error" in data[x]:
                                newdata[0]["error"] = data[x]["error"]
                            else:
                                for m in range(len(data[x]["data"])):
                                    newdata[0]["data"].append(data[x]["data"][m])
                    return newdata
                else:
                    matchnotfound = True
            if matchnotfound:
               return {"error":"No performance found"} 
        else:
            return {"error":"Mandatory key missing"}


    def send_message(self, message):
        self.write_message(message)

    def on_close(self):
        print('connection closed')
        query_args = dict(self.request.query_arguments)
        query_args = {k: v[0].decode("utf-8") for k,v in query_args.items()}
        if query_args.get("socketpath") == "browserhandler":
            uniquekey = query_args.get("uniquekey")
            users.set_user(uniquekey, {"clientconnectionstatus": False,"checkmodule_request": False})
        # self.application.remove_event_listener(self)

    def check_origin(self, origin):
        return True


application = tornado.web.Application([
    (r'/ws', WSHandler)
])

io_loop = tornado.ioloop.IOLoop.instance()
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(49999)
io_loop.start()
