import hid
# import hid
# pip install hidapi
# https://github.com/trezor/cython-hidapi
import time
import os

PACKET_SIZE = 65
DIR_OUTPUT = 0
DIR_INPUT = 1

class PyMCP2221A:
    def __init__(self, VID=0x04D8, PID=0x00DD, devnum=0):
        self.mcp2221a = hid.device()
        self.mcp2221a.open_path(hid.enumerate(VID, PID)[devnum]["path"])
        self.CLKDUTY_0 = 0x00
        self.CLKDUTY_25 = 0x08
        self.CLKDUTY_50 = 0x10
        self.CLKDUTY_75 = 0x18
        # self.CLKDIV_1 = 0x00    # 48MHz  Dont work.
        self.CLKDIV_2 = 0x01  # 24MHz
        self.CLKDIV_4 = 0x02  # 12MHz
        self.CLKDIV_8 = 0x03  # 6MHz
        self.CLKDIV_16 = 0x04  # 3MHz
        self.CLKDIV_32 = 0x05  # 1.5MHz
        self.CLKDIV_64 = 0x06  # 750KHz
        self.CLKDIV_128 = 0x07  # 375KHz

    def compile_packet(self, buf):
        """
        :param list buf:
        """
        assert len(buf) <= PACKET_SIZE

        buf = buf + [0 for i in range(PACKET_SIZE - len(buf))]
        return buf

    #######################################################################
    # HID DeviceDriver Info
    #######################################################################
    def DeviceDriverInfo(self):
        print("Manufacturer: %s" % self.mcp2221a.get_manufacturer_string())
        print("Product: %s" % self.mcp2221a.get_product_string())
        print("Serial No: %s" % self.mcp2221a.get_serial_number_string())

    #######################################################################
    # Command Structure
    #######################################################################
    def Command_Structure(self, I2C_Cancel_Bit, I2C_Speed_SetUp_Bit, I2C_Speed_SetVal_Byte):
        I2C_Cancel_Bit = 0
        I2C_Speed_SetUp_Bit = 0
        I2C_Speed_SetVal_Byte = 0
        buf = self.compile_packet([0x00, 0x10, 0x00,
                                   I2C_Cancel_Bit << 4,
                                   I2C_Speed_SetUp_Bit << 5,
                                   I2C_Speed_SetVal_Byte])

        self.mcp2221a.write(buf)
        buf = self.mcp2221a.read(PACKET_SIZE)

        print(chr(buf[46]))
        print(chr(buf[47]))
        print(chr(buf[48]))
        print(chr(buf[49]))

    #######################################################################
    # Read Flash Data
    #######################################################################

    def Read_Flash_Data(self, Read_Deta_Setting_Byte):
        Read_Deta_Setting_Byte = 0x00
        # Read_Chip_Settings             = 0x00
        # Read_GP_Settings               = 0x01
        # Read_USB_Manufacturer_Settings = 0x02
        # Read_USB_Product_Settings      = 0x03
        # Read_USB_SerialNum_Settings    = 0x04
        # Read_Chip_Factory_Settings     = 0x05

        buf = self.compile_packet([0x00, 0xB0, Read_Deta_Setting_Byte])
        # print ("Write")
        # print (buf)
        self.mcp2221a.write(buf)

        buf = self.mcp2221a.read(PACKET_SIZE)
        # print ("Read")
        # print (buf)

    #######################################################################
    # Write Flash Data
    #######################################################################

    def Write_Flash_Data(self, data):
        pass
        # Write_Deta_Setting_Byte = 0x00
        # Write_Chip_Settings             = 0x00
        # Write_GP_Settings               = 0x01
        # Write_USB_Manufacturer_Settings = 0x02
        # Write_USB_Product_Settings      = 0x03
        # Write_USB_SerialNum_Settings    = 0x04
        # buf = [0x00,0xB1,Write_Deta_Setting_Byte]
        # buf = buf + [0 for i in range(PACKET_SIZE-len(buf))]
        # !!!! Be careful when making changes !!!!
        # buf[6+1] =  0xD8    # VID (Lower)
        # buf[7+1] =  0x04    # VID (Higher)
        # buf[8+1] =  0xDD    # PID (Lower)
        # buf[9+1] =  0x00    # PID (Higher)

        # print ("Write")
        # print (buf)
        # h.write(buf)
        # buf = h.read(PACKET_SIZE)
        # print ("Read")
        # print (buf)

    #######################################################################
    # GPIO Init
    #######################################################################
    def GPIO_Init(self):
        buf = self.compile_packet([0x00, 0x61])
        self.mcp2221a.write(buf)

        rbuf = self.mcp2221a.read(PACKET_SIZE)

        buf = self.compile_packet([0x00, 0x60])
        buf[2 + 1] = rbuf[5]  # Clock Output Divider value
        buf[3 + 1] = rbuf[6]  # DAC Voltage Reference
        buf[4 + 1] = 0x00  # Set DAC output value
        buf[5 + 1] = 0x00  # ADC Voltage Reference
        # buf[6+1] = 0x00     #   Setup the interrupt detection mechanism and clear the detection flag
        buf[7 + 1] = 0x80  # Alter GPIO configuration: alters the current GP designation
        #   datasheet says this should be 1, but should actually be 0x80

        self.GPIO_0_BIT = (rbuf[22 + 1] >> 4) & 0x01  # 1:Hi 0:LOW
        self.GPIO_0_DIR = (rbuf[22 + 1] >> 3) & 0x01  # 0:OutPut 1:Input
        self.GPIO_0_MODE = rbuf[22 + 1] & 0x07  # GPIO MODE = 0x00
        self.GPIO_1_BIT = (rbuf[23 + 1] >> 4) & 0x01  # 1:Hi 0:LOW
        self.GPIO_1_DIR = (rbuf[23 + 1] >> 3) & 0x01  # 0:OutPut 1:Input
        self.GPIO_1_MODE = rbuf[23 + 1] & 0x07  # GPIO MODE = 0x00
        self.GPIO_2_BIT = (rbuf[24 + 1] >> 4) & 0x01  # 1:Hi 0:LOW
        self.GPIO_2_DIR = (rbuf[24 + 1] >> 3) & 0x01  # 0:OutPut 1:Input
        self.GPIO_2_MODE = rbuf[24 + 1] & 0x07  # GPIO MODE = 0x00
        self.GPIO_3_BIT = (rbuf[25 + 1] >> 4) & 0x01  # 1:Hi 0:LOW
        self.GPIO_3_DIR = (rbuf[25 + 1] >> 3) & 0x01  # 0:OutPut 1:Input
        self.GPIO_3_MODE = rbuf[25 + 1] & 0x07  # GPIO MODE = 0x00

        # for(i in range(64)):
        #    buf[i] = rbuf[i] | buf[i]
        self.mcp2221a.write(buf)
        buf = self.mcp2221a.read(PACKET_SIZE)

    #######################################################################
    # GPIO Set Direction and Set Value commands
    #######################################################################
    def GPIO_SetDirection(self, pin, direction):

        buf = self.compile_packet([0x00, 0x50])
        offset = (pin + 1) * 4
        buf[offset + 1] = 0x01  # set pin direction
        buf[offset + 1 + 1] = direction  # to this
        self.mcp2221a.write(buf)

        rbuf = self.mcp2221a.read(PACKET_SIZE)
        if rbuf[1] != 0x00:
            raise RuntimeError("GPIO_SetDirection Failed")

    def GPIO_SetValue(self, pin, value):

        buf = self.compile_packet([0x00, 0x50])
        offset = ((pin + 1) * 4) - 1
        buf[offset - 1 + 1] = 0x01  # set pin value
        buf[offset + 1] = value  # to this
        self.mcp2221a.write(buf)

        rbuf = self.mcp2221a.read(PACKET_SIZE)
        if rbuf[1] != 0x00:
            raise RuntimeError("GPIO_SetValue Failed")

    #######################################################################
    # Read GPIO Data command
    #######################################################################
    def GPIO_Read(self):

        buf = self.compile_packet([0x00, 0x51])
        self.mcp2221a.write(buf)

        buf = self.mcp2221a.read(PACKET_SIZE)
        self.GPIO_0_INPUT = buf[2]
        self.GPIO_0_DIR = buf[3]
        self.GPIO_1_INPUT = buf[4]
        self.GPIO_1_DIR = buf[5]
        self.GPIO_2_INPUT = buf[6]
        self.GPIO_2_DIR = buf[7]
        self.GPIO_3_INPUT = buf[8]
        self.GPIO_3_DIR = buf[9]
        return buf

    # Return the GPIO value as an integer instead of tuple
    def GPIO_GetValue(self, pin):
        rbuf = self.GPIO_Read()
        offset = (pin + 1) * 2
        if rbuf[offset] == 0xEE:
            raise RuntimeError("GPIO_GetValue Failed, pin is not set for GPIO operation")
        return rbuf[offset]

    #######################################################################
    # GPIO Outpu/Input Data
    #######################################################################
    def GPIO_0_Output(self, bit):
        self.GPIO_0_BIT = bit  # 1:Hi 0:LOW
        self.GPIO_0_OutputMode()
        self.GPIO_SetValue(pin=0, value=self.GPIO_0_BIT)

    def GPIO_0_InputMode(self):
        self.GPIO_0_DIR = DIR_INPUT  # 0:OutPut 1:Input
        self.GPIO_SetDirection(pin=0, direction=self.GPIO_0_DIR)

    def GPIO_0_OutputMode(self):
        self.GPIO_0_DIR = DIR_OUTPUT  # 0:OutPut 1:Input
        self.GPIO_SetDirection(pin=0, direction=self.GPIO_0_DIR)

    def GPIO_0_Input(self):
        self.GPIO_Read()
        return self.GPIO_0_INPUT, self.GPIO_0_DIR

    def GPIO_1_Output(self, bit):
        self.GPIO_1_BIT = bit  # 1:Hi 0:LOW
        self.GPIO_1_OutputMode()
        self.GPIO_SetValue(pin=1, value=self.GPIO_1_BIT)

    def GPIO_1_InputMode(self):
        self.GPIO_1_DIR = DIR_INPUT  # 0:OutPut 1:Input
        self.GPIO_SetDirection(pin=1, direction=self.GPIO_1_DIR)

    def GPIO_1_OutputMode(self):
        self.GPIO_1_DIR = DIR_OUTPUT  # 0:OutPut 1:Input
        self.GPIO_SetDirection(pin=1, direction=self.GPIO_1_DIR)

    def GPIO_1_Input(self):
        self.GPIO_Read()
        return self.GPIO_1_INPUT, self.GPIO_1_DIR

    def GPIO_2_Output(self, bit):
        self.GPIO_2_BIT = bit  # 1:Hi 0:LOW
        self.GPIO_2_OutputMode()
        self.GPIO_SetValue(pin=2, value=self.GPIO_2_BIT)

    def GPIO_2_InputMode(self):
        self.GPIO_2_DIR = DIR_INPUT  # 0:OutPut 1:Input
        self.GPIO_SetDirection(pin=2, direction=self.GPIO_2_DIR)

    def GPIO_2_OutputMode(self):
        self.GPIO_2_DIR = DIR_OUTPUT  # 0:OutPut 1:Input
        self.GPIO_SetDirection(pin=2, direction=self.GPIO_2_DIR)

    def GPIO_2_Input(self):
        self.GPIO_Read()
        return self.GPIO_2_INPUT, self.GPIO_2_DIR

    def GPIO_3_Output(self, bit):
        self.GPIO_3_BIT = bit  # 1:Hi 0:LOW
        self.GPIO_3_OutputMode()
        self.GPIO_SetValue(pin=3, value=self.GPIO_3_BIT)

    def GPIO_3_InputMode(self):
        self.GPIO_3_DIR = DIR_INPUT  # 0:OutPut 1:Input
        self.GPIO_SetDirection(pin=3, direction=self.GPIO_3_DIR)

    def GPIO_3_OutputMode(self):
        self.GPIO_3_DIR = DIR_OUTPUT  # 0:OutPut 1:Input
        self.GPIO_SetDirection(pin=3, direction=self.GPIO_3_DIR)

    def GPIO_3_Input(self):
        self.GPIO_Read()
        return self.GPIO_3_INPUT, self.GPIO_3_DIR

    #######################################################################
    # Clock Out Value & Duty
    #######################################################################
    def ClockOut(self, duty, value):
        """
        :param int duty:    Bit 4-3: Duty cycle
                            00 | 0% duty cycle
                            01 | 25% duty cycle
                            10 | 50% duty cycle
                            11 | 75% duty cycle
        :param int value:   Bit 2-0: Clock divider value
        """
        buf = self.compile_packet([0x00, 0x61])  # Get SRAM Settings

        self.mcp2221a.write(buf)
        rbuf = self.mcp2221a.read(PACKET_SIZE)

        buf = self.compile_packet([0x00, 0x60])  # Set SRAM Settings
        buf[2 + 1] = 0x80 | duty | (0x07 & value)  # Clock Output Divider value
        buf[3 + 1] = rbuf[6]  # DAC Voltage Reference
        buf[4 + 1] = 0x00  # Set DAC output value
        buf[5 + 1] = rbuf[7]  # ADC Voltage Reference
        buf[6 + 1] = 0x00  # Setup the interrupt detection mechanism and clear the detection flag
        buf[7 + 1] = 0x80  # Alter GPIO configuration: alters the current GP designation
        #   datasheet says this should be 1, but should actually be 0x80
        buf[8 + 1] = rbuf[22]  # GP0 settings
        buf[9 + 1] = 0x01  # GP1 settings - 001 Dedicated function operation (Clock Output)
        buf[10 + 1] = rbuf[24]  # GP2 settings
        buf[11 + 1] = rbuf[25]  # GP3 settings
        self.mcp2221a.write(buf)
        buf = self.mcp2221a.read(PACKET_SIZE)

    #######################################################################
    # ADC 1
    #######################################################################
    def ADC_1_Init(self):
        buf = self.compile_packet([0x00, 0x61])
        self.mcp2221a.write(buf)

        rbuf = self.mcp2221a.read(PACKET_SIZE)

        buf = self.compile_packet([0x00, 0x60])
        buf[2 + 1] = rbuf[5]  # Clock Output Divider value
        buf[3 + 1] = rbuf[6]  # DAC Voltage Reference
        buf[4 + 1] = 0x00  # Set DAC output value
        buf[5 + 1] = 0x00  # ADC Voltage Reference
        buf[6 + 1] = 0x00  # Setup the interrupt detection mechanism and clear the detection flag
        buf[7 + 1] = 0xFF  # Alter GPIO configuration: alters the current GP designation
        #   datasheet says this should be 1, but should actually be 0x80
        buf[8 + 1] = rbuf[22]  # GP0 settings
        buf[9 + 1] = 0x02  # GP1 settings
        buf[10 + 1] = rbuf[24]  # GP2 settings
        buf[11 + 1] = rbuf[25]  # GP3 settings
        self.mcp2221a.write(buf)
        buf = self.mcp2221a.read(PACKET_SIZE)

    #######################################################################
    # ADC 2
    #######################################################################

    def ADC_2_Init(self):
        buf = self.compile_packet([0x00, 0x61])
        self.mcp2221a.write(buf)

        rbuf = self.mcp2221a.read(PACKET_SIZE)

        buf = self.compile_packet([0x00, 0x60])
        buf[2 + 1] = rbuf[5]  # Clock Output Divider value
        buf[3 + 1] = rbuf[6]  # DAC Voltage Reference
        buf[4 + 1] = 0x00  # Set DAC output value
        buf[5 + 1] = rbuf[7]  # ADC Voltage Reference
        buf[6 + 1] = 0x00  # Setup the interrupt detection mechanism and clear the detection flag
        buf[7 + 1] = 0x80  # Alter GPIO configuration: alters the current GP designation
        #   datasheet says this should be 1, but should actually be 0x80
        buf[8 + 1] = rbuf[22]  # GP0 settings
        buf[9 + 1] = rbuf[23]  # GP1 settings
        buf[10 + 1] = 0x02  # GP2 settings
        buf[11 + 1] = rbuf[25]  # GP3 settings
        self.mcp2221a.write(buf)
        buf = self.mcp2221a.read(PACKET_SIZE)

    #######################################################################
    # ADC 3
    #######################################################################

    def ADC_3_Init(self):
        buf = self.compile_packet([0x00, 0x61])

        self.mcp2221a.write(buf)
        rbuf = self.mcp2221a.read(PACKET_SIZE)

        buf = self.compile_packet([0x00, 0x60])
        buf[2 + 1] = rbuf[5]  # Clock Output Divider value
        buf[3 + 1] = rbuf[6]  # DAC Voltage Reference
        buf[4 + 1] = 0x00  # Set DAC output value
        buf[5 + 1] = rbuf[7]  # ADC Voltage Reference
        buf[6 + 1] = 0x00  # Setup the interrupt detection mechanism and clear the detection flag
        buf[7 + 1] = 0x80  # Alter GPIO configuration: alters the current GP designation
        #   datasheet says this should be 1, but should actually be 0x80
        buf[8 + 1] = rbuf[22]  # GP0 settings
        buf[9 + 1] = rbuf[23]  # GP1 settings
        buf[10 + 1] = rbuf[24]  # GP2 settings
        buf[11 + 1] = 0x02  # GP3 settings
        self.mcp2221a.write(buf)
        buf = self.mcp2221a.read(PACKET_SIZE)

    #######################################################################
    # ADC Deta Get
    #######################################################################

    def ADC_DataRead(self):
        buf = self.compile_packet([0x00, 0x10])
        self.mcp2221a.write(buf)

        buf = self.mcp2221a.read(PACKET_SIZE)
        # for i in range(len(buf)):
        #    print ("[%d]: 0x{:02x}".format(buf[i]) % (i))
        self.ADC_1_data = buf[50] | (buf[51] << 8)  # ADC Data (16-bit) values
        self.ADC_2_data = buf[52] | (buf[53] << 8)  # ADC Data (16-bit) values
        self.ADC_3_data = buf[54] | (buf[55] << 8)  # ADC Data (16-bit) values

    #######################################################################
    # DAC 1
    #######################################################################
    def DAC_1_Init(self):
        buf = self.compile_packet([0x00, 0x61])
        self.mcp2221a.write(buf)

        rbuf = self.mcp2221a.read(PACKET_SIZE)

        buf = self.compile_packet([0x00, 0x60])
        buf[2 + 1] = rbuf[5]  # Clock Output Divider value
        buf[3 + 1] = 0x00  # DAC Voltage Reference
        buf[4 + 1] = 0x00  # Set DAC output value
        buf[5 + 1] = rbuf[7]  # ADC Voltage Reference
        buf[6 + 1] = 0x00  # Setup the interrupt detection mechanism and clear the detection flag
        buf[7 + 1] = 0xFF  # Alter GPIO configuration: alters the current GP designation
        #   datasheet says this should be 1, but should actually be 0x80
        buf[8 + 1] = rbuf[22]  # GP0 settings
        buf[9 + 1] = rbuf[23]  # GP1 settings
        buf[10 + 1] = 0x03  # GP2 settings
        buf[11 + 1] = rbuf[25]  # GP3 settings
        self.mcp2221a.write(buf)
        buf = self.mcp2221a.read(PACKET_SIZE)

    #######################################################################
    # DAC 2
    #######################################################################

    def DAC_2_Init(self):
        buf = self.compile_packet([0x00, 0x61])
        self.mcp2221a.write(buf)

        rbuf = self.mcp2221a.read(PACKET_SIZE)

        buf = self.compile_packet([0x00, 0x60])
        buf[2 + 1] = rbuf[5]  # Clock Output Divider value
        buf[3 + 1] = 0x00  # DAC Voltage Reference
        buf[4 + 1] = 0x00  # Set DAC output value
        buf[5 + 1] = rbuf[7]  # ADC Voltage Reference
        buf[6 + 1] = 0x00  # Setup the interrupt detection mechanism and clear the detection flag
        buf[7 + 1] = 0xFF  # Alter GPIO configuration: alters the current GP designation
        #   datasheet says this should be 1, but should actually be 0x80
        buf[8 + 1] = rbuf[22]  # GP0 settings
        buf[9 + 1] = rbuf[23]  # GP1 settings
        buf[10 + 1] = rbuf[24]  # GP2 settings
        buf[11 + 1] = 0x03  # GP3 settings
        self.mcp2221a.write(buf)
        buf = self.mcp2221a.read(PACKET_SIZE)

    #######################################################################
    # DAC Output
    #######################################################################

    def DAC_Datawrite(self, value):
        buf = self.compile_packet([0x00, 0x61])
        self.mcp2221a.write(buf)

        rbuf = self.mcp2221a.read(PACKET_SIZE)

        buf = self.compile_packet([0x00, 0x60])
        buf[2 + 1] = rbuf[5]  # Clock Output Divider value
        buf[3 + 1] = 0x00  # DAC Voltage Reference
        buf[4 + 1] = 0x80 | (0x1F & value)  # Set DAC output value
        buf[5 + 1] = rbuf[7]  # ADC Voltage Reference
        buf[6 + 1] = 0x00  # Setup the interrupt detection mechanism and clear the detection flag
        buf[7 + 1] = 0xFF  # Alter GPIO configuration: alters the current GP designation
        #   datasheet says this should be 1, but should actually be 0x80
        buf[8 + 1] = rbuf[22]  # GP0 settings
        buf[9 + 1] = rbuf[23]  # GP1 settings
        buf[10 + 1] = rbuf[24]  # GP2 settings
        buf[11 + 1] = rbuf[25]  # GP3 settings
        self.mcp2221a.write(buf)
        buf = self.mcp2221a.read(PACKET_SIZE)

    #######################################################################
    # I2C Init
    #######################################################################
    def I2C_Init(self, speed=100000):  # speed = 100000
        self.MCP2221_I2C_SLEEP = float(os.environ.get("MCP2221_I2C_SLEEP", 0))

        buf = self.compile_packet([0x00, 0x10])
        buf[2 + 1] = 0x00  # Cancel current I2C/SMBus transfer (sub-command)
        buf[3 + 1] = 0x20  # Set I2C/SMBus communication speed (sub-command)
        # The I2C/SMBus system clock divider that will be used to establish the communication speed
        buf[4 + 1] = int((12000000 / speed) - 3)
        self.mcp2221a.write(buf)

        rbuf = self.mcp2221a.read(PACKET_SIZE)
        # print("Init")
        if (rbuf[22] == 0):
            raise RuntimeError("SCL is low.")
        if (rbuf[23] == 0):
            raise RuntimeError("SDA is low.")

        # time.sleep(0.001)

    #######################################################################
    # I2C State Check
    #######################################################################
    def I2C_State_Check(self):
        buf = self.compile_packet([0x00, 0x10])
        self.mcp2221a.write(buf)

        rbuf = self.mcp2221a.read(PACKET_SIZE)
        return rbuf[8]

    #######################################################################
    # I2C Cancel
    #######################################################################

    def I2C_Cancel(self):
        buf = self.compile_packet([0x00, 0x10])
        buf[2 + 1] = 0x10  # Cancel current I2C/SMBus transfer (sub-command)
        self.mcp2221a.write(buf)

        self.mcp2221a.read(PACKET_SIZE)
        # time.sleep(0.1)

    #######################################################################
    # I2C Write
    #######################################################################
    def I2C_Write(self, addrs, data):
        """ Writes a block of data with Start and Stop c condition on bus
        :param int addrs: 7-bit I2C slave address
        :param list data: list of int

        Referring to MCP2221A Datasheet(Rev.B 2017), section 3.1.5
        """
        buf = self.compile_packet([0x00, 0x90])
        self._i2c_write(addrs, data, buf)

    def I2C_Write_Repeated(self, addrs, data):
        """ Writes a block of data with Repeated Start and Stop conditions on bus
        :param int addrs: 7-bit I2C slave address
        :param list data: list of int

        Referring to MCP2221A Datasheet(Rev.B 2017), section 3.1.6
        """
        buf = self.compile_packet([0x00, 0x92])
        self._i2c_write(addrs, data, buf)

    def I2C_Write_No_Stop(self, addrs, data):
        """ Writes a block of data with Start condition on bus
        :param int addrs: 7-bit I2C slave address
        :param list data: list of int

        Referring to MCP2221A Datasheet(Rev.B 2017), section 3.1.7
        """
        buf = self.compile_packet([0x00, 0x94])
        self._i2c_write(addrs, data, buf)

    def _i2c_write(self, addrs, data, buf):

        buf[1 + 1] = (len(data) & 0x00FF)  # Cancel current I2C/SMBus transfer (sub-command)
        buf[2 + 1] = (len(data) & 0xFF00) >> 8  # Set I2C/SMBus communication speed (sub-command)
        # The I2C/SMBus system clock divider that will be used to establish the communication speed
        buf[3 + 1] = 0xFF & (addrs << 1)
        for i in range(len(data)):
            # print ("{:d}: 0x{:02x}".format(i,data[i]))
            buf[4 + 1 + i] = data[
                i]  # The I2C/SMBus system clock divider that will be used to establish the communication speed
        self.mcp2221a.write(buf)
        rbuf = self.mcp2221a.read(PACKET_SIZE)
        time.sleep(0.008)

    #######################################################################
    # I2C Read
    #######################################################################
    def I2C_Read(self, addrs, size):
        """ Reads a block of data with Start and Stop conditions on bus
        :param int addrs: 7-bit I2C slave address
        :param int size: size of read out in bytes

        Referring to MCP2221A Datasheet(Rev.B 2017), section 3.1.8
        """
        buf = self.compile_packet([0x00, 0x91])
        return self._i2c_read(addrs, size, buf)

    def I2C_Read_Repeated(self, addrs, size):
        """ Reads a block of data with Repeated Start and Stop conditions on bus
        :param int addrs: 7-bit I2C slave address
        :param int size: size of read out in bytes

        Referring to MCP2221A Datasheet(Rev.B 2017), section 3.1.9
        """
        buf = self.compile_packet([0x00, 0x93])
        return self._i2c_read(addrs, size, buf)

    def _i2c_read(self, addrs, size, buf):

        buf[1 + 1] = (size & 0x00FF)  # Read LEN
        buf[2 + 1] = (size & 0xFF00) >> 8  # Read LEN
        buf[3 + 1] = 0xFF & (addrs << 1)  # addrs
        self.mcp2221a.write(buf)
        rbuf = self.mcp2221a.read(PACKET_SIZE)
        if (rbuf[1] != 0x00):
            # print("[0x91:0x{:02x},0x{:02x},0x{:02x}]".format(rbuf[1],rbuf[2],rbuf[3]))
            self.I2C_Cancel()
            self.I2C_Init()
            raise RuntimeError("I2C Read Data Failed: Code " + rbuf[1])
        time.sleep(self.MCP2221_I2C_SLEEP)

        buf = self.compile_packet([0x00, 0x40])
        buf[1 + 1] = 0x00
        buf[2 + 1] = 0x00
        buf[3 + 1] = 0x00
        self.mcp2221a.write(buf)
        rbuf = self.mcp2221a.read(PACKET_SIZE)
        if (rbuf[1] != 0x00):
            # print("[0x40:0x{:02x},0x{:02x},0x{:02x}]".format(rbuf[1],rbuf[2],rbuf[3]))
            self.I2C_Cancel()
            self.I2C_Init()
            print("You can try increasing environment variable MCP2221_I2C_SLEEP")
            raise RuntimeError("I2C Read Data - Get I2C Data Failed: Code " + rbuf[1])
        if (rbuf[2] == 0x00 and rbuf[3] == 0x00):
            self.I2C_Cancel()
            self.I2C_Init()
            return rbuf[4]
        if (rbuf[2] == 0x55 and rbuf[3] == size):
            rdata = [0] * size
            for i in range(size):
                rdata[i] = rbuf[4 + i]
            return rdata

    #######################################################################
    # reset
    #######################################################################
    def Reset(self):
        print("Reset")
        buf = self.compile_packet([0x00, 0x70, 0xAB, 0xCD, 0xEF])

        self.mcp2221a.write(buf)
        time.sleep(1)


