# -*- coding: iso-8859-1 -*-

from Drivers.FiscalPrinterDriver import FiscalPrinterDriver, ComunicationError
import random
import time

__name__ = "HasarDriver"


class HasarDriver(FiscalPrinterDriver):
    ACK = chr(0x06)
    NAK = chr(0x15)
    STATPRN = chr(0xa1)

    fiscalStatusErrors = [(1 << 0 + 1 << 7, "Memoria Fiscal llena"),
                          (1 << 0, "Error en memoria fiscal"),
                          (1 << 1, "Error de comprobación en memoria de trabajo"),
                          (1 << 2, "Poca batería"),
                          (1 << 3, "Comando no reconocido"),
                          (1 << 4, "Campo de datos no válido"),
                          (1 << 5, "Comando no válido para el estado fiscal"),
                          (1 << 6, "Desbordamiento de totales"),
                          (1 << 7, "Memoria Fiscal llena"),
                          (1 << 8, "Memoria Fiscal casi llena"),
                          (1 << 11,
                           "Es necesario hacer un cierre de la jornada fiscal o se superó la cantidad máxima de tickets en una factura."),
                          ]

    printerStatusErrors = [(1 << 2, "Error y/o falla de la impresora"),
                           (1 << 3, "Impresora fuera de linea"),
                           ##                          (1<<4, "Poco papel para la cinta de auditoría"),
                           ##                          (1<<5, "Poco papel para comprobantes o tickets"),
                           (1 << 6, "Buffer de impresora lleno"),
                           (1 << 8, "Tapa de impresora abierta"),
                           ]
                               
    def start(self):
        pass

    def close(self):
        pass

    def _initSequenceNumber(self):
        self._sequenceNumber = random.randint(0x20, 0x7f)
        if self._sequenceNumber % 2:
            self._sequenceNumber -= 1

    def _incrementSequenceNumber(self):
        # Avanzo el número de sequencia, volviendolo a 0x20 si pasó el limite
        self._sequenceNumber += 2
        if self._sequenceNumber > 0x7f:
            self._sequenceNumber = 0x20

    def _sendAndWaitAck(self, message, count=0):
        if count > 10:
            raise ComunicationError, "Demasiados NAK desde la impresora. Revise la conexión."
        self._write(message)
        timeout = time.time() + self.WAIT_TIME
        while 1:
            if time.time() > timeout:
                raise ComunicationError, "Expiró el tiempo de espera para una respuesta de la impresora. Revise la conexión."
            c = self._read(1)
            if len(c) == 0:
                continue
            if c == self.ACK:
                return True
            if c == self.NAK:
                return self._sendAndWaitAck(message, count + 1)

    def _sendMessage(self, message):
        # Envía el mensaje
        # @return reply Respuesta (sin el checksum)
        self._sendAndWaitAck(message)
        timeout = time.time() + self.WAIT_TIME
        retries = 0
        while 1:
            if time.time() > timeout:
                raise ComunicationError, "Expiró el tiempo de espera para una respuesta de la impresora. Revise la conexión."
            c = self._read(1)
            if len(c) == 0:
                continue
            if ord(c) in (0x12, 0x14):  # DC2 o DC4
                # incrementar timeout
                timeout += self.WAIT_TIME
                continue
            ##            if ord(c) == self.NAK: # NAK
            ##                if retries > self.RETRIES:
            ##                    raise ComunicationError, "Falló el envío del comando a la impresora luego de varios reintentos"
            ##                # Reenvío el mensaje
            ##                self._write( message )
            ##                timeout = time.time() + self.WAIT_TIME
            ##                retries +=1
            ##                continue
            if c == chr(0x02):  # STX - Comienzo de la respuesta
                reply = c
                noreplyCounter = 0
                while c != chr(0x03):  # ETX (Fin de texto)
                    c = self._read(1)
                    if not c:
                        noreplyCounter += 1
                        time.sleep(self.WAIT_CHAR_TIME)
                        if noreplyCounter > self.NO_REPLY_TRIES:
                            raise ComunicationError, "Fallo de comunicación mientras se recibía la respuesta de la impresora."
                    else:
                        noreplyCounter = 0
                        reply += c
                bcc = self._read(4)  # Leo BCC
                if not self._checkReplyBCC(reply, bcc):
                    # Mando un NAK y espero la respuesta de nuevo.
                    self._write(self.NAK)
                    timeout = time.time() + self.WAIT_TIME
                    retries += 1
                    if retries > self.RETRIES:
                        raise ComunicationError, "Fallo de comunicación, demasiados paquetes inválidos (bad bcc)."
                    continue
                elif reply[1] != chr(self._sequenceNumber):  # Los número de seq no coinciden
                    # Reenvío el mensaje
                    self._write(self.ACK)
                    # self._sendAndWaitAck( message )
                    timeout = time.time() + self.WAIT_TIME
                    retries += 1
                    if retries > self.RETRIES:
                        raise ComunicationError, "Fallo de comunicación, demasiados paquetes inválidos (bad sequenceNumber)."
                    continue
                else:
                    # Respuesta OK
                    self._write(self.ACK)
                    break
        return reply
