import socket
import json
import time


class MarkoPrinter:
    def __init__(self, configFilePath):
        self.inkStatCounter = 0
        self.printSock = None
        self.headStatus = dict()
        self.connected = False
        self.sending = False
        with open(configFilePath, "r") as setFile:
            self.settings = json.load(setFile)
        self.data = self.settings["printcmd"]
        self.debug = True

    def log(self, *logtxt):
        if self.debug:
            print(*logtxt)

    def connetti(self):
        if not self.connected:
            if self.printSock is None:
                try:
                    self.printSock = socket.socket(
                        socket.AF_INET, socket.SOCK_STREAM)
                    self.printSock.connect(
                        (self.settings["ip"], self.settings["port"]))
                    self.connected = True
                    self.printSock.settimeout(0.5)
                    self.checkStatus()
                except socket.error as e:
                    self.printSock = None
                    self.connected = False
                    self.log("Connessione Fallita: {}".format(e))
            else:
                self.printSock.close()
                self.printSock = None
                self.connetti()
        return self.connected

    def disconnetti(self):
        if self.connected:
            self.printSock.close()
            self.printSock = None
            self.connected = False
        return self.connected

    def checkStatus(self):
        statusUpdated = False
        if self.connected:
            try:
                self.printSock.send(b"\x1BS1\r")
                time.sleep(1)
                c = self.printSock.recv(1)
                inData = b""
                while c != b"\r":
                    inData += c
                    if len(inData) > 200:
                        self.log("Status Message Length Error")
                        raise IOError
                    c = self.printSock.recv(1)
                inData = str(inData, "ascii")
                inData = inData.split(":")
                for index, key in enumerate(self.data["headstatus"]):
                    if key != "txt":
                        self.headStatus[key] = int(inData[index])
                    else:
                        self.headStatus[key] = str(inData[index])
                self.log("Status: {}".format(self.headStatus))
                statusUpdated = True
            except:
                self.log("Status retreive error!")
        return statusUpdated

    def upload(self, descr, datastr):
        self.sending = True
        response = ""
        if self.connected:
            cmdstr = "\x02TZ" + self.data["filename"] + \
                ";" + self.data["printmode"] + "\r"
            self.log(bytearray(descr, "ascii"))
            descr = descr.replace("\n", "\t")
            outstr = cmdstr + datastr + "\03\r"
            self.printSock.settimeout(1.0)
            try:
                self.printSock.send(bytearray(outstr, "ascii"))
                retval = self.printSock.recv(1)
                self.log("ACK: ", retval)
                if retval == b'\x06':
                    retval = self.printSock.recv(6)
                    if retval == b'\x021OK\x03':
                        self.log("RESP: ", retval)
                        response = "Invio Riuscito!"
                        self.log("Printer OK")
                    else:
                        response = "Invio Fallito!"
                        self.log("Printer Error")
                else:
                    self.log("Send Error")
                self.printSock.settimeout(0.5)
                statusUpdated = self.checkStatus()
                if self.headStatus["ink"] == 2:
                    response = "CARTUCCIA ESAURITA\nSostituire!"
                elif self.headStatus["ink"] == 1:
                    response = "Cartuccia in Esaurimento"
            except socket.error as e:
                self.log("Socket error: ", e)
                self.printSock.settimeout(0.5)
                response = "Invio Fallito!"
                self.printSock.sendall(b"\r"*5)
                self.printSock.recv(5)
        self.sending = False
        return response, statusUpdated

    def keepalive(self):
        statusUpdated = False
        if not self.sending:
            self.log("Keepalive")
            if self.connected:
                try:
                    self.printSock.send(b"\x1B*\r")
                    self.log(str(self.printSock.recv(5)))
                    if self.inkStatCounter <= self.settings["inkstat"]:
                        self.inkStatCounter += 1
                    else:
                        statusUpdated = self.checkStatus()
                        self.inkStatCounter = 0
                except:
                    self.disconnetti()
            return self.connected, statusUpdated