from flask import Flask, request
import pyfiglet
import requests
import sys

header = pyfiglet.figlet_format("MESSENGER",font='banner3-D',width=100)

if len(sys.argv) == 2:
    app = Flask(__name__)

    print(header)
    print('Listening on port {})'.format(str(sys.argv[1])))

    @app.route('/', methods=['POST'])
    def chat():
        request_msg = request.get_data(as_text=True)
        print(request_msg)
        return request_msg

    app.run(port=sys.argv[1], host='0.0.0.0', use_reloader=False)
    print('\nGoodbye')

elif len(sys.argv) == 3:
    try:
        print(header)
        username = input("Enter username:")
        print('Press CTRL + C to exit')
        while True:
            msg = input('Message: \n')
            r = requests.post(url='http://%s:%s/' % (sys.argv[1], sys.argv[2]), data='[%s] - %s\n' % (username, msg))
    except requests.exceptions.ConnectionError as e:
        print('Server unavaliable')
        print(e)
    except KeyboardInterrupt:
        print('\nGoodbye!')
        sys.exit()
    except Exception as e:
        print('Something is wrong')
        print('Details: {}'.format(e))


import numpy as np
from mteb import MTEB
from sentence_transformers import SentenceTransformer
import os
import ctypes
from typing import Union, List
import sys

