#
# The MIT License
#
# @copyright Copyright (c) 2017 Intel Corporation
# @copyright Copyright (c) 2020 ApertureData 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.
#

#! /usr/bin/python
import struct
from threading import Thread
import sys
import os
import socket
import urllib
import time
import json

# VDMS Protobuf import (autogenerated)
from . import queryMessage_pb2

class vdms(object):

    def __init__(self):
        self.dataNotUsed = []
        self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.conn.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)

        # TCP_QUICKACK only supported in Linux 2.4.4+.
        # We use startswith for checking the platform following Python's
        # documentation:
        # https://docs.python.org/dev/library/sys.html#sys.platform
        if sys.platform.startswith('linux'):
            self.conn.setsockopt(socket.SOL_TCP, socket.TCP_QUICKACK, 1)

        self.connected = False
        self.last_response = ''

    def __del__(self):
        self.conn.close()

    def connect(self, host='localhost', port=55555):
        self.conn.connect((host, port))
        self.connected = True

    def disconnect(self):
        self.conn.close()
        self.connected = False

    # Recieves a json struct as a string
    def query(self, query, blob_array = []):

        # Check the query type
        if not isinstance(query, str): # assumes json
            query_str = json.dumps(query)
        else:
            query_str = query

        if not self.connected:
            return "NOT CONNECTED"

        quer = queryMessage_pb2.queryMessage()
        # quer has .json and .blob
        quer.json = query_str

        # We allow both a "list of lists" or a "list"
        # to be passed as blobs.
        # This is because we originally forced a "list of lists",
        # for no good reason other than lacking Python skills.
        # But most of the apps pass a "list of list" as a param,
        # and we don't want to break backward-compatibility.
        # So we now allow both.
        for im in blob_array:
            if isinstance(im, list):
                # extend will insert the entire list at the end
                quer.blobs.extend(im)
            else:
                # append will just insert a single element at the end
                quer.blobs.append(im)

        # Serialize with protobuf and send
        data = quer.SerializeToString();
        sent_len = struct.pack('@I', len(data)) # send size first
        self.conn.send( sent_len )
        self.conn.send(data)

        # Recieve response
        recv_len = self.conn.recv(4)
        recv_len = struct.unpack('@I', recv_len)[0]
        response = b''
        while len(response) < recv_len:
            packet = self.conn.recv(recv_len - len(response))
            if not packet:
                return None
            response += packet

        querRes = queryMessage_pb2.queryMessage()
        querRes.ParseFromString(response)

        response_blob_array = []
        for b in querRes.blobs:
            response_blob_array.append(b)

        self.last_response = json.loads(querRes.json)

        return (self.last_response, response_blob_array)

    def get_last_response(self):
        return self.last_response

    def get_last_response_str(self):
        return json.dumps(self.last_response, indent=4, sort_keys=False)

    def print_last_response(self):
        print(self.get_last_response_str())