os.chdir(os.path.dirname(__file__))

MODEL_NAME = 'all-MiniLM-L6-v2'
if len(sys.argv) > 1:
    MODEL_NAME = sys.argv[1]

HF_PREFIX = ''
if 'all-MiniLM' in MODEL_NAME:
    HF_PREFIX = 'sentence-transformers/'
N_THREADS = 6

modes = ['q4_0', 'q4_1', 'f32', 'f16', 'sbert', 'sbert-batchless']

TASKS = [
    "STSBenchmark",
    "EmotionClassification",
]

os.environ["TOKENIZERS_PARALLELISM"] = "false" # Get rid of the warning spam from sbert tokenizer

class BertModel:
    def __init__(self, fname):
        self.lib = ctypes.cdll.LoadLibrary("../build/libbert.so")

        self.lib.bert_load_from_file.restype = ctypes.c_void_p
        self.lib.bert_load_from_file.argtypes = [ctypes.c_char_p]

        self.lib.bert_n_embd.restype = ctypes.c_int32
        self.lib.bert_n_embd.argtypes = [ctypes.c_void_p]

        self.lib.bert_free.argtypes = [ctypes.c_void_p]

        self.lib.bert_encode_batch.argtypes = [
            ctypes.c_void_p,
            ctypes.c_int32,
            ctypes.c_int32,
            ctypes.c_int32,
            ctypes.POINTER(ctypes.c_char_p),
            ctypes.POINTER(ctypes.POINTER(ctypes.c_float)),
        ]

        self.ctx = self.lib.bert_load_from_file(fname.encode("utf-8"))
        self.n_embd = self.lib.bert_n_embd(self.ctx)

    def __del__(self):
        self.lib.bert_free(self.ctx)

    def encode(self, sentences: Union[str, List[str]], batch_size: int = 16) -> np.ndarray:
        if isinstance(sentences, str):
            sentences = [sentences]

        n = len(sentences)

        embeddings = np.zeros((n, self.n_embd), dtype=np.float32)
        embeddings_pointers = (ctypes.POINTER(ctypes.c_float) * len(embeddings))(*[e.ctypes.data_as(ctypes.POINTER(ctypes.c_float)) for e in embeddings])

        texts = (ctypes.c_char_p * n)()
        for j, sentence in enumerate(sentences):
            texts[j] = sentence.encode("utf-8")

        self.lib.bert_encode_batch(
            self.ctx, N_THREADS, batch_size, len(sentences), texts, embeddings_pointers
        )

        return embeddings

class BatchlessModel():
    def __init__(self, model) -> None:
        self.model = model

    def encode(self, sentences, batch_size=32, **kwargs):
        return self.model.encode(sentences, batch_size=1, **kwargs)

for mode in modes:
    if mode == 'sbert':
        model = SentenceTransformer(f"{HF_PREFIX}{MODEL_NAME}")
    elif mode == 'sbert-batchless':
        model = BatchlessModel(SentenceTransformer(f"{HF_PREFIX}{MODEL_NAME}"))
    else:
        model = BertModel(f'../models/{MODEL_NAME}/ggml-model-{mode}.bin')

    evaluation = MTEB(tasks=TASKS)
    output_folder = f"results/{MODEL_NAME}_{mode}"

    evaluation.run(model, output_folder=output_folder, eval_splits=["test"], task_langs=["en"])


import gc
import glob
import os
import random
import sys

import numpy as np

import pcl

import config
from utils.reader import Reader

def augment(xyzs):
    axyz = np.ones((len(xyzs), 4))
    axyz[:, :3] = xyzs
    return axyz

def estimate(xyzs):
    return np.linalg.svd(xyzs)[-1][-1, :]

def run_ransac(data, sample_size, goal_inliers, max_iterations,
               stop_at_goal=True, random_seed=None, thresh=0.05):
    data = augment(data)

    best_ic = 0
    best_model = None
    if random_seed:
        random.seed(random_seed)

    idx = list(range(data.shape[0]))
    for i in range(max_iterations):
        s = data[random.sample(idx, sample_size)]
        m = estimate(s)
        ic = np.count_nonzero(np.abs(m.dot(data.T)) < thresh)
        if ic > best_ic:
            best_ic = ic
            best_model = m
            if stop_at_goal and ic > goal_inliers:
                break

    return best_model, best_ic

def calculate_ransac(name):
    print("calculating ransac planes for", name)
    reader = Reader(name, color=False, infra=False, coords=True)

    good_idx = np.zeros(shape=(reader.coords.shape[0], reader.coords.shape[1]), dtype=np.bool)
    planes = np.ndarray(shape=(reader.coords.shape[0], 4), dtype=np.float32)

    for i in range(reader.coords.shape[0]):
        coords = reader.coords_not_nan(i)
        p = pcl.PointCloud(coords)
        seg = config.make_segmenter(p)
        indices, model = seg.segment()

        del p
        gc.collect()
        sys.stdout.write(".")
        sys.stdout.flush()

        good_idx[i, indices] = True
        planes[i, :] = model

        # DEBUG: show segmented cloud
        if config.debug_step4:
            from utils.pcl import draw_pointcloud, color_inlier
            draw_pointcloud(coords, colors=color_inlier(coords, indices), plane=model)

    print(" done.")
    np.save(reader.path("good_idx", ext="npy"), good_idx, allow_pickle=False)
    np.save(reader.path("planes", ext="npy"), planes, allow_pickle=False)

def calculate_all_ransac():
    folders = glob.glob(os.path.join(config.data_directory, "**/coords.npy"))
    for folder in folders:
        dir = os.path.dirname(folder)
        if os.path.exists(dir + "/planes.npy"):
            continue

        calculate_ransac(dir)

if __name__ == "__main__":
    calculate_all_ransac()


#SVM
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

#importing the datasetset
dataset = pd.read_csv('Position_Salaries.csv')
x = dataset.iloc[:,1:2].values.reshape(-1,1)
y = dataset.iloc[:,2].values.reshape(-1,1)

#the svr class does not have feature scaling
# feature scaling
from sklearn.preprocessing import StandardScaler
sc_x = StandardScaler()
sc_y = StandardScaler()
x = sc_x.fit_transform(x)
y = sc_y.fit_transform(y)

#fitting  regression model to thr data set
#here we will create future non regression model

from sklearn.svm import SVR
regressor =SVR(kernel = 'rbf')
regressor.fit(x,y)

#predicting a new result

y_pred = sc_y.inverse_transform(regressor.predict(sc_x.transform(np.array([[6.5]]))))

#visualizing the   Regression model
plt.scatter(x,y,color = 'red')
plt.plot(x,regressor.predict(x),color = 'blue')
plt.title('truth or bluff ( SVR)')
plt.xlabel('Position level')
plt.ylabel('salary')
plt.show()

#visualizing the SVR for heigher resolution and smoother curve
x_grid = np.arange(min(x),max(x),0.1)# this will aslo predict 90  imaginary level
 #this will gives us vector and we need matrix so so we have to use reahpe function
x_grid = x_grid.reshape((len(x_grid),1))
plt.scatter(x,y,color = 'red')
plt.plot(x,regressor.predict(x),color = 'blue')
plt.title('truth or bluff ( SVR)')
plt.xlabel('Position level')
plt.ylabel('salary')
plt.show()


import pygame
from src.persistence import Persistence
from src.button import Button, MenuButton
from src.game import Game
from src.contextmenu import Context
from src.soldier import *
from src.tower import *
from src.core import *
from src.tile import *
from src.tileview import *
import os

pygame.init()

SCREEN_WIDTH = 1248  # 1280
SCREEN_HEIGHT = 720

screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('Castle Royale')

simulation_starting_time = 0  # 1 second = 1000 millisecond
clock = pygame.time.Clock()
FPS = 60

hamburger = Context()

# 1 - Menu
# 2 - New Game
# 3 - Load Game
# 4 - In Game

game_state = 1

in_game_menu = ["MAIN MENU", "BUILD", "TRAIN", "MOVE", "CONTINUE"]

main_menu_scale = 5
# MENU ASSETS
menu_images = {
    "BOTTOM": pygame.image.load("assets/menu_assets/also_tabla.png"),
    "MIDDLE": pygame.image.load("assets/menu_assets/koztes_tabla.png"),
    "LOGO": pygame.image.load("assets/menu_assets/logo_tabla.png"),
    "BG": pygame.image.load("assets/menu_assets/menu_bg.png")
}
menu_images["LOGO"] = pygame.transform.scale(menu_images["LOGO"], (
menu_images["LOGO"].get_width() * main_menu_scale, menu_images["LOGO"].get_height() * main_menu_scale))

main_menu = [(1, "NEW GAME"), (4, "SAVE"), (3, "LOAD"), (2, "QUIT")]
main_menu_btn = []
menu_top_padding = 0
for i, elem in enumerate(main_menu):
    if (len(main_menu) - 1) == i:
        img = menu_images['BOTTOM']
    else:
        img = menu_images['MIDDLE']

    padding = (i * (menu_images['MIDDLE'].get_height() * main_menu_scale))

    main_menu_btn.append(MenuButton(SCREEN_WIDTH / 2 - img.get_width() * main_menu_scale / 2,
                                    menu_top_padding + menu_images["LOGO"].get_height() + padding,
                                    img.get_width() * main_menu_scale, img.get_height() * main_menu_scale, elem[1],
                                    (len(main_menu) - 1) == i))

btn_quit = Button((255, 0, 0), 18, 676, 228, 40, "MAIN MENU")
btn_build = Button((255, 0, 0), 264, 676, 228, 40, "BUILD")
btn_train = Button((255, 0, 0), 510, 676, 228, 40, "TRAIN")
btn_move = Button((255, 0, 0), 756, 676, 228, 40, "MOVE")
btn_continue = Button((255, 0, 0), 1002, 676, 228, 40, "CONTINUE")
btn_end = Button((255, 0, 0), SCREEN_WIDTH / 2 - 40, SCREEN_HEIGHT / 2 - 25, 80, 50, "MENU")

btn_back = Button((255, 0, 0), 18, 676, 228, 40, "MAIN MENU")

game = None
persistence = Persistence()

font = pygame.font.SysFont('comicsans', 20)
font2 = pygame.font.Font(os.path.join("assets", "fonts", 'arcadeclassic.ttf'), 23)
font_game_over = pygame.font.Font(os.path.join("assets", "fonts", 'arcadeclassic.ttf'), 100)
SCALE = 3

gold_coin = pygame.image.load("assets/gold_coin.png")
gold_coin = pygame.transform.scale(gold_coin, (16 * SCALE, 16 * SCALE))

game_icon = pygame.image.load("assets/tile_assets/blue_castle.png")
pygame.display.set_icon(game_icon)

sword = pygame.image.load("assets/sword.png")
sword = pygame.transform.scale(sword, (16 * 2, 16 * 2))

health_bar_left = pygame.image.load("assets/health_bar.png")
health_bar_left = pygame.transform.scale(health_bar_left, (44 * SCALE, 9 * SCALE))

health_bar_inside_left = pygame.image.load("assets/health_bar_inside.png")
health_bar_inside_left = pygame.transform.scale(health_bar_inside_left, (44 * SCALE, 9 * SCALE))

health_bar_inside_original_left = pygame.image.load("assets/health_bar_inside.png")
health_bar_inside_original_left = pygame.transform.scale(health_bar_inside_original_left, (44 * SCALE, 9 * SCALE))

health_bar_right = pygame.image.load("assets/health_bar.png")
health_bar_right = pygame.transform.flip(health_bar_right, True, False)
health_bar_right = pygame.transform.scale(health_bar_right, (44 * SCALE, 9 * SCALE))

health_bar_inside_right = pygame.image.load("assets/health_bar_inside.png")
health_bar_inside_right = pygame.transform.flip(health_bar_inside_right, True, False)
health_bar_inside_right = pygame.transform.scale(health_bar_inside_right, (44 * SCALE, 9 * SCALE))

health_bar_inside_original_right = pygame.image.load("assets/health_bar_inside.png")
health_bar_inside_original_right = pygame.transform.flip(health_bar_inside_original_right, True, False)
health_bar_inside_original_right = pygame.transform.scale(health_bar_inside_original_right, (44 * SCALE, 9 * SCALE))

buttons_background = pygame.image.load("assets/in_game_button_assets/button_background.png")
lock = pygame.image.load("assets/lock.png")
lock = pygame.transform.scale(lock, (16 * 2, 16 * 2))
lock2 = pygame.image.load("assets/lock.png")
lock2 = pygame.transform.scale(lock, (16 * 3, 16 * 3))

# Change name color based on round
name_color = (0, 0, 0)
name_color_now_playing = (255, 0, 0)

tile_view = []

load_buttons = []
def create_buttons(num_buttons):
    global load_buttons
    load_buttons = []
    for i in range(num_buttons):
        load_buttons.append(Button((255, 0, 0), (i * 228) + ((i+1) * 18), 18, 228, 40, "MAP {}".format(i)))

def fill(surface, original_surface, hue):
    if hue < 0:
        hue = 0
    w, h = surface.get_size()
    for x in range(w):
        for y in range(h):
            a = surface.get_at((x, y))[3]
            c = original_surface.get_at((x, y))
            c.hsla = (c.hsla[0] + hue, c.hsla[1], c.hsla[2], c.hsla[3])
            surface.set_at((x, y), pygame.Color(c.r, c.g, c.b, a))

def get_name_color(player):
    if game.current_player == player:
        return name_color_now_playing
    return name_color

def translate(value, left_min, left_max, right_min, right_max):
    left_span = left_max - left_min
    right_span = right_max - right_min

    value_scaled = float(value - left_min) / float(left_span)

    return right_min + (value_scaled * right_span)

def update_tile_view(map):
    if(tile_view == []):
        for i in range(0, 14):
            tile_view.append([])
            for j in range(0, 26):
                tile_view[i].append(TileView(game, i, j))
                tile_view[i][j]._tile = map[i][j]
    else:
        for i in range(0, 14):
            for j in range(0, 26):
                tile_view[i][j]._tile = map[i][j]

run = True
while run:
    clock.tick(FPS)
    # Background color for testing
    screen.fill((247, 217, 181))
    # Draw update function
    if game_state == 1:

        screen.blit(menu_images["BG"], [0, 0, SCREEN_WIDTH, SCREEN_HEIGHT])

        screen.blit(menu_images["LOGO"], [SCREEN_WIDTH / 2 - img.get_width() * main_menu_scale / 2, menu_top_padding,
                                          menu_images["LOGO"].get_width(), menu_images["LOGO"].get_height()])

        for elem in main_menu_btn:
            elem.draw(screen)

        if game is None:
            screen.blit(lock2, [410, 320, lock.get_width(), lock.get_height()])
        # draw
    elif game_state == 2:
        screen.blit(menu_images["BG"], [0, 0, SCREEN_WIDTH, SCREEN_HEIGHT])

        if game.winner:
            game_over_title = font_game_over.render("{} WINS".format(game.winner.name), True, (255, 215, 166))
            game_over_title_outlines = font_game_over.render("{} WINS".format(game.winner.name), True, (39, 28, 57))

            screen.blit(game_over_title_outlines, ((SCREEN_WIDTH / 2 - game_over_title.get_width() / 2) - 4,
                                                   (SCREEN_HEIGHT / 2 - game_over_title.get_height() / 2) + 4))
            screen.blit(game_over_title, (
            SCREEN_WIDTH / 2 - game_over_title.get_width() / 2, SCREEN_HEIGHT / 2 - game_over_title.get_height() / 2))

        btn_back.draw(screen)
        btn_back.is_over(pygame.mouse.get_pos())
        # draw
    elif game_state == 3:
        pass
    elif game_state == 5:
        screen.blit(menu_images["BG"], [0, 0, SCREEN_WIDTH, SCREEN_HEIGHT])

        for i in load_buttons:
            i.draw(screen)
            i.is_over(pygame.mouse.get_pos())

        btn_back.draw(screen)
        btn_back.is_over(pygame.mouse.get_pos())

        # draw
    elif game_state == 4:
        # Draw Tiles

        screen.blit(buttons_background, [0, 672, SCREEN_WIDTH, 200])

        if not game.is_ended:
            update_tile_view(game._map)
            for i in range(0, 14):
                for j in range(0, 26):
                    tile_view[i][j].draw(screen)
            for i in range(0, 14):
                for j in range(0, 26):
                    tile_view[i][j].draw_buildings_and_soldiers(screen)
            for i in range(0, 14):
                for j in range(0, 26):
                    tile_view[i][j].draw_context_menu_for_tiles(screen)
        else:
            text = pygame.font.SysFont('Arial', 25).render("The winner is {0}.".format(game.winner), False, (0, 0, 0))
            screen.blit(text, (SCREEN_WIDTH / 2 - text.get_width() / 2, SCREEN_HEIGHT / 2 - 60))
            btn_end.draw(screen)

        # Draw Player Information
        if not game.is_ended:
            p1_name = str(game.player_1.name)
            p2_name = str(game.player_2.name)

            player1_name = font2.render(p1_name, True, (255, 255, 255))
            player1_name_outlines = font2.render(p1_name, True, (39, 28, 57))
            player1_money = font2.render(str(game.player_1.gold), True, pygame.Color(39, 28, 57))
            player1_money_outline = font2.render(str(game.player_1.gold), True, pygame.Color(255, 206, 73))

            hud_pos_x = 10
            hud_pos_y = 70

            player1_hp = game.player_1.castle_tile.units[0].health
            fill(health_bar_inside_left, health_bar_inside_original_left, math.floor(player1_hp / 10))

            screen.blit(player1_name_outlines, (30, 15, 200, 200))
            screen.blit(player1_name, (30 + 2, 15 - 2, 200, 200))

            player1_display_hp = translate(player1_hp, 0, 1000, 160, 1000)
            screen.blit(health_bar_left, (20, 45, 200, 200))
            screen.blit(health_bar_inside_left, (20, 45, 200, 200),
                        (0, 0, (health_bar_inside_left.get_width() * player1_display_hp) / 1000, 200))

            screen.blit(gold_coin, (hud_pos_x, hud_pos_y))
            screen.blit(player1_money, (-5 + hud_pos_x + gold_coin.get_width(),
                                        hud_pos_y + (gold_coin.get_height() / 2 - player1_money.get_height() / 2)))
            screen.blit(player1_money_outline, (-5 + 3 + hud_pos_x + gold_coin.get_width(), hud_pos_y + (
                        gold_coin.get_height() / 2 - player1_money_outline.get_height() / 2) - 1))

            player2_name = font2.render(p2_name, True, (255, 255, 255))
            player2_name_outlines = font2.render(p2_name, True, (39, 28, 57))
            player2_money = font2.render(str(game.player_2.gold), True, pygame.Color(39, 28, 57))
            player2_money_outline = font2.render(str(game.player_2.gold), True, pygame.Color(255, 206, 73))

            if not game.start_simulation:
                if game.current_player == game.player_1:
                    screen.blit(sword, (30 + player1_name.get_width(), 8))
                else:
                    screen.blit(pygame.transform.flip(sword, flip_x=True, flip_y=False),
                                (SCREEN_WIDTH - 30 - sword.get_width() - player2_name.get_width(), 8))

            player2_hp = game.player_2.castle_tile.units[0].health
            fill(health_bar_inside_right, health_bar_inside_original_right, math.floor(player2_hp / 10))
            screen.blit(health_bar_right, (SCREEN_WIDTH - 20 - health_bar_right.get_width(), 45, 200, 200))

            player2_display_hp = translate(player2_hp, 0, 1000, 160, 1000)
            screen.blit(health_bar_inside_right, (SCREEN_WIDTH - 20 - health_bar_inside_right.get_width() + (
                        health_bar_inside_right.get_width() - (
                            (health_bar_inside_right.get_width() * player2_display_hp) / 1000)), 45, 200, 200), (
                        health_bar_inside_right.get_width() - (
                                    (health_bar_inside_right.get_width() * player2_display_hp) / 1000), 0,
                        health_bar_inside_right.get_width(), 200))

            screen.blit(player2_name_outlines, (SCREEN_WIDTH - 30 - player2_name_outlines.get_width(), 15, 200, 200))
            screen.blit(player2_name, (SCREEN_WIDTH - 30 - player2_name_outlines.get_width() + 2, 15 - 2, 200, 200))

            screen.blit(gold_coin, (SCREEN_WIDTH - gold_coin.get_width() - hud_pos_x, hud_pos_y))
            screen.blit(player2_money, (
            5 + SCREEN_WIDTH - gold_coin.get_width() - hud_pos_x - player2_money.get_width(),
            hud_pos_y + (gold_coin.get_height() / 2 - player2_money.get_height() / 2)))
            screen.blit(player2_money_outline, (
            5 + 3 + SCREEN_WIDTH - gold_coin.get_width() - hud_pos_x - player2_money_outline.get_width(),
            hud_pos_y + (gold_coin.get_height() / 2 - player2_money_outline.get_height() / 2) - 1))

            if not game.start_simulation:
                current_player_state = font2.render(str(game.current_player.state), True, (255, 255, 255))
                current_player_state_outline = font2.render(str(game.current_player.state), True, (39, 28, 57))
            else:
                current_player_state = font2.render("Simulation", True, (255, 255, 255))
                current_player_state_outline = font2.render("Simulation", True, (39, 28, 57))

            screen.blit(current_player_state_outline,
                        ((SCREEN_WIDTH / 2) - 2 - (current_player_state.get_width() / 2), 10 + 2))
            screen.blit(current_player_state, ((SCREEN_WIDTH / 2) - (current_player_state.get_width() / 2), 10))

            if game_state == 4 and game.winner:
                game_state = 2

        if not game.start_simulation:
            if not hamburger.opened:
                btn_quit.is_over(pygame.mouse.get_pos())
                btn_build.is_over(pygame.mouse.get_pos())
                btn_train.is_over(pygame.mouse.get_pos())
                btn_move.is_over(pygame.mouse.get_pos())
                btn_continue.is_over(pygame.mouse.get_pos())
                btn_end.is_over(pygame.mouse.get_pos())

        if not game.is_ended:
            btn_quit.draw(screen)
            btn_build.draw(screen)
            btn_train.draw(screen)
            btn_move.draw(screen)
            btn_continue.draw(screen)

        if game.start_simulation:
            screen.blit(lock, [17, 682, lock.get_width(), lock.get_height()])
            screen.blit(lock, [263, 682, lock.get_width(), lock.get_height()])
            screen.blit(lock, [509, 682, lock.get_width(), lock.get_height()])
            screen.blit(lock, [755, 682, lock.get_width(), lock.get_height()])
            screen.blit(lock, [1001, 682, lock.get_width(), lock.get_height()])
        # Draw Context Menu
        hamburger.draw(screen)
        hamburger.is_over(pygame.mouse.get_pos())

        if game.start_simulation:
            game.simulate()

    # Keyboard input update function
    for event in pygame.event.get():
        if game_state == 1:
            if event.type == pygame.MOUSEBUTTONUP:
                for i, btn in enumerate(main_menu_btn):
                    if btn.is_over(pygame.mouse.get_pos()):
                        if main_menu[i][0] == 1:
                            game = Game()
                            game.new_game(1000, "Player1", "Player2")
                            game_state = 4
                            tile_view = []
                        elif main_menu[i][0] == 2:
                            run = False
                        elif main_menu[i][0] == 3:
                            num_saves = persistence.get_num_saves()
                            create_buttons(num_saves)
                            game_state = 5
                        elif main_menu[i][0] == 4:
                            persistence.save(game)
                            game = None

        elif game_state == 2:
            if event.type == pygame.MOUSEBUTTONUP and (not game or not game.start_simulation):
                if btn_back.is_over(pygame.mouse.get_pos()):
                    game_state = 1

        elif game_state == 5:
            if event.type == pygame.MOUSEBUTTONUP and (not game or not game.start_simulation):
                if btn_back.is_over(pygame.mouse.get_pos()):
                    game_state = 1
                for index, btn in enumerate(load_buttons):
                    if btn.is_over(pygame.mouse.get_pos()):
                        load = persistence.load(index)
                        if load:
                            game = load
                            tile_view = []
                        game_state = 4

        elif game_state == 3:
            pass
            # keyboard input
        elif game_state == 4:
            if not game.start_simulation:
                if hamburger.opened:
                    if event.type == pygame.MOUSEBUTTONUP:
                        content = hamburger.is_over(pygame.mouse.get_pos())
                        for item in content:
                            if item[2] and item[1] == "Tower":
                                game.current_tile.build(game.current_player, "BasicTower")
                            if item[2] and item[1] == "Slow":
                                game.current_tile.build(game.current_player, "Slow")
                            if item[2] and item[1] == "Splash":
                                game.current_tile.build(game.current_player, "Splash")
                            if item[2] and item[1] == "Barracks":
                                print("barracks")
                            if item[2] and item[1] == "Upgrade":
                                game.current_tile.upgrade_tower()
                            if item[2] and item[1] == "Demolish":
                                game.current_tile.demolish_tower()
                            if item[2] and item[1] == "Remove":
                                game.current_tile.remove_tower_ruin()
                            if item[2] and item[1] == "Soldier":
                                game.current_player.castle_tile.train(game.current_player, "BasicSoldier")
                            if item[2] and item[1] == "Climber":
                                game.current_player.castle_tile.train(game.current_player, "Climber")
                            if item[2] and item[1] == "Suicide":
                                game.current_player.castle_tile.train(game.current_player, "Suicide")
                            if item[2] and item[1] == "Tank":
                                game.current_player.castle_tile.train(game.current_player, "Tank")
                            if item[2] and item[1] == "Select":
                                game.select_current_tile()
                            if item[2] and item[1] == "Waypoint":
                                game.add_waypoint()
                            if item[2] and item[1] == "Reset":
                                game.reset_waypoint()
                            hamburger.opened = False
                else:
                    for row in game.map:
                        for tile in row:
                            if tile.is_over(pygame.mouse.get_pos()) and event.type == pygame.MOUSEBUTTONUP:
                                if game.current_player.state == "BUILD":
                                    mouse_cords = pygame.mouse.get_pos()
                                    if tile.has_building and issubclass(type(tile.units[0]), Tower) and not tile.units[
                                        0].is_in_ruins:
                                        hamburger.change_content(["Upgrade", "Demolish"])
                                    elif tile.has_building and issubclass(type(tile.units[0]), Tower) and tile.units[
                                        0].is_in_ruins:
                                        hamburger.change_content(["Remove"])
                                    else:
                                        hamburger.change_content(["Tower", "Slow", "Splash"])
                                    hamburger.open(mouse_cords[0], mouse_cords[1])

                                elif game.current_player.state == "TRAIN":
                                    mouse_cords = pygame.mouse.get_pos()
                                    hamburger.change_content(["Soldier", "Climber", "Suicide", "Tank"])
                                    hamburger.open(mouse_cords[0], mouse_cords[1])

                                elif game.current_player.state == "MOVE":
                                    mouse_cords = pygame.mouse.get_pos()
                                    options = []
                                    if tile_can_be_selected(tile):
                                        options.append("Select")

                                    if game.selected_tile and tile_can_be_added_as_waypoint(tile, game.selected_tile):
                                        options.append("Waypoint")

                                    if game.selected_tile:
                                        options.append("Reset")
                                    hamburger.change_content(options)
                                    if len(options) > 0:
                                        hamburger.open(mouse_cords[0], mouse_cords[1])
                                game.current_tile = tile
                    if event.type == pygame.MOUSEBUTTONUP and not game.start_simulation:
                        if btn_continue.is_over(pygame.mouse.get_pos()):
                            btn_continue.is_over((0, 0))
                            game.next_round()
                            for row in game.map:
                                for tile in row:
                                    tile.selected = False
                                    tile.waypoint = False
                            if game.start_simulation:
                                simulation_starting_time = pygame.time.get_ticks()
                        elif btn_quit.is_over(pygame.mouse.get_pos()):
                            game_state = 1
                        elif btn_build.is_over(pygame.mouse.get_pos()):
                            game.current_player.state = "BUILD"
                        elif btn_train.is_over(pygame.mouse.get_pos()):
                            game.current_player.state = "TRAIN"
                        elif btn_move.is_over(pygame.mouse.get_pos()):
                            game.current_player.state = "MOVE"
                        elif btn_end.is_over(pygame.mouse.get_pos()):
                            pass
        if event.type == pygame.QUIT:
            run = False

    pygame.display.update()

pygame.quit()


#!/usr/bin/env python
# -*- coding: utf-8 -*-

# from __future__ import ( division, absolute_import, print_function, unicode_literals )

import sys
import os
import argparse
from termcolor import colored
import json
from json import encoder

if sys.version_info >= (3,):
    import urllib.request as urllib2
    import urllib.parse as urlparse
else:
    import urllib2
    import urlparse

global gSettings

def treatCmdOpts(argv):
    """
    Treats the command line options

    :param argv: the options
    :type argv: list of string

    url = "ftp://cddis.gsfc.nasa.gov/pub/gps/data/daily/2018/318/18d/CORD00ARG_R_20183180000_01D_30S_MO.crx.gz"

    """
    # print('argv (treat daily-duty) = %s' % argv)
    global cBaseName  # colored version
    baseName = os.path.basename(__file__)
    cBaseName = colored(baseName, 'yellow')

    helpTxt = baseName + ' downloads files according to specified protocol to location. Example: url = ftp://cddis.gsfc.nasa.gov/pub/gps/data/daily/2018/318/18d/CORD00ARG_R_20183180000_01D_30S_MO.crx.gz'

    # create the parser for command line arguments
    parser = argparse.ArgumentParser(description=helpTxt)

    parser.add_argument('-p', '--protocol', help='Download protocol', required=True, type=str)
    parser.add_argument('-s', '--server', help='IGS', required=True, type=str)
    parser.add_argument('-r', '--dir_remote', help='Remote directory', required=True, type=str)
    parser.add_argument('-f', '--file_remote', help='Remote file', required=True, type=str)
    parser.add_argument('-l', '--dir_local', help='Local directory', required=True, type=str)

    parser.add_argument('-v', '--verbose', help='increase output verbosity (default False)',
                        action='store_true', required=False, default=False)

    # drop argv[0]
    args = parser.parse_args(argv)

    # return arguments
    return args.protocol, args.server, args.dir_remote, args.file_remote, args.dir_local, args.verbose

def download_file(url, proxy, dest=None, verbose=False):
    """
    Download and save a file specified by url to dest directory,
    """
    proxies = {"http":"http://%s" % proxy}
    proxy_support = urllib2.ProxyHandler(proxies)
    opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler(debuglevel=1))
    urllib2.install_opener(opener)

    req = urllib2.Request(url)
    req.add_unredirected_header('User-Agent', 'Mozilla/5.0')
    u = urllib2.urlopen(req)

    scheme, netloc, path, query, fragment = urlparse.urlsplit(url)
    filename = os.path.basename(path)
    if not filename:
        filename = 'downloaded.file'
    if dest:
        filename = os.path.join(dest, filename)

    with open(filename, 'wb') as f:
        meta = u.info()
        meta_func = meta.getheaders if hasattr(meta, 'getheaders') else meta.get_all
        meta_length = meta_func("Content-Length")
        file_size = None
        if meta_length:
            file_size = int(meta_length[0])

        if verbose:
            print("... Downloading: {0} (Bytes: {1})".format(url, file_size))

        file_size_dl = 0
        block_sz = 8192
        while True:
            buffer = u.read(block_sz)
            if not buffer:
                break

            file_size_dl += len(buffer)
            f.write(buffer)

            status = "{0:16}".format(file_size_dl)
            if file_size:
                status += "   [{0:6.2f}%]".format(file_size_dl * 100 / file_size)
            status += chr(13)
            if verbose:
                print(status, end="")

        if verbose:
            print()

    return filename

def main(argv):
    """
    ``download_file`` downloads a file from a server according to an Internet Protocol
    """

    # limit float precision
    encoder.FLOAT_REPR = lambda o: format(o, '.3f')
    cFuncName = colored(sys._getframe().f_code.co_name, 'green')

    # treat command line options
    protocol, server, dir_remote, filename, dir_local, verbose = treatCmdOpts(argv)

    # store in dictionary
    gSettings = {}
    # settings of remote file
    gSettings['remote'] = {}
    gSettings['remote']['protocol'] = protocol
    gSettings['remote']['IGS'] = server
    gSettings['remote']['dir_remote'] = dir_remote
    gSettings['remote']['file_remote'] = filename
    # settings of local file
    gSettings['local'] = {}
    gSettings['local']['dir_local'] = dir_local

    gSettings['proxy'] = {}
    gSettings['proxy']['http'] = os.environ.get("http_proxy")
    gSettings['proxy']['https'] = os.environ.get("https_proxy")

    # create download url
    gSettings['remote']['url'] = gSettings['remote']['protocol'] + '://' + gSettings['remote']['IGS'] + os .path.join(gSettings['remote']['dir_remote'], gSettings['remote']['file_remote'])

    if verbose:
        print('%s:\n... %s:' % (cBaseName, colored('global Settings', 'green')))
        print(json.dumps(gSettings, sort_keys=True, indent=4))

    # download the url
    gSettings['local']['filename'] = download_file(url=gSettings['remote']['url'], dest=gSettings['local']['dir_local'], proxy=gSettings['proxy']['http'], verbose=verbose)

    # inform the user and save the json file'
    if verbose:
        print('%s: %s\n... %s:' % (cBaseName, cFuncName, colored('global Settings', 'green')))
        print(json.dumps(gSettings, sort_keys=True, indent=4))

    # # url = "http://download.thinkbroadband.com/10MB.zip"
    # url = "ftp://cddis.gsfc.nasa.gov/pub/gps/data/daily/2018/318/18d/CORD00ARG_R_20183180000_01D_30S_MO.crx.gz"
    # filename = download_file(url)
    # print(filename)

    # url = "ftp://cddis.gsfc.nasa.gov/pub/gps/data/daily/2018/200/18d/cord2000.18d.Z"
    # filename = download_file(url)
    # print(filename)

    # url = "ftp://cddis.gsfc.nasa.gov/pub/gps/products/2027/igr20270.sp3.Z"
    # filename = download_file(url)
    # print(filename)

    # url = "ftp://cddis.gsfc.nasa.gov/pub/gps/data/daily/2018/318/18n/brdc3180.18n.Z"
    # filename = download_file(url)
    # print(filename)

    # url = "ftp://cddis.gsfc.nasa.gov/pub/glonass/data/daily/2018/318/18g/brdc3180.18g.Z"
    # filename = download_file(url)
    # print(filename)

    # gunzip -c CORD00ARG_R_20183190000_01D_30S_MO.crx.gz | CRX2RNX - | gfzrnx_lx -kv -fout CORD00ARG_R_20183190000_01D_30S_MO.rnx -f

if __name__ == "__main__":  # Only run if this file is called directly
    main(sys.argv[1:])


# LIBRARIES
import pygame
from queue import LifoQueue, PriorityQueue
import time
import tkinter.filedialog as tkf
import pickle
import random
import preloadedmazes as mazes

###############################################################################################
# INITIAL SETUP
###############################################################################################

#PROGRAM INFORMATION
version = "V5.0"
lastUpdate = "12/6/2022"

#WINDOW DISPLAY
WIDTH = 800
WIN = pygame.display.set_mode((WIDTH, WIDTH))
pygame.display.set_caption("Visual Application of Pathfinding Algorithms")

#COLOR SET
RED = (255, 0, 0)
GREEN = (0, 255, 0)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
PURPLE = (128, 0, 128)
ORANGE = (255, 165 ,0)
GREY = (128, 128, 128)
TURQUOISE = (64, 224, 208)

#DEFINES EACH GRID AND DEFINES STATUS
class Node:
    def __init__(self, row, col, width, total_rows):
        self.row = row
        self.col = col
        self.x = row * width
        self.y = col * width
        self.color = WHITE
        self.neighbors = []
        self.width = width
        self.total_rows = total_rows

    def get_pos(self):
        return self.row, self.col

    def is_closed(self):
        return self.color == RED

    def is_open(self):
        return self.color == GREEN

    def is_barrier(self):
        return self.color == BLACK

    def is_start(self):
        return self.color == ORANGE

    def is_end(self):
        return self.color == TURQUOISE

    def is_path(self):
        return self.color == PURPLE

    def is_opennode(self):
        return self.color == WHITE

    def reset(self):
        self.color = WHITE

    def make_start(self):
        self.color = ORANGE

    def make_closed(self):
        self.color = RED

    def make_open(self):
        self.color = GREEN

    def make_barrier(self):
        self.color = BLACK

    def make_end(self):
        self.color = TURQUOISE

    def make_path(self):
        self.color = PURPLE

    def draw(self, win):
        pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.width))

    #DETERMINES BARRIERS ON A GLOBAL LEVEL BEFORE ALGORITHM STARTS
    def update_neighbors(self, grid):
        self.neighbors = []
        if self.row < self.total_rows - 1 and not grid[self.row + 1][self.col].is_barrier(): #DOWN
            self.neighbors.append(grid[self.row + 1][self.col])

        if self.row > 0 and not grid[self.row - 1][self.col].is_barrier(): #UP
            self.neighbors.append(grid[self.row - 1][self.col])

        if self.col < self.total_rows - 1 and not grid[self.row][self.col + 1].is_barrier(): #RIGHT
            self.neighbors.append(grid[self.row][self.col + 1])

        if self.col > 0 and not grid[self.row][self.col - 1].is_barrier(): #LEFT
            self.neighbors.append(grid[self.row][self.col - 1])

    def __lt__(self, other):
        return False

#FUNCTION TO FIND TAXI-CAB DISTANCE
def h(p1, p2):
    x1, y1 = p1
    x2, y2 = p2
    return abs(x1 - x2) + abs(y1 - y2)

#SHOWS SHORTEST PATH
def reconstruct_path(came_from, current, draw):
    while current in came_from:
        current = came_from[current]
        current.make_path()
        draw()

###############################################################################################
# ALGORITHMS FOR SEACHING
###############################################################################################

#A* ALGORITHM
def astar(draw, grid, start, end):
    count = 0
    open_set = PriorityQueue() #SET THAT RETURNS THE NODE WITH SMALLEST VALUE WHEN CALLED
    open_set.put((0, count, start))
    came_from = {} #RECORDS PATH FROM PREVIOUS NODE
    g_score = {node: float("inf") for row in grid for node in row} #DISTANCE FROM THE START
    g_score[start] = 0
    f_score = {node: float("inf") for row in grid for node in row} #DISTANCE FROM THE END
    f_score[start] = h(start.get_pos(), end.get_pos())
    open_set_hash = {start} #SEARCHABLE QUEUE SINCE PRIORITYQUEUE DOESN'T ALLOW US TO

    while not open_set.empty():
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()

        current = open_set.get()[2]
        open_set_hash.remove(current)

        #SHOWS SHORTEST PATH
        if current == end:
            reconstruct_path(came_from, end, draw)
            end.make_end()
            start.make_start()
            return True

        for neighbor in current.neighbors:
            temp_g_score = g_score[current] + 1 #ONE SPACE AWAY FROM CURRENT NODE
            #REROUTES PATH AND UPDATES VALUE IF CLOSER PATH FOUND
            if temp_g_score < g_score[neighbor]:
                came_from[neighbor] = current
                g_score[neighbor] = temp_g_score
                f_score[neighbor] = temp_g_score + h(neighbor.get_pos(), end.get_pos())
                #OPENS PATH OPTION IN NODE IF IT WAS UNEXPLORED
                if neighbor not in open_set_hash:
                    count += 1
                    open_set.put((f_score[neighbor], count, neighbor))
                    open_set_hash.add(neighbor)
                    neighbor.make_open()
        draw()
        if current != start:
            current.make_closed()

#DIJKSTRA'S ALGORITHM
def dijkstra(draw, grid, start, end):
    count = 0
    open_set = PriorityQueue() #SET THAT RETURNS THE NODE WITH SMALELST VALUE WHEN CALLED
    open_set.put((0, count, start))
    came_from = {} #RECORDS PATH FROM PREVIOUS NODE
    g_score = {node: float("inf") for row in grid for node in row} #DISTANCE FROM THE START
    g_score[start] = 0
    open_set_hash = {start} #SEARCHABLE QUEUE SINCE PRIORITYQUEUE DOESN'T ALLOW US TO

    while not open_set.empty():
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()

        current = open_set.get()[2]
        open_set_hash.remove(current)

        #SHOWS SHORTEST PATH
        if current == end:
            reconstruct_path(came_from, end, draw)
            end.make_end()
            start.make_start()
            return True

        for neighbor in current.neighbors:
            temp_g_score = g_score[current] + 1 #ONE SPACE AWAY FROM CURRENT NODE
            #REROUTES PATH AND UPDATES VALUE IF CLOSER PATH FOUND
            if temp_g_score < g_score[neighbor]:
                came_from[neighbor] = current
                g_score[neighbor] = temp_g_score
                #OPENS PATH OPTION IN NODE IF IT WAS UNEXPLORED
                if neighbor not in open_set_hash:
                    count += 1
                    open_set.put((g_score[neighbor], count, neighbor))
                    open_set_hash.add(neighbor)
                    neighbor.make_open()
        draw()
        if current != start:
            current.make_closed()

#DEPTH FIRST SEARCH ALGORITHM
def dfs(draw, grid, start, end):
    count = 0
    open_set = LifoQueue() #LAST IN FIRST OUT QUEUE TO AGGRESIVELY SEARCH
    open_set.put((count, start))
    came_from = {} #KEEPS TRACK OF WHERE EACH EXPLORED NODE CAME FROM
    open_set_hash = {start} #LIST OF EXPLORED NODES

    while not open_set.empty():
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()

        current = open_set.get()[1]

        #SHOWS FOUND PATH
        if current == end:
            reconstruct_path(came_from, end, draw)
            end.make_end()
            start.make_start()
            return True

        #PUTS EACH AVAILABLE NEIGHBOR OF CURRENT NODE INTO LIFO QUEUE
        for neighbor in current.neighbors:
            if not neighbor in open_set_hash:
                came_from[neighbor] = current
            if neighbor not in open_set_hash:
                    count += 1
                    open_set.put((count, neighbor))
                    open_set_hash.add(neighbor)
                    if neighbor != end:
                        neighbor.make_open()
        draw()
        if current != start:
            current.make_closed()

###############################################################################################
# FUNCTIONS TO USE
###############################################################################################

#MAKES AREA FOR GRID SPACES
def make_grid(rows, width):
    grid = []
    gap = width // rows
    for i in range(rows):
        grid.append([])
        for j in range(rows):
            node = Node(i, j, gap, rows)
            grid[i].append(node)
    return grid

#DRAWS LINES TO VISUALLY DEFINE GRIDS
def draw_grid(win, rows, width):
    gap = width // rows
    for i in range(rows):
        pygame.draw.line(win, GREY, (0, i * gap), (width, i * gap))
    for j in range(rows):
        pygame.draw.line(win, GREY, (j * gap, 0), (j * gap, width))

#FILLS GRID WITH COLOR WHEN CLICKED AND UPDATES ENTIRE SCREEN
def draw(win, grid, rows, width):
    win.fill(WHITE)
    for row in grid:
        for node in row:
            node.draw(win)
    draw_grid(win, rows, width)
    pygame.display.update()

#TAKES PIXEL LOCATION AND DETERMINES GRID LOCATION
def get_clicked_pos(pos, rows, width):
    gap = width // rows
    y, x = pos
    row = y // gap
    col = x // gap
    return row, col

#COUNT PATH LENGTH
def path_length(grid):
    path_count = 0
    for row in grid:
        for node in row:
            if node.is_path():
                path_count += 1
    return path_count

#DETERMINES IF A PATH WAS FOUND
def path_stats(grid, start_time):
    for row in grid:
        for node in row:
            if node.is_path():
                print("--- %.2f seconds and %i path blocks ---" % ((time.time() - start_time), path_length(grid)))
                return
    print("No Path Was Found...")

#SAVES THE MAZE FILE
def save_mazefile(row, grid, node):
    try:
        #PROCESS TO STORE BARRIER LAYOUT IN THE FILE
        mazeLayout = []
        for row in grid:
            for node in row:
                if node.is_barrier():
                    mazeLayout.append("1")
                else:
                    mazeLayout.append("4")

        #Export data to pickle file with user choice of save location
        files = [('Pickle File', '*.pickle')]
        filename = tkf.asksaveasfilename(filetypes = files, defaultextension = files)
        with open(filename, 'wb') as f:
            pickle.dump(mazeLayout, f)
        print("Successfully saved the file.")

    except FileNotFoundError:
        print("Saving file failed. Reason: Aborted save process.")
    except:
        print("Saving file failed.")

#LOADS MAZE ONTO BOARD
def loading_maze(grid, mazeLayout):
    i = 0
    for row in grid:
        for node in row:
            if mazeLayout[i] == '1':
                node.make_barrier()
            else:
                node.reset()
            i+=1

#LOADS A MAZE FROM SELECTED FILE
def load_mazefile(grid):
    try:
        #USING TKINTER TO OPEN INTERFACE TO SELECT FILE
        files = [('Pickle File', '*.pickle')]
        filename = tkf.askopenfilename(filetypes = files, defaultextension = files)
        with open(filename, 'rb') as f:
            mazeLayout = pickle.load(f)

        #PROCESS TO BUILD MAZE BY READING FILE
        loading_maze(grid, mazeLayout)
        print("Successfully opened the maze layout file.")
    except FileNotFoundError:
        print("Opening file failed. Reason: Aborted opening process.")
    except:
        print("Opening file failed.")

# Instructions on use
def say_usermanual():
    print("")
    print("Welcome to the pathfinding algorithm visualizer by Jeffrey Collier!")
    print("---------------------------------------------------------------------")
    print("Current version: %s" % version)
    print("Last updated: %s" % lastUpdate)
    print("---------------------------------------------------------------------")
    print("• Your first left mouse click will place the start node, second click will place the end node, and then any remaining clicks will place walls.")
    print("• Your right mouse click will remove selected node.")
    print("• Keyboard press \"1\" runs the A* search algorithm.")
    print("• Keyboard press \"2\" runs the Dijkstra's algorithm.")
    print("• Keyboard press \"3\" runs the Depth-first search algorithm.")
    print("• Keyboard press \"R\" loads a random preloaded maze.")
    print("• Keyboard press \"C\" clears the board.")
    print("• Keyboard press \"S\" saves your current board layout.")
    print("• Keyboard press \"L\" loads a saved board layout.")
    print("• Keyboard press \"H\" prints this menu again for help.")

#LOADING A RANDOM PRELOADED MAZE
numberMemmory = [0]
def load_randomMaze(grid):
    try:
        lastNumber = numberMemmory.pop()

        currentNumber = random.randint(0,2)
        while currentNumber == lastNumber:
            currentNumber = random.randint(0,2)
        numberMemmory.append(currentNumber)

        listofmazes = [mazes.maze1, mazes.maze2, mazes.maze3]
        mazeLayout = listofmazes[currentNumber]
        loading_maze(grid, mazeLayout)
        print("Successfully loaded a random preloaded maze.")
    except Exception as e:
        print("Error: failed loading a random preloaded maze.")
        print(e)

###############################################################################################
# MAIN GAME LOOP
###############################################################################################

def main(win, width):
    say_usermanual()
    ROWS = 50
    grid = make_grid(ROWS, width)
    start = None #start node
    end = None #end node
    locked = False #board lock

    run = True
    while run:
        draw(win, grid, ROWS, width)
        for event in pygame.event.get():
            #QUITS PROGRAM IF REQUESTED
            if event.type == pygame.QUIT:
                run = False

            #CLEARS BOARD IF NEW ALGORITHM IS STARTED OR MOUSE BUTTON IS CLICKED
            if pygame.mouse.get_pressed()[0] or pygame.mouse.get_pressed()[2] or \
                (event.type == pygame.KEYDOWN and event.key == pygame.K_1) or \
                (event.type == pygame.KEYDOWN and event.key == pygame.K_2) or \
                (event.type == pygame.KEYDOWN and event.key == pygame.K_3):
                    if locked:
                        locked = False
                        for row in grid:
                            for node in row:
                                if node.is_open() or node.is_closed() or node.is_path():
                                    node.reset()

            #CREATES START, END, AND BARRIER NODES
            if pygame.mouse.get_pressed()[0]: #LEFT MOUSE CLICK
                pos = pygame.mouse.get_pos()
                row, col = get_clicked_pos(pos, ROWS, width)
                node = grid[row][col]
                if not start and node != end:
                    start = node
                    start.make_start()
                elif not end and node != start:
                    end = node
                    end.make_end()
                elif node != end and node != start:
                    node.make_barrier()

            #RESETS NODES WITH MOUSE CLICK
            elif pygame.mouse.get_pressed()[2]: #RIGHT MOUSE CLICK
                pos = pygame.mouse.get_pos()
                row, col = get_clicked_pos(pos, ROWS, width)
                node = grid[row][col]
                node.reset()
                if node == start:
                    start = None
                elif node == end:
                    end = None

            #KEYBOARD COMMANDS
            if event.type == pygame.KEYDOWN:
                #A* STAR ALGORITHM
                if event.key == pygame.K_1 and start and end: #RUNS PROGRAM
                    start_time = time.time()
                    for row in grid:
                        for node in row:
                            node.update_neighbors(grid)
                    astar(lambda: draw(win, grid, ROWS, width), grid, start, end)
                    locked = True
                    path_stats(grid, start_time)

                #DIJKSTRA'S ALGORITHM
                if event.key == pygame.K_2 and start and end: #RUNS PROGRAM
                    start_time = time.time()
                    for row in grid:
                        for node in row:
                            node.update_neighbors(grid)
                    dijkstra(lambda: draw(win, grid, ROWS, width), grid, start, end)
                    locked = True
                    path_stats(grid, start_time)

                #DEPTH FIRST SEARCH ALGORITHM
                if event.key == pygame.K_3 and start and end: #RUNS PROGRAM
                    start_time = time.time()
                    for row in grid:
                        for node in row:
                            node.update_neighbors(grid)
                    dfs(lambda: draw(win, grid, ROWS, width), grid, start, end)
                    locked = True
                    path_stats(grid, start_time)

                #LOADING A SAVED MAZE FILE ONTO BOARD
                if event.key == pygame.K_l:
                    grid = make_grid(ROWS, width)
                    start = None
                    end = None
                    load_mazefile(grid)

                #SAVING A MAZE BOARD INTO A FILE
                if event.key == pygame.K_s:
                    save_mazefile(row, grid, node)

                #CLEARS THE GRID BOARD
                if event.key == pygame.K_c:
                    start = None
                    end = None
                    grid = make_grid(ROWS, width)

                #PRINTS THE HELP MENU
                if event.key == pygame.K_h:
                    say_usermanual()

                #LOADS A RANDOM MAZE
                if event.key == pygame.K_r:
                    grid = make_grid(ROWS, width)
                    start = None
                    end = None
                    load_randomMaze(grid)

    pygame.quit()
main(WIN, WIDTH)


# -*- coding: utf-8 -*-
'''
Created on Nov. 23, 2012

@author: E. LEGROS
@contact: emeline.legros@ibcp.fr
@license: GPLv3
'''
import os
from ConfigParser import Error as ConfigParserError
import logging
_log = logging.getLogger(__name__)

from mongokit import Document, ObjectId, IS
from mf.annotation import mf_decorator, MF_READ, MF_EDIT

from .connection import connection
from .config import Config
from .data import AbstractData
from .objectmanager import ObjectManager

@mf_decorator
@connection.register
class Project(Document):
    """
    Project is a class that stores all information about a project
    (owner username, inputs, outputs, job id).
    It's initialized by two parameters: the name of the owner of
    the project and the project name itself.
    """

    __collection__ = 'projects'
    __database__ = Config.config().get('app:main', 'db_name')

    structure = {'name': basestring,
                 'description': basestring,
                 'owner': ObjectId,
                 'users': [{'user': ObjectId, 'role': IS(u'manager',
                                                         u'contributor',
                                                         u'watcher')}],
                 'notebook': basestring,
                 'public': bool,
                 '_dir': basestring
                }

    required_fields = ['name', 'owner']

    default_values = {'_dir': None}

    @property
    def creation_date(self):
        """
        Get project creation date
        :returns: the attribute value
        :rtype: datetime
        """
        return self['_id'].generation_time

    def add_user(self, user, role):
        """
        add_user is a method defined to attach a new user
        and its role into the project.
        :param user: user to be associated to the project.
        :type user: :class:`User` object.
        :param role: user's role in the project.
        :type role: string.
        """
        self['users'].append({'user': user['_id'], 'role': role})

    @property
    def dir(self):
        """
        :return: the project directory
        :rtype: string
        """
        try:
            projects_store = Config.config().get("DEFAULT","projects_store")
        except ConfigParserError:
            _log.warning("cannot compute a project directory path from the config file",
                      exc_info=True)
            return None
        return os.path.join(projects_store, 'projects', str(self['_id']))

    @property
    def id(self):
        """
        :return: the unique identifier of this project
        :rtype:
        """
        return self['_id']

    @staticmethod
    def my_project_acl_filter(control, request, authenticated_userid=None):
        # find the user corresponding to the provided email
        user = connection.User.find_one({'email': authenticated_userid})
        # id is set if user exists, otherwise set to None so that the filter
        # works even for unauthenticated users.
        user_id = user['_id'] if user else None
        # admin_mode tells wether the admin user
        # is in admin mode and should access everything
        admin_mode = hasattr(request, 'session') \
                     and 'adminmode' in request.session
        if user and user.get('admin') and admin_mode:
            # admin_mode = provide everything
            project_filter = {}
        elif control == MF_READ:
            # read: elements for projects where the user is active or where he
            if user is None:
                project_filter = {'public': True}
            else:
                project_filter = {"$or": [{"users": {"$elemMatch":
                                  {'user': user_id}}}, {'public':True}]}
        elif control == MF_EDIT:
            # User must be one of project contributors or managers
            if user is None:
                project_filter = None
            else:
                project_filter = {"users": {"$elemMatch": {'user': user_id,
                                  "$or": [{'role': 'contributor'},
                                          {'role': 'manager'}]}}}
        return project_filter

    def my(self, control, request, authenticated_userid=None):
        return self.my_project_acl_filter(control,
                                          request, authenticated_userid)

class ProjectDocument(Document):
    """
    ProjectDocument is an abstract class which defines the ACLs of
    project-contained elements. The ACLs of such documents are completely
    defined by the users of the containing project
    """

    def my(self, control, request, authenticated_userid=None):
        project_filter = Project.my_project_acl_filter(control, request,
                                                       authenticated_userid)
        # return directly project filter if it allows everything or nothing
        if project_filter == {} or project_filter is None:
            return project_filter
        # otherwise select the ids of the allowed projects
        else:
            project_ids_curs = connection.Project.find(project_filter,
                                                       {'_id': 1})
            project_ids = []
            for project_id in project_ids_curs:
                project_ids.append(project_id['_id'])
            return {"project": {"$in": project_ids}}

@mf_decorator
@connection.register
class ProjectData(ProjectDocument):
    """
    ProjectData describes a data linked to a project. It is referenced by jobs
    and user data manager. A ProjectData can be persistent or not.
    Data contains an AbstractData structure defining the data available.
    """

    __collection__ = 'projects_data'
    __database__ = Config.config().get('app:main', 'db_name')

    structure = {'name': basestring,
                 'description': basestring,
                 'tags': [basestring],
                 'project': ObjectId,
                 'data': AbstractData,
                 # see ObjectManager. Only READY data can be used
                 'status': int,
                 # set to True to avoid automatic deletion
                 # by cleanup tasks
                 'persistent': bool,
                 # path to the container directory for the data
                 # if it is not stored in the datamanager pairtree
                 'path': basestring,
                 # set to True to override project visibility
                 'public': bool
                 #TODO: add data provenance information
                }

    default_values = {'persistent': False, 'public': False}

    @property
    def default_value(self):
        """
        return default_value, delegated to data property
        """
        return self['data'].default_value

    def expr_value(self):
        """
        return expr_value(), delegated to data property
        """
        return self['data'].expr_value()

    def import_to_job(self, job):
        return self['data'].import_to_job(job, self.get_file_path())

    def get_file_path(self):
        '''Get root path for files of the dataset'''
        if self['path']:
            return self['path']
        return ObjectManager.get_file_path(str(self['_id']))

    def schema(self, schema=None):
        '''Update schema if parameter is not None, return schema'''
        if schema is not None:
            self['data'] = schema
            self.save()
        return self['data']

    def status(self, status=None):
        '''Update status if parameter is not None, return status'''
        if status is not None:
            self['status'] = status
            self.save()
        return self['status']

    def save_with_history(self, files=None, msg=None):
        '''
        Save object and update git repo if available

        :param files: List of relative path of new or updated files in dataset
        :type files: list
        :param msg: optional msg for the update
        :type msg: str
        '''
        if files is not None and files and ObjectManager.use_repo:
            index = ObjectManager.get_repository_index(str(self['_id']))
            index.add(files)
            if msg is None:
                msg = "Update data"
            index.commit(msg)
        self.save()


import ujson
from django.test import Client
from django.test.testcases import TestCase

class EventAPIViewTests(TestCase):
    def setUp(self):
        self.path = '/event'
        self.client = Client()

    def test_post_event_api_view(self):
        data = {'type': 'deposit', 'destination': '100', 'amount': 10}

        response = self.client.post(self.path, data, content_type='application/json')

        self.assertEqual(201, response.status_code)
        expected = {'destination': {'id': '100', 'balance': 10}}
        self.assertEqual(expected, ujson.loads(response.content))

    def test_post_event_api_view_with_non_existing_account(self):
        data = {'type': 'withdraw', 'origin': '200', 'amount': 10}

        response = self.client.post(self.path, data, content_type='application/json')

        self.assertEqual(404, response.status_code)


from PyQt5 import QtCore, QtGui, QtWidgets
import os

directory = os.getcwd()

class Cryptor:
		text = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~','\n']
		key = ["Contact developer for keys"]
		def enc(inpt):
			return ''.join([Cryptor.key[Cryptor.text.index(tol)] for tol in inpt if tol in Cryptor.text])
		def dec(inpt):
			de = [inpt[d:d+5] for d in range(0, len(inpt), 5)]
			return ''.join([Cryptor.text[Cryptor.key.index(dr)] for dr in de if dr in Cryptor.key])

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(411, 408)
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(9)
        MainWindow.setFont(font)
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(f"{directory}/logotk.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        MainWindow.setWindowIcon(icon)
        self.data = 'Encrypt'
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
# =============================================================================================================================
        self.messagebox = QtWidgets.QTextEdit(self.centralwidget)
        self.messagebox.setGeometry(QtCore.QRect(10, 70, 391, 131))
        self.messagebox.setObjectName("messagebox")
# =============================================================================================================================
        self.outputbox = QtWidgets.QTextEdit(self.centralwidget)
        self.outputbox.setGeometry(QtCore.QRect(10, 240, 291, 131))
        self.outputbox.setObjectName("outputbox")
# =============================================================================================================================
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(10, 30, 261, 41))
        self.label.setObjectName("label")
# =============================================================================================================================
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(70, 200, 201, 41))
        self.label_2.setObjectName("label_2")
# =============================================================================================================================
        self.Choose = QtWidgets.QComboBox(self.centralwidget)
        self.Choose.setGeometry(QtCore.QRect(280, 40, 121, 22))
        self.Choose.setObjectName("Choose")
        self.Choose.addItem('Encrypt')
        self.Choose.addItem('Decrypt')
        self.Choose.activated[str].connect(self.onPressed)
# =============================================================================================================================
        self.crypt = QtWidgets.QPushButton(self.centralwidget)  # Cryptor Button
        self.crypt.setGeometry(QtCore.QRect(310, 330, 91, 31))
        self.crypt.setObjectName("crypt")
        self.crypt.clicked.connect(self.onChanged)
# =============================================================================================================================
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_3.setGeometry(QtCore.QRect(80, 0, 241, 41))
        self.label_3.setAutoFillBackground(False)
        self.label_3.setObjectName("label_3")
# =============================================================================================================================
        self.widget = QtWidgets.QWidget(self.centralwidget)
        self.widget.setGeometry(QtCore.QRect(310, 240, 91, 75))
        self.widget.setObjectName("widget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.widget)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.label_4 = QtWidgets.QLabel(self.widget)
        self.label_4.setObjectName("label_4")
        self.verticalLayout.addWidget(self.label_4)
# =============================================================================================================================
        self.pushButton = QtWidgets.QPushButton(self.widget)   # Clear Button
        self.pushButton.setObjectName("pushButton")
        self.pushButton.clicked.connect(self.clear)
        self.verticalLayout.addWidget(self.pushButton)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 411, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Cryptor"))
        self.label.setText(_translate("MainWindow", "
Enter Your Message Below
"))
        self.label_2.setText(_translate("MainWindow", "
Generated Output
"))
        self.crypt.setText(_translate("MainWindow", "C R Y P T"))
        self.label_3.setText(_translate("MainWindow", "
GhosTmaN EnCryption
"))
        self.label_4.setText(_translate("MainWindow", "
Click here to

clear Screen
"))
        self.pushButton.setText(_translate("MainWindow", "Clear"))

    def onPressed(self,text):
        self.data = text

    def onChanged(self):
        text = self.messagebox.toPlainText()
        if self.data == "Encrypt":
            self.outputbox.setPlainText(Cryptor.enc(text))
        elif self.data == "Decrypt":
            self.outputbox.setPlainText(Cryptor.dec(text))
    def clear(self):
        self.messagebox.setPlainText('')
        self.outputbox.setPlainText('')

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())