# Python SCALE Codec Library
#
# Copyright 2018-2020 Stichting Polkascan (Polkascan Foundation).
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import math
from datetime import datetime
from hashlib import blake2b

from scalecodec.utils.ss58 import ss58_decode_account_index, ss58_decode, ss58_encode, is_valid_ss58_address

from scalecodec.base import ScaleType, ScaleBytes
from scalecodec.exceptions import InvalidScaleTypeValueException, MetadataCallFunctionNotFound
from scalecodec.utils.math import trailing_zeros, next_power_of_two

class Compact(ScaleType):

    def __init__(self, data=None, **kwargs):
        self.compact_length = 0
        self.compact_bytes = None
        super().__init__(data, **kwargs)

    def process_compact_bytes(self):
        compact_byte = self.get_next_bytes(1)
        try:
            byte_mod = compact_byte[0] % 4
        except IndexError:
            raise InvalidScaleTypeValueException("Invalid byte for Compact")

        if byte_mod == 0:
            self.compact_length = 1
        elif byte_mod == 1:
            self.compact_length = 2
        elif byte_mod == 2:
            self.compact_length = 4
        else:
            self.compact_length = int(5 + (compact_byte[0] - 3) / 4)

        if self.compact_length == 1:
            self.compact_bytes = compact_byte
        elif self.compact_length in [2, 4]:
            self.compact_bytes = compact_byte + self.get_next_bytes(self.compact_length - 1)
        else:
            self.compact_bytes = self.get_next_bytes(self.compact_length - 1)

        return self.compact_bytes

    def process(self):

        self.process_compact_bytes()

        if self.sub_type:

            byte_data = self.get_decoder_class(
                type_string=self.sub_type, data=ScaleBytes(self.compact_bytes), runtime_config=self.runtime_config
            ).process()

            if type(byte_data) is int and self.compact_length <= 4:
                return int(byte_data / 4)
            else:
                return byte_data
        else:
            return self.compact_bytes

    def process_encode(self, value):

        value = int(value)

        if value <= 0b00111111:
            return ScaleBytes(bytearray(int(value << 2).to_bytes(1, 'little')))

        elif value <= 0b0011111111111111:
            return ScaleBytes(bytearray(int((value << 2) | 0b01).to_bytes(2, 'little')))

        elif value <= 0b00111111111111111111111111111111:

            return ScaleBytes(bytearray(int((value << 2) | 0b10).to_bytes(4, 'little')))

        else:
            for bytes_length in range(4, 68):
                if 2 ** (8 * (bytes_length - 1)) <= value < 2 ** (8 * bytes_length):
                    return ScaleBytes(bytearray(
                        ((bytes_length - 4) << 2 | 0b11).to_bytes(1, 'little') + value.to_bytes(bytes_length,
                                                                                'little')))
            else:
                raise ValueError('{} out of range'.format(value))

class CompactU32(Compact):
    """
    Specialized composite implementation for performance improvement
    """

    type_string = 'Compact<u32>'

    def process(self):
        self.process_compact_bytes()

        if self.compact_length <= 4:
            return int(int.from_bytes(self.compact_bytes, byteorder='little') / 4)
        else:
            return int.from_bytes(self.compact_bytes, byteorder='little')

    def process_encode(self, value):

        if value <= 0b00111111:
            return ScaleBytes(bytearray(int(value << 2).to_bytes(1, 'little')))

        elif value <= 0b0011111111111111:
            return ScaleBytes(bytearray(int((value << 2) | 0b01).to_bytes(2, 'little')))

        elif value <= 0b00111111111111111111111111111111:

            return ScaleBytes(bytearray(int((value << 2) | 0b10).to_bytes(4, 'little')))

        else:
            for bytes_length in range(4, 68):
                if 2 ** (8 * (bytes_length-1)) <= value < 2 ** (8 * bytes_length):
                    return ScaleBytes(bytearray(((bytes_length - 4) << 2 | 0b11).to_bytes(1, 'little') + value.to_bytes(bytes_length, 'little')))
            else:
                raise ValueError('{} out of range'.format(value))

class Option(ScaleType):
    def process(self):

        option_byte = self.get_next_bytes(1)

        if self.sub_type and option_byte != b'\x00':
            return self.process_type(self.sub_type).value

        return None

    def process_encode(self, value):

        if value is not None and self.sub_type:
            sub_type_obj = self.get_decoder_class(self.sub_type, runtime_config=self.runtime_config)
            return ScaleBytes('0x01') + sub_type_obj.encode(value)

        return ScaleBytes('0x00')

class Bytes(ScaleType):

    type_string = 'Vec<u8>'

    def process(self):

        length = self.process_type('Compact<u32>').value
        value = self.get_next_bytes(length)

        try:
            return value.decode()
        except UnicodeDecodeError:
            return '0x{}'.format(value.hex())

    def process_encode(self, value):
        string_length_compact = CompactU32()

        if value[0:2] == '0x':
            # TODO implicit HexBytes conversion can have unexpected result if string is actually starting with '0x'
            value = bytes.fromhex(value[2:])
            data = string_length_compact.encode(len(value))
            data += value
        else:
            data = string_length_compact.encode(len(value))
            data += value.encode()

        return data

class OptionBytes(ScaleType):

    type_string = 'Option<Vec<u8>>'

    def process(self):

        option_byte = self.get_next_bytes(1)

        if option_byte != b'\x00':
            return self.process_type('Bytes').value

        return None

    def process_encode(self, value):

        if value is not None:
            sub_type_obj = Bytes()
            return ScaleBytes('0x01') + sub_type_obj.encode(value)

        return ScaleBytes('0x00')

# TODO replace in metadata
class String(ScaleType):

    def process(self):

        length = self.process_type('Compact<u32>').value
        value = self.get_next_bytes(length)

        return value.decode()

    def process_encode(self, value):
        string_length_compact = CompactU32()
        data = string_length_compact.encode(len(value))
        data += value.encode()
        return data

class HexBytes(ScaleType):

    def __init__(self, *args, **kwargs):
        self.length_obj = None
        super().__init__(*args, **kwargs)

    def process(self):

        self.length_obj = self.process_type('Compact<u32>')

        return '0x{}'.format(self.get_next_bytes(self.length_obj.value).hex())

    def process_encode(self, value):

        if value[0:2] != '0x':
            raise ValueError('HexBytes value should start with "0x"')

        value = bytes.fromhex(value[2:])

        string_length_compact = CompactU32()
        data = string_length_compact.encode(len(value))
        data += value
        return data

class CallBytes(ScaleType):

    def process(self):
        raise NotImplementedError()

    def process_encode(self, value):
        return bytes.fromhex(value[2:])

class U8(ScaleType):

    def process(self):
        return self.get_next_u8()

    def process_encode(self, value):

        if 0 <= int(value) <= 2**8 - 1:
            return ScaleBytes(bytearray(int(value).to_bytes(1, 'little')))
        else:
            raise ValueError('{} out of range for u8'.format(value))

class U16(ScaleType):

    def process(self):
        return int.from_bytes(self.get_next_bytes(2), byteorder='little')

    def process_encode(self, value):

        if 0 <= int(value) <= 2**16 - 1:
            return ScaleBytes(bytearray(int(value).to_bytes(2, 'little')))
        else:
            raise ValueError('{} out of range for u16'.format(value))

class U32(ScaleType):

    def process(self):
        return int.from_bytes(self.get_next_bytes(4), byteorder='little')

    def process_encode(self, value):

        if 0 <= int(value) <= 2**32 - 1:
            return ScaleBytes(bytearray(int(value).to_bytes(4, 'little')))
        else:
            raise ValueError('{} out of range for u32'.format(value))

class U64(ScaleType):

    def process(self):
        return int(int.from_bytes(self.get_next_bytes(8), byteorder='little'))

    def process_encode(self, value):

        if 0 <= int(value) <= 2**64 - 1:
            return ScaleBytes(bytearray(int(value).to_bytes(8, 'little')))
        else:
            raise ValueError('{} out of range for u64'.format(value))

class U128(ScaleType):

    def process(self):
        return int(int.from_bytes(self.get_next_bytes(16), byteorder='little'))

    def process_encode(self, value):

        if 0 <= int(value) <= 2**128 - 1:
            return ScaleBytes(bytearray(int(value).to_bytes(16, 'little')))
        else:
            raise ValueError('{} out of range for u128'.format(value))

class U256(ScaleType):

    def process(self):
        return int(int.from_bytes(self.get_next_bytes(32), byteorder='little'))

    def process_encode(self, value):

        if 0 <= int(value) <= 2**256 - 1:
            return ScaleBytes(bytearray(int(value).to_bytes(32, 'little')))
        else:
            raise ValueError('{} out of range for u256'.format(value))

class I8(ScaleType):

    def process(self):
        return int.from_bytes(self.get_next_bytes(1), byteorder='little', signed=True)

    def process_encode(self, value):

        if -128 <= int(value) <= 127:
            return ScaleBytes(bytearray(int(value).to_bytes(1, 'little', signed=True)))
        else:
            raise ValueError('{} out of range for i8'.format(value))

class I16(ScaleType):

    def process(self):
        return int.from_bytes(self.get_next_bytes(2), byteorder='little', signed=True)

    def process_encode(self, value):

        if -32768 <= int(value) <= 32767:
            return ScaleBytes(bytearray(int(value).to_bytes(2, 'little', signed=True)))
        else:
            raise ValueError('{} out of range for i16'.format(value))

class I32(ScaleType):

    def process(self):
        return int.from_bytes(self.get_next_bytes(4), byteorder='little', signed=True)

    def process_encode(self, value):

        if -2147483648 <= int(value) <= 2147483647:
            return ScaleBytes(bytearray(int(value).to_bytes(4, 'little', signed=True)))
        else:
            raise ValueError('{} out of range for i32'.format(value))

class I64(ScaleType):

    def process(self):
        return int.from_bytes(self.get_next_bytes(8), byteorder='little', signed=True)

    def process_encode(self, value):

        if -2**64 <= int(value) <= 2**64-1:
            return ScaleBytes(bytearray(int(value).to_bytes(8, 'little', signed=True)))
        else:
            raise ValueError('{} out of range for i64'.format(value))

class I128(ScaleType):

    def process(self):
        return int.from_bytes(self.get_next_bytes(16), byteorder='little', signed=True)

    def process_encode(self, value):

        if -2**128 <= int(value) <= 2**128-1:
            return ScaleBytes(bytearray(int(value).to_bytes(16, 'little', signed=True)))
        else:
            raise ValueError('{} out of range for i128'.format(value))

class I256(ScaleType):

    def process(self):
        return int.from_bytes(self.get_next_bytes(32), byteorder='little', signed=True)

    def process_encode(self, value):

        if -2**256 <= int(value) <= 2**256-1:
            return ScaleBytes(bytearray(int(value).to_bytes(32, 'little', signed=True)))
        else:
            raise ValueError('{} out of range for i256'.format(value))

class H160(ScaleType):

    def process(self):
        return '0x{}'.format(self.get_next_bytes(20).hex())

    def process_encode(self, value):
        if value[0:2] != '0x' or len(value) != 42:
            raise ValueError('Value should start with "0x" and should be 20 bytes long')
        return ScaleBytes(value)

class H256(ScaleType):

    def process(self):
        return '0x{}'.format(self.get_next_bytes(32).hex())

    def process_encode(self, value):
        if value[0:2] != '0x' or len(value) != 66:
            raise ValueError('Value should start with "0x" and should be 32 bytes long')
        return ScaleBytes(value)

class H512(ScaleType):

    def process(self):
        return '0x{}'.format(self.get_next_bytes(64).hex())

    def process_encode(self, value):
        if value[0:2] != '0x' or len(value) != 130:
            raise ValueError('Value should start with "0x" and should be 64 bytes long')
        return ScaleBytes(value)

class Struct(ScaleType):

    def __init__(self, data=None, type_mapping=None, **kwargs):

        if type_mapping:
            self.type_mapping = type_mapping

        super().__init__(data, **kwargs)

    def process(self):

        result = {}

        for key, data_type in self.type_mapping:
            if data_type is None:
                data_type = 'Null'
            result[key] = self.process_type(data_type, metadata=self.metadata).value

        return result

    def process_encode(self, value):
        data = ScaleBytes(bytearray())

        for key, data_type in self.type_mapping:
            if key not in value:
                raise ValueError('Element "{}" of struct is missing in given value'.format(key))

            element_obj = self.get_decoder_class(
                type_string=data_type, metadata=self.metadata, runtime_config=self.runtime_config
            )
            data += element_obj.encode(value[key])

        return data

class Tuple(ScaleType):
    def __init__(self, data=None, type_mapping=None, **kwargs):

        if type_mapping:
            self.type_mapping = type_mapping

        super().__init__(data, **kwargs)

    def process(self):

        result = ()

        for member_type in self.type_mapping:
            if member_type is None:
                member_type = 'Null'
            result += (self.process_type(member_type, metadata=self.metadata).value,)

        return result

    def process_encode(self, value):
        data = ScaleBytes(bytearray())

        if type(value) is list or type(value) is tuple:
            if len(value) != len(self.type_mapping):
                raise ValueError('Element count of value ({}) doesn\'t match type_definition ({})'.format(
                    len(value), len(self.type_mapping))
                )

            for idx, member_type in enumerate(self.type_mapping):

                element_obj = self.get_decoder_class(
                    member_type, metadata=self.metadata, runtime_config=self.runtime_config
                )
                data += element_obj.encode(value[idx])

        return data

class Set(ScaleType):
    value_list = []
    value_type = 'u64'

    def __init__(self, data, value_list=None, **kwargs):
        self.set_value = None

        if value_list:
            self.value_list = value_list

        super().__init__(data, **kwargs)

    def process(self):
        self.set_value = self.process_type(self.value_type).value
        result = []
        if self.set_value > 0:

            for value, set_mask in self.value_list.items():
                if self.set_value & set_mask > 0:
                    result.append(value)
        return result

    def process_encode(self, value):
        result = 0
        if type(value) is not list:
            raise ValueError('Value for encoding a set must be a list')

        for item, set_mask in self.value_list.items():
            if item in value:
                result += set_mask

        u64_obj = self.get_decoder_class(type_string=self.value_type, runtime_config=self.runtime_config)

        return u64_obj.encode(result)

class Era(ScaleType):
    """
    An Era represents a range of blocks in which a transaction is allowed to be
    executed.

    An Era may either be "immortal", in which case the transaction is always valid,
    or "mortal", in which case the transaction has a defined start block and period
    in which it is valid.
    """

    def __init__(self, **kwargs):
        self.period = None
        self.phase = None
        super().__init__(**kwargs)

    def process(self):

        option_byte = self.get_next_bytes(1).hex()
        if option_byte == '00':
            self.period = None
            self.phase = None
            return option_byte
        else:
            encoded = int(option_byte, base=16) + (int(self.get_next_bytes(1).hex(), base=16) << 8)
            self.period = 2 << (encoded % (1 << 4))
            quantize_factor = max(1, (self.period >> 12))
            self.phase = (encoded >> 4) * quantize_factor
            if self.period >= 4 and self.phase < self.period:
                return (self.period, self.phase)
            else:
                raise ValueError('Invalid phase and period: {}, {}'.format(self.phase, self.period))

    def _tuple_from_dict(self, value):
        if 'period' not in value:
            raise ValueError("Value missing required field 'period' in dict Era")
        period = value['period']

        if 'phase' in value:
            return (period, value['phase'])

        # If phase not specified explicitly, let the user specify the current block,
        # and calculate the phase from that.
        if 'current' not in value:
            raise ValueError("Dict Era must have one of the fields 'phase' or 'current'")

        current = value['current']

        # Period must be a power of two between 4 and 2**16
        period = max(4, min(1 << 16, next_power_of_two(period)))
        phase = current % period
        quantize_factor = max(1, (period >> 12))
        quantized_phase = (phase // quantize_factor) * quantize_factor

        return (period, quantized_phase)

    def process_encode(self, value):
        if value == '00':
            self.period = None
            self.phase = None
            return ScaleBytes('0x00')
        if isinstance(value, dict):
            value = self._tuple_from_dict(value)
        if isinstance(value, tuple) and len(value) == 2:
            period, phase = value
            if not isinstance(phase, int) or not isinstance(period, int):
                raise ValueError("Phase and period must be ints")
            if phase > period:
                raise ValueError("Phase must be less than period")
            self.period = period
            self.phase = phase
            quantize_factor = max(period >> 12, 1)
            encoded = min(15, max(1, trailing_zeros(period) - 1)) | ((phase // quantize_factor) << 4)
            return ScaleBytes(encoded.to_bytes(length=2, byteorder='little', signed=False))

        raise ValueError("Value must be the string '00' or tuple of two ints")

    def is_immortal(self) -> bool:
        """Returns true if the era is immortal, false if mortal."""
        return self.period is None or self.phase is None

    def birth(self, current: int) -> int:
        """Gets the block number of the start of the era given, with `current`
        as the reference block number for the era, normally included as part
        of the transaction.
        """
        if self.is_immortal():
            return 0
        return (max(current, self.phase) - self.phase) // self.period * self.period + self.phase

    def death(self, current: int) -> int:
        """Gets the block number of the first block at which the era has ended.

        If the era is immortal, 2**64 - 1 (the maximum unsigned 64-bit integer) is returned.
        """
        if self.is_immortal():
            return 2**64 - 1
        return self.birth(current) + self.period

class Bool(ScaleType):

    def process(self):
        return self.get_next_bool()

    def process_encode(self, value):
        if value is True:
            return ScaleBytes('0x01')
        elif value is False:
            return ScaleBytes('0x00')
        else:
            raise ValueError("Value must be boolean")

class CompactMoment(CompactU32):
    type_string = 'Compact<Moment>'

    def process(self):
        int_value = super().process()

        if int_value > 10000000000:
            int_value = int_value / 1000

        return datetime.utcfromtimestamp(int_value)

    def serialize(self):
        return self.value.isoformat()

class ProposalPreimage(Struct):
    type_string = '(Vec<u8>, AccountId, BalanceOf, BlockNumber)'

    type_mapping = (
        ("proposal", "HexBytes"),
        ("registredBy", "AccountId"),
        ("deposit", "BalanceOf"),
        ("blockNumber", "BlockNumber")
    )

    def process(self):

        result = {}
        for key, data_type in self.type_mapping:
            result[key] = self.process_type(data_type, metadata=self.metadata).value

        # Replace HexBytes with actual proposal
        result['proposal'] = self.get_decoder_class('Proposal', data=ScaleBytes(result['proposal']),
                                                    metadata=self.metadata).decode()

        return result

class ValidatorPrefs(Struct):
    type_string = '(Compact<Balance>)'

    type_mapping = (('commission', 'Compact<Balance>'),)

class ValidatorPrefsLegacy(Struct):
    type_string = '(Compact<u32>,Compact<Balance>)'

    type_mapping = (('unstakeThreshold', 'Compact<u32>'), ('validatorPayment', 'Compact<Balance>'))

class Linkage(Struct):
    type_string = 'Linkage<AccountId>'

    type_mapping = (
        ('previous', 'Option<AccountId>'),
        ('next', 'Option<AccountId>')
    )

class GenericAccountId(H256):

    def __init__(self, data=None, **kwargs):
        self.ss58_address = None
        self.public_key = None
        super().__init__(data, **kwargs)

    def process_encode(self, value):
        if value[0:2] != '0x':
            from scalecodec.utils.ss58 import ss58_decode
            self.ss58_address = value
            value = '0x{}'.format(ss58_decode(value))
        return super().process_encode(value)

    def serialize(self):
        return self.ss58_address or self.value

    def process(self):
        value = self.public_key = super().process()

        if self.runtime_config.ss58_format is not None:
            try:
                value = self.ss58_address = ss58_encode(value, ss58_format=self.runtime_config.ss58_format)
            except ValueError:
                pass

        return value

class GenericAccountIndex(U32):
    pass

class Vec(ScaleType):

    def __init__(self, data=None, **kwargs):
        self.elements = []
        super().__init__(data, **kwargs)

    def process(self):
        element_count = self.process_type('Compact<u32>').value

        result = []
        for _ in range(0, element_count):
            element = self.process_type(self.sub_type, metadata=self.metadata)
            self.elements.append(element)
            result.append(element.value)

        return result

    def process_encode(self, value):

        if type(value) is not list:
            raise ValueError("Provided value is not a list")

        # encode element count to Compact<u32>
        element_count_compact = CompactU32()

        element_count_compact.encode(len(value))

        data = element_count_compact.data

        for element in value:

            element_obj = self.get_decoder_class(
                type_string=self.sub_type, metadata=self.metadata, runtime_config=self.runtime_config
            )
            data += element_obj.encode(element)

        return data

class BoundedVec(Vec):
    def __init__(self, data=None, **kwargs):

        # Rebuild sub_type as last item is the upper bound of elements allowed
        self.sub_type, self.max_elements = [x.strip() for x in self.sub_type.rsplit(',', 1)]

        super().__init__(data, **kwargs)

class BitVec(ScaleType):
    """
    A BitVec that represents an array of bits. The bits are however stored encoded. The difference between this
    and a normal Bytes would be that the length prefix indicates the number of bits encoded, not the bytes
    """
    def process(self):
        length_obj = self.process_type('Compact<u32>')

        total = math.ceil(length_obj.value / 8)

        value_int = int.from_bytes(self.get_next_bytes(total), byteorder='little')

        return '0b' + bin(value_int)[2:].zfill(length_obj.value)

    def process_encode(self, value):

        if type(value) is list:
            value = sum(v << i for i, v in enumerate(reversed(value)))

        if type(value) is str and value[0:2] == '0b':
            value = int(value[2:], 2)

        if type(value) is not int:
            raise ValueError("Provided value is not an int, binary str or a list of booleans")

        if value == 0:
            return ScaleBytes(b'\x00')

        # encode the length in a compact u32
        compact_obj = CompactU32()
        data = compact_obj.encode(value.bit_length())

        byte_length = math.ceil(value.bit_length() / 8)

        return data + value.to_bytes(length=byte_length, byteorder='little')

class GenericAddress(ScaleType):

    def __init__(self, data=None, **kwargs):
        self.account_length = None
        self.account_id = None
        self.account_index = None
        self.account_idx = None
        super().__init__(data, **kwargs)

    def process(self):
        self.account_length = self.get_next_bytes(1)

        if self.account_length == b'\xff':
            self.account_id = self.get_next_bytes(32).hex()
            self.account_length = self.account_length.hex()

            return self.account_id
        else:
            if self.account_length == b'\xfc':
                account_index = self.get_next_bytes(2)
            elif self.account_length == b'\xfd':
                account_index = self.get_next_bytes(4)
            elif self.account_length == b'\xfe':
                account_index = self.get_next_bytes(8)
            else:
                account_index = self.account_length

            self.account_index = account_index.hex()
            self.account_idx = int.from_bytes(account_index, byteorder='little')

            self.account_length = self.account_length.hex()

            return self.account_index

    def process_encode(self, value):

        if type(value) == str and value[0:2] != '0x':
            # Assume SS58 encoding address
            if len(value) >= 46:
                from scalecodec.utils.ss58 import ss58_decode
                value = '0x{}'.format(ss58_decode(value))
            else:
                from scalecodec.utils.ss58 import ss58_decode_account_index
                index_obj = GenericAccountIndex()
                value = index_obj.encode(ss58_decode_account_index(value))

        if type(value) == str and value[0:2] == '0x' and len(value) == 66:
            # value is AccountId
            return ScaleBytes('0xff{}'.format(value[2:]))
        elif type(value) == int:
            # value is AccountIndex
            raise NotImplementedError('Encoding of AccountIndex Adresses not supported yet')
        else:
            raise ValueError('Value is in unsupported format, expected 32 bytes hex-string for AccountIds or int for AccountIndex')

    def serialize(self):
        if self.account_id:
            return '0x{}'.format(self.value)
        else:
            return self.value

class AccountIdAddress(GenericAddress):

    def process(self):
        self.account_id = self.process_type('AccountId').value.replace('0x', '')
        self.account_length = 'ff'
        return self.account_id

    def process_encode(self, value):
        if type(value) == str and value[0:2] != '0x':
            # Assume SS58 encoding address
            if len(value) >= 46:
                from scalecodec.utils.ss58 import ss58_decode
                value = '0x{}'.format(ss58_decode(value))
            else:
                from scalecodec.utils.ss58 import ss58_decode_account_index
                index_obj = GenericAccountIndex()
                value = index_obj.encode(ss58_decode_account_index(value))

        if type(value) == str and value[0:2] == '0x' and len(value) == 66:
            # value is AccountId
            return ScaleBytes('0x{}'.format(value[2:]))
        elif type(value) == int:
            # value is AccountIndex
            raise NotImplementedError('Encoding of AccountIndex Adresses not supported yet')
        else:
            raise ValueError('Value is in unsupported format, expected 32 bytes hex-string for AccountIds or int for AccountIndex')

class RawAddress(GenericAddress):
    pass

class Enum(ScaleType):

    value_list = []
    type_mapping = None

    def __init__(self, data=None, value_list=None, type_mapping=None, **kwargs):

        self.index = None

        if type_mapping:
            self.type_mapping = type_mapping

        if value_list:
            self.value_list = value_list

        super().__init__(data, **kwargs)

    def process(self):
        self.index = int(self.get_next_bytes(1).hex(), 16)

        if self.type_mapping:
            try:
                enum_type_mapping = self.type_mapping[self.index]
                return self.process_type(
                    type_string='Struct', type_mapping=[enum_type_mapping]
                ).value

            except IndexError:
                raise ValueError("Index '{}' not present in Enum type mapping".format(self.index))
        else:
            try:
                return self.value_list[self.index]
            except IndexError:
                raise ValueError("Index '{}' not present in Enum value list".format(self.index))

    def process_encode(self, value):
        if self.type_mapping:

            if type(value) == str:
                # Convert simple enum values
                value = {value: None}

            if type(value) != dict:
                raise ValueError("Value must be a dict when type_mapping is set, not '{}'".format(value))

            if len(value) != 1:
                raise ValueError("Value for enum with type_mapping can only have one value")

            for enum_key, enum_value in value.items():
                for idx, (item_key, item_value) in enumerate(self.type_mapping):
                    if item_key == enum_key:
                        self.index = idx
                        struct_obj = self.get_decoder_class(
                            type_string='Struct',
                            type_mapping=[self.type_mapping[self.index]],
                            runtime_config=self.runtime_config
                        )
                        return ScaleBytes(bytearray([self.index])) + struct_obj.encode(value)

                raise ValueError("Value '{}' not present in type_mapping of this enum".format(enum_key))

        else:
            for idx, item in enumerate(self.value_list):
                if item == value:
                    self.index = idx
                    return ScaleBytes(bytearray([self.index]))

            raise ValueError("Value '{}' not present in value list of this enum".format(value))

    def get_enum_value(self):
        if self.value:

            if self.type_mapping:
                return list(self.value.values())[0]
            else:
                return self.value_list[self.index]

class Data(Enum):
    type_mapping = [
        ["None", "Null"],
        ["Raw", "Bytes"],
        ["BlakeTwo256", "H256"],
        ["Sha256", "H256"],
        ["Keccak256", "H256"],
        ["ShaThree256", "H256"]
      ]

    def process(self):

        self.index = int(self.get_next_bytes(1).hex(), 16)

        if self.index == 0:
            return {'None': None}

        elif self.index >= 1 and self.index <= 33:
            # Determine value of Raw type (length is processed in index byte)
            data = self.get_next_bytes(self.index - 1)

            try:
                value = data.decode()
            except UnicodeDecodeError:
                value = '0x{}'.format(data.hex())
            return {"Raw": value}

        elif self.index >= 34 and self.index <= 37:

            enum_value = self.type_mapping[self.index - 32][0]

            return {enum_value: self.process_type(self.type_mapping[self.index - 32][1]).value}

        raise ValueError("Unable to decode Data, invalid indicator byte '{}'".format(self.index))

    def process_encode(self, value):

        if type(value) != dict:
            raise ValueError("Value must be a dict when type_mapping is set, not '{}'".format(value))

        if len(value) != 1:
            raise ValueError("Value for enum with type_mapping can only have one value")

        for enum_key, enum_value in value.items():

            for idx, (item_key, item_value) in enumerate(self.type_mapping):
                if item_key == enum_key:
                    self.index = idx

                    if item_value == 'Null':
                        return ScaleBytes(bytearray([0]))

                    elif item_value == 'Bytes':

                        if enum_value[0:2] == '0x':

                            if len(enum_value) > 66:
                                raise ValueError("Raw type in Data cannot exceed 32 bytes")

                            enum_value = bytes.fromhex(enum_value[2:])
                            data = bytes([len(enum_value) + 1]) + enum_value
                            return ScaleBytes(bytearray(data))
                        else:

                            if len(enum_value) > 32:
                                raise ValueError("Raw type in Data cannot exceed 32 bytes")

                            data = bytes([len(enum_value) + 1]) + enum_value.encode()
                            return ScaleBytes(bytearray(data))
                    else:

                        struct_obj = self.get_decoder_class(
                            type_string=self.type_mapping[self.index][1],
                            runtime_config=self.runtime_config
                        )
                        return ScaleBytes(bytearray([self.index + 32])) + struct_obj.encode(enum_value)

            raise ValueError("Value '{}' not present in type_mapping of this enum".format(enum_key))

class Null(ScaleType):

    def process(self):
        return None

    def process_encode(self, value):
        return ScaleBytes(bytearray())

class InherentOfflineReport(Null):
    pass

class StorageHasher(Enum):

    value_list = ['Blake2_128', 'Blake2_256', 'Blake2_128Concat', 'Twox128', 'Twox256', 'Twox64Concat', 'Identity']

    def is_blake2_128(self):
        return self.index == 0

    def is_blake2_256(self):
        return self.index == 1

    def is_twoblake2_128_concat(self):
        return self.index == 2

    def is_twox128(self):
        return self.index == 3

    def is_twox256(self):
        return self.index == 4

    def is_twox64_concat(self):
        return self.index == 5

    def is_identity(self):
        return self.index == 6

class LockPeriods(U8):
    pass

class SessionKey(H256):
    pass

class PrefabWasmModule(Struct):
    type_string = 'wasm::PrefabWasmModule'

    type_mapping = (
        ('scheduleVersion', 'Compact<u32>'),
        ('initial', 'Compact<u32>'),
        ('maximum', 'Compact<u32>'),
        ('_reserved', 'Option<Null>'),
        ('code', 'Bytes'),
    )

class SessionKeysSubstrate(Struct):

    type_mapping = (
        ('grandpa', 'AccountId'),
        ('babe', 'AccountId'),
        ('im_online', 'AccountId'),
    )

class LegacyKeys(Struct):

    type_mapping = (
        ('grandpa', 'AccountId'),
        ('babe', 'AccountId'),
    )

class EdgewareKeys(Struct):
    type_mapping = (
        ('grandpa', 'AccountId'),
    )

class QueuedKeys(Struct):

    type_string = '(ValidatorId, Keys)'

    type_mapping = (
        ('validator', 'ValidatorId'),
        ('keys', 'Keys'),
    )

class LegacyQueuedKeys(Struct):

    type_string = '(ValidatorId, LegacyKeys)'

    type_mapping = (
        ('validator', 'ValidatorId'),
        ('keys', 'LegacyKeys'),
    )

class EdgewareQueuedKeys(Struct):

    type_string = '(ValidatorId, EdgewareKeys)'

    type_mapping = (
        ('validator', 'ValidatorId'),
        ('keys', 'EdgewareKeys'),
    )

class VecQueuedKeys(Vec):
    type_string = 'Vec<(ValidatorId, Keys)>'

    def process(self):
        element_count = self.process_type('Compact<u32>').value
        result = []
        for _ in range(0, element_count):
            element = self.process_type('QueuedKeys')
            self.elements.append(element)
            result.append(element.value)

        return result

class Conviction(Enum):
    CONVICTION_MASK = 0b01111111
    DEFAULT_CONVICTION = 0b00000000

    value_list = ['None', 'Locked1x', 'Locked2x', 'Locked3x', 'Locked4x', 'Locked5x', 'Locked6x']

class GenericBlock(ScaleType):
    # TODO implement generic block type

    def process(self):
        raise NotImplementedError()

    def process_encode(self, value):
        raise NotImplementedError()

class GenericVote(U8):
    pass

class GenericCall(ScaleType):

    type_string = "Box<Call>"

    def __init__(self, data, **kwargs):
        self.call_index = None
        self.call_function = None
        self.call_args = []
        self.call_module = None
        self.call_hash = None

        super().__init__(data, **kwargs)

    def process(self):

        self.call_index = self.get_next_bytes(2).hex()

        self.call_module, self.call_function = self.metadata.call_index[self.call_index]

        call_bytes = bytes.fromhex(self.call_index)

        for arg in self.call_function.args:
            arg_type_obj = self.process_type(arg.type, metadata=self.metadata)

            call_bytes += arg_type_obj.get_used_bytes()

            self.call_args.append({
                'name': arg.name,
                'type': arg.type,
                'value': arg_type_obj.serialize()
            })

        call_hash = blake2b(call_bytes, digest_size=32).digest()

        return {
            'call_index': f'0x{self.call_index}',
            'call_function': self.call_function.name,
            'call_module': self.call_module.name,
            'call_args': self.call_args,
            'call_hash': f'0x{call_hash.hex()}'
        }

    def process_encode(self, value):

        if type(value) is not dict:
            raise TypeError("value must be of type dict to encode a GenericCall")

        # Check requirements
        if 'call_index' in value:
            self.call_index = value['call_index']

        elif 'call_module' in value and 'call_function' in value:
            # Look up call module from metadata
            for call_index, (call_module, call_function) in self.metadata.call_index.items():

                if call_module.name == value['call_module'] and call_function.name == value['call_function']:
                    self.call_index = call_index
                    self.call_module = call_module
                    self.call_function = call_function
                    break

            if not self.call_index:
                raise MetadataCallFunctionNotFound(
                    f"Call function '{value['call_module']}.{value['call_function']}' not found in metadata"
                )

        elif not self.call_module or not self.call_function:
            raise ValueError('No call module and function specified')

        data = ScaleBytes(bytearray.fromhex(self.call_index))

        # Encode call params
        if len(self.call_function.args) > 0:
            for arg in self.call_function.args:
                if arg.name not in value['call_args']:
                    raise ValueError('Parameter \'{}\' not specified'.format(arg.name))
                else:
                    param_value = value['call_args'][arg.name]

                    arg_obj = self.get_decoder_class(
                        type_string=arg.type, metadata=self.metadata, runtime_config=self.runtime_config
                    )
                    data += arg_obj.encode(param_value)
        return data

class GenericContractExecResult(Enum):
    def __init__(self, data=None, contract_result_scale_type=None, **kwargs):
        self.contract_result_scale_type = contract_result_scale_type
        self.gas_consumed = None
        self.flags = None
        self.contract_result_data = None
        super().__init__(data, **kwargs)

    def process(self):
        value = super().process()
        self.process_contract_result()
        return value

    def process_contract_result(self):
        if 'success' in self.value:
            self.gas_consumed = self.value['success']['gas_consumed']
            self.flags = self.value['success']['flags']
            self.contract_result_data = self.value['success']['data']

    def process_encode(self, value):

        if self.contract_result_scale_type is None:
            raise ValueError("Encoding is not possible because 'contract_result_scale_type' is not set")

        if 'success' in value:
            value = {'Success': value['success']}
        return super().process_encode(value)

class OpaqueCall(Bytes):

    def process_encode(self, value):
        call_obj = self.get_decoder_class(
            type_string='Call', metadata=self.metadata, runtime_config=self.runtime_config
        )
        return super().process_encode(str(call_obj.encode(value)))

    def process(self):
        value = super().process()
        try:
            call_obj = self.get_decoder_class(
                type_string='Call',
                data=ScaleBytes('0x{}'.format(self.raw_value)),
                metadata=self.metadata,
                runtime_config=self.runtime_config
            )

            return call_obj.process()
        except:
            return value

class MultiAccountId(GenericAccountId):

    @classmethod
    def create_from_account_list(cls, accounts, threshold):
        from scalecodec.utils.ss58 import ss58_decode

        account_ids = []
        for account in accounts:
            if account[0:2] != '0x':
                account = '0x{}'.format(ss58_decode(account))
            account_ids.append(account)

        account_list_cls = cls.get_decoder_class('Vec<AccountId>', runtime_config=cls.runtime_config)
        account_list_data = account_list_cls.encode(sorted(account_ids))
        threshold_data = cls.get_decoder_class("u16").encode(threshold)

        multi_account_id = "0x{}".format(blake2b(
            b"modlpy/utilisuba" + bytes(account_list_data.data) + bytes(threshold_data.data), digest_size=32
        ).digest().hex())

        multi_account_obj = cls(runtime_config=cls.runtime_config)
        multi_account_obj.encode(multi_account_id)

        return multi_account_obj

class FixedLengthArray(ScaleType):

    element_count = 0

    def process(self):

        if self.element_count:
            if self.sub_type == 'u8':
                return '0x{}'.format(self.get_next_bytes(self.element_count).hex())
            else:
                result = []
                for idx in range(self.element_count):
                    result.append(self.process_type(self.sub_type).value)
        else:
            result = []

        return result

    def process_encode(self, value):
        data = ScaleBytes(bytearray())

        value = value or []

        if self.sub_type == 'u8':
            # u8 arrays are represented as hex-bytes (e.g. [u8; 3] as 0x123456)
            if value[0:2] != '0x' or len(value[2:]) != self.element_count * 2:
                raise ValueError('Value should start with "0x" and should be {} bytes long'.format(self.element_count))

            return ScaleBytes(value)

        else:

            if not type(value) is list:
                raise ValueError('Given value is not a list')

            for element_value in value:
                element_obj = self.get_decoder_class(
                    type_string=self.sub_type, metadata=self.metadata, runtime_config=self.runtime_config
                )
                data += element_obj.encode(element_value)

            return data

class GenericMultiAddress(Enum):
    type_mapping = [
        ["Id", "AccountId"],
        ["Index", "Compact<AccountIndex>"],
        ["Raw", "HexBytes"],
        ["Address32", "H256"],
        ["Address20", "H160"],
      ]

    def __init__(self, data, **kwargs):
        self.account_length = None
        self.account_id = None
        self.account_index = None
        self.account_idx = None
        super().__init__(data, **kwargs)

    def process(self):
        value = super().process()
        self.account_length = self.index
        if self.index == 0:
            value = list(value.values())[0]

            if is_valid_ss58_address(value):
                self.account_id = ss58_decode(value)
            elif value[0:2] == '0x':
                self.account_id = value[2:]

            return value
        elif self.index == 1:
            self.account_index = list(value.values())[0]
            return self.account_index
        else:
            # Todo cap HexBytes / zero pad to 32 bytes to keep compatibility with AccountId
            account_id = list(value.values())[0]
            self.account_id = account_id[2:66].ljust(64, '0')
            return value

    def process_encode(self, value):

        if type(value) is int:
            # Implied decoded AccountIndex
            value = {"Index": value}

        elif type(value) is str:
            if len(value) <= 8 and value[0:2] != '0x':
                # Implied raw AccountIndex
                value = {"Index": ss58_decode_account_index(value)}
            elif is_valid_ss58_address(value):
                # Implied SS58 encoded AccountId
                value = {"Id": f'0x{ss58_decode(value)}'}
            elif len(value) == 66 and value[0:2] == '0x':
                # Implied raw AccountId
                value = {"Id": value}
            elif len(value) == 42:
                # Implied raw Address20
                value = {"Address20": value}
            else:
                raise NotImplementedError("Address type not yet supported")

        return super().process_encode(value)

class Map(ScaleType):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.map_key, self.map_value = [x.strip() for x in self.sub_type.split(',')]

    def process(self):

        element_count = self.process_type('Compact<u32>').value

        result = []
        for _ in range(0, element_count):
            key_value = self.process_type(self.map_key, metadata=self.metadata).value
            result.append((key_value, self.process_type(self.map_value, metadata=self.metadata).value))

        return result

    def process_encode(self, value):

        if type(value) is not list:
            raise ValueError("value should be a list of tuples e.g.: [('1', 2), ('23', 24), ('28', 30), ('45', 80)]")

        element_count_compact = CompactU32()

        element_count_compact.encode(len(value))

        data = element_count_compact.data

        for item_key, item_value in value:
            key_obj = self.get_decoder_class(
                type_string=self.map_key, metadata=self.metadata, runtime_config=self.runtime_config
            )
            data += key_obj.encode(item_key)

            value_obj = self.get_decoder_class(
                type_string=self.map_value, metadata=self.metadata, runtime_config=self.runtime_config
            )
            data += value_obj.encode(item_value)

        return data

class HashMap(Map):
    pass

class BTreeMap(Map):
    pass

class BTreeSet(Vec):
    pass


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

# In[24]:

import gym
from gym import spaces
import gym_qch
import numpy as np
from numpy.random import randint
import networkx as nx

from qutip import *
from IPython.display import Image
from qutip.qip.operations import *
from qutip.qip.circuit import *
from qutip.qip.device import Processor
from qutip.qip.device import CircularSpinChain, LinearSpinChain
from qutip.qip.noise import RandomNoise
from qutip.operators import sigmaz, sigmay, sigmax, destroy
from qutip.states import basis
from qutip.metrics import fidelity
from qutip.qip.operations import rx, ry, rz, hadamard_transform

import copy
import MyGates as mg
import CircuitUtils as cu
import CircutEmbedding as ce

# In[120]:

class QubitHardwareEnv(gym.Env):
    metadata = {'render.modes': ['human']}
    movements = ['up', 'down', 'left', 'right']

    def __init__(self, height_grid, width_grid, width_circuit,current_position=None):

        """
        # Define action and observation space

        We will have two sub-actions:

        1. Apply a hadamard, apply a cnot, or apply a swap
        2. Move a pointer left, right, up, or down. This action is ignored on the
        first step because we apply a hadamard
        #can apply gates to from current possition and choose one

        #Instead of allowing the pointer to teleport anywhere it wants restrict it to moving one space in a direction from its current position

        """
        super(QubitHardwareEnv, self).__init__()
        self.trapped = False
        self.used_points = []
        self.num_cnots = 0
        self.time_step = 0
        self.movements = ['up', 'down', 'left', 'right']
        self.width_circuit = width_circuit
        self.height_grid = height_grid
        self.width_grid = width_grid
        self.gates_list = []

        if current_position != None:
            self.current_position = current_position
        else:
            self.current_position = None
        #self.previous_position = 0
        #create a noise dictionary to represent coherent noise in the hardware
        self.hardware = nx.generators.lattice.grid_2d_graph(self.height_grid, self.width_grid, create_using = nx.DiGraph)
        self.undirected_hardware = nx.generators.lattice.grid_2d_graph(self.height_grid, self.width_grid)
        self.noise_dict = ce.get_noise_dict(self.hardware,self.undirected_hardware)
        '''
        self.circuit_graph = 0
        self.circuit = 0
        '''
        #hardware = ce.relabel(hardware)
        self.num_qubits  = self.hardware.number_of_nodes()
        #self.gates_list = []
        self.adj_dict = {node:list(edges) for node,edges in dict(self.hardware.adj).items()}
        self.mapping = {i:j for i,j in enumerate(list(self.hardware.nodes))}

        self.gates = 3 #Hadamard, CNOT, SWAP

        self.action_space = spaces.Tuple([spaces.Discrete(len(self.movements)), spaces.Discrete(self.gates),spaces.Discrete(len(self.mapping))])
        self.observation_space = spaces.Box(low=0, high=1, shape = (self.num_qubits,self.num_qubits) ,dtype=np.float16)

    def step(self, action):
        #Gate actions for which gate to apply and which direction to apply that gate
        #print(action)
        direction, gate, initial_position = action
        self.previous_position = copy.copy(self.current_position)
        x,y = self._move(direction)
        done = False
        #print(initial_position)
        #Check if we are out of bounds, if we are end the episode

        #This makes is so that we only apply a Hadamard at the first time step. If we apply a different state,
        #end the episode and if we apply one after the first time step end the episode
        if self.time_step == 0:
            if gate == 0:
                self.current_position = self.mapping[initial_position.tolist()]
                self.used_points.append(self.current_position)
                self.apply_gate(gate)
                reward = self.avg_fidelity()
                self.time_step += 1
            elif gate > 0:
                done = True
                reward = 0
        elif self.time_step > 0:
            if gate == 0:
                done = True
                reward = 0
            elif gate > 0:
                #Use this to check if the circuit is trapped by itself. If so, end the episode
                if gate == 1:
                    self.num_cnots += 1

                if x >= self.width_grid or x < 0 or y >= self.height_grid or y < 0:
                    done = True
                    reward = 0
                #check if the action put us at a point which has already been passed over.
                #If so, end episode
                elif (x,y) in set(self.used_points):
                    done = True
                    reward = 0

                if not done:
                #Use this to check if the circuit is trapped by itself. If so, end the episode
                    p = 0
                    for adj_point in self.adj_dict[(x,y)]:
                        if adj_point in set(self.used_points):
                            p += 1

                    if len(self.adj_dict[(x,y)]) == p and self.num_cnots < (self.width_circuit - 1):
                            done = True
                            reward = 0

                    #Check if we are out of bounds, if we are end the episode

                if self.num_cnots < (self.width_circuit - 1) and not done:
                    self.current_position = x,y
                    self.used_points.append(self.current_position)
                    self.apply_gate(gate)
                    self.circuit = nx.convert_matrix.to_numpy_array(self.circuit_graph)
                    reward = self.avg_fidelity()
                    self.time_step += 1

        if self.num_cnots == (self.width_circuit - 1) and not done:
            self.current_position = x,y
            self.used_points.append(self.current_position)
            self.apply_gate(gate)
            self.circuit = nx.convert_matrix.to_numpy_array(self.circuit_graph)
            done = True
            reward = self._fidelity(self.gates_list, self.used_points)
        state =  nx.convert_matrix.to_numpy_array(self.circuit_graph)
        return state, reward, done, {}

    def avg_fidelity(self):
        target = 0
        avg_fidelity = 0

        while target < 10:
            current_cnots = copy.copy(self.num_cnots)
            current_gates_list = copy.copy(self.gates_list)
            current_used_points = copy.copy(self.used_points)
            current_point = copy.copy(self.current_position)
            done = False
            trapped = False
            #Need to consider case where it gets stuck in a corner or gets trapped by itself in general
            #print(current_gates_list)

            while not done:
                rand_gate = randint(1,3) # CNOT, SWAP
                rand_adj_point = self.adj_dict[current_point][randint(0,len(self.adj_dict[current_point]))]

                while rand_adj_point in set(current_used_points):
                    rand_adj_point = self.adj_dict[current_point][randint(0,len(self.adj_dict[current_point]))]

                current_point = rand_adj_point
                current_used_points.append(current_point)

                if rand_gate == 1:
                    current_cnots += 1
                    current_gates_list.append("CNOT")
                elif rand_gate == 2:
                    current_gates_list.append("SWAP")

                p = 0
                for adj_point in self.adj_dict[current_point]:
                    if adj_point in set(current_used_points):
                        p += 1
                if len(self.adj_dict[current_point]) == p and current_cnots < (self.width_circuit - 1) :
                    trapped = True
                    break

                if current_cnots == (self.width_circuit - 1):
                    done = True

            if not trapped:
                avg_fidelity += self._fidelity(current_gates_list, current_used_points)
                target += 1
                #print("target")
        return avg_fidelity/10

    def _fidelity(self, gates_list, used_points):
        num_qubits = len(used_points)
        q1 = QubitCircuit(num_qubits)
        q2 = QubitCircuit(num_qubits)
        #print(gates_list)
        q1.user_gates = {"UCNOT": mg.user_cnot, "RCNOT":mg.cnot_swap, "USWAP": mg.user_swap}
        q2.user_gates = {"UCNOT": mg.user_cnot, "RCNOT":mg.cnot_swap, "USWAP": mg.user_swap}
        edges = list(nx.utils.pairwise(used_points))
        #print(edges)

        i = 0
        for gate in gates_list:
            if gate == "H":
                q1.add_gate("SNOT",i)
                q2.add_gate("SNOT",i)

            elif gate == "CNOT":
                q1.add_gate("UCNOT",targets = [i,i+1 ], arg_value = 1)
                q2.add_gate("UCNOT",targets = [i, i+1 ], arg_value = self.noise_dict[edges[i]])
                i += 1

            elif gate == "SWAP":
                q1.add_gate("USWAP",targets = [i,i+1 ], arg_value = 1)
                q2.add_gate("USWAP",targets = [i,i+1], arg_value = self.noise_dict[edges[i]])
                i += 1
        #print(q1.gates)
        y = gate_sequence_product(q1.propagators())*tensor([basis(2,0)]*num_qubits)
        y2 = gate_sequence_product(q2.propagators())*tensor([basis(2,0)]*num_qubits)
        return fidelity(y,y2)

    def _move(self, direction):
        x, y = self.current_position
        if self.movements[direction] == 'up':
            y += 1
        elif self.movements[direction] == 'down':
            y -= 1
        elif self.movements[direction] == 'left':
            x -= 1
        else:
            x += 1
        return x,y

    def apply_gate(self, gate):
        if gate == 0:
            self.gates_list.append("H")

        if gate == 1:
            self.circuit_graph.add_edge(self.previous_position, self.current_position)
            self.gates_list.append("CNOT")

        if gate == 2:
            self.circuit_graph.add_edge(self.previous_position, self.current_position)
            self.gates_list.append("SWAP")

    def reset(self):
        self.trapped = False
        self.used_points = []
        self.num_cnots = 0
        self.time_step = 0
        if self.current_position == None:
            self.current_position = (randint(0, self.width_grid),randint(0, self.height_grid))
        self.circuit_graph = nx.DiGraph()
        self.circuit_graph.add_nodes_from(self.hardware)
        circuit = nx.convert_matrix.to_numpy_array(self.circuit_graph)
        self.circuit = circuit
        self.gates_list = []
        return circuit

    # Render the environment to the screen
    def render(self, mode='console'):
        print(self.mapping)
        print(self.current_position)
        print(self.used_points)
        print(self.circuit)

# In[131]:

'''
env = gym.make('qch-v0')
env = QubitHardwareEnv(3,3,3,(0,0))
print(env.hardware.nodes)
env.reset()
env.render()
#print(env.adj_dict)
#env.circuit_graph.add_edge((0,0),(1,0))
#print(nx.convert_matrix.to_numpy_array(env.circuit_graph))
movements = ['up', 'down', 'left', 'right']
print(env.current_position)
'''


import os
import numpy as np
import matplotlib.pyplot as pyplot
from simtk import unit
from foldamers.cg_model.cgmodel import CGModel
from foldamers.parameters.reweight import *
from foldamers.thermo.calc import calculate_heat_capacity
from foldamers.utilities.util import random_positions
from cg_openmm.build.cg_build import build_topology
from cg_openmm.simulation.rep_exch import *

grid_size = 4

# Job settings
top_directory = 'output'
if not os.path.exists(top_directory):
  os.mkdir(top_directory)
run_simulations = True

# OpenMM simulation settings
print_frequency = 5 # Number of steps to skip when printing output
total_simulation_time = 1.0 * unit.nanosecond # Units = picoseconds
simulation_time_step = 5.0 * unit.femtosecond
total_steps = round(total_simulation_time.__div__(simulation_time_step))

# Yank (replica exchange) simulation settings
output_data=str(str(top_directory)+"/output.nc")
number_replicas = 30
min_temp = 100.0 * unit.kelvin
max_temp = 350.0 * unit.kelvin
temperature_list = get_temperature_list(min_temp,max_temp,number_replicas)
print("Using "+str(len(temperature_list))+" replicas.")
if total_steps > 10000:
   exchange_attempts = round(total_steps/1000)
else:
   exchange_attempts = 10

###
#
# Coarse grained model settings
#
###

# Global definitions
polymer_length=8
backbone_lengths=[1]
sidechain_lengths=[1]
sidechain_positions=[0]
include_bond_forces=False
include_bond_angle_forces=True
include_nonbonded_forces=True
include_torsion_forces=True
constrain_bonds = True

# Particle properties
mass = 100.0 * unit.amu
masses = {'backbone_bead_masses': mass, 'sidechain_bead_masses': mass}

# Bonded interaction properties
bond_length = 7.5 * unit.angstrom
bond_lengths = {'bb_bb_bond_length': bond_length,'bb_sc_bond_length': bond_length,'sc_sc_bond_length': bond_length}
bond_force_constant = 1250 * unit.kilojoule_per_mole / unit.nanometer / unit.nanometer
bond_force_constants = {'bb_bb_bond_k': bond_force_constant, 'bb_sc_bond_k': bond_force_constant, 'sc_sc_bond_k': bond_force_constant}

# Bond angle properties
bond_angle_force_constant = 200 * unit.kilojoule_per_mole / unit.radian / unit.radian
bond_angle_force_constants = {'bb_bb_bb_angle_k': bond_angle_force_constant,'bb_bb_sc_angle_k': bond_angle_force_constant,'bb_sc_sc_angle_k': bond_angle_force_constant,'sc_sc_sc_angle_k': bond_angle_force_constant, 'sc_bb_sc_angle_k': bond_angle_force_constant, 'sc_sc_bb_angle_k': bond_angle_force_constant}
equil_bond_angle = 92
equil_bond_angles = {'bb_bb_bb_angle_0': equil_bond_angle,'bb_bb_sc_angle_0': 120}

# Torsion properties
torsion_force_constant = 200
torsion_force_constants = {'bb_bb_bb_bb_torsion_k': torsion_force_constant,'bb_bb_bb_sc_torsion_k': 0,'bb_bb_sc_sc_torsion_k': torsion_force_constant, 'bb_sc_sc_sc_torsion_k': torsion_force_constant, 'sc_bb_bb_sc_torsion_k': torsion_force_constant, 'bb_sc_sc_bb_torsion_k': torsion_force_constant, 'sc_sc_sc_sc_torsion_k': torsion_force_constant,  'sc_bb_bb_bb_torsion_k': torsion_force_constant}
equil_torsion_angle = 52
equil_torsion_angles = {'bb_bb_bb_bb_torsion_0': equil_torsion_angle,'bb_bb_bb_sc_torsion_0': equil_torsion_angle,'bb_bb_sc_sc_torsion_0': equil_torsion_angle, 'bb_sc_sc_sc_torsion_0': equil_torsion_angle, 'sc_bb_bb_sc_torsion_0': equil_torsion_angle, 'bb_sc_sc_bb_torsion_0': equil_torsion_angle, 'sc_sc_sc_sc_torsion_0': equil_torsion_angle, 'sc_bb_bb_bb_torsion_0': equil_torsion_angle}

file = open(str("Cv_data.dat"),"w")
file.write("Epsilon(kCal/mol) T(Kelvin) Cv(kCal/mol*Kelvin)\n")
file.close()

file = open(str("dCv_data.dat"),"w")
file.write("Epsilon(kCal/mol) T(Kelvin) dCv(kCal/mol*Kelvin)\n")
file.close()

C_v_list = []
dC_v_list = []
folding_T_list = []

sigma_list = [2.0 * bond_length]
#sigma_list = [ (1.5 + i*0.1) * bond_length for i in range(grid_size)]
epsilon_list = [ unit.Quantity((2.0 + i*0.25),unit.kilocalorie_per_mole) for i in range(grid_size)]
for sigma in sigma_list:
 for epsilon in epsilon_list:
  print("Performing simulations and heat capacity analysis for a coarse grained model")
  print("with sigma values of "+str(sigma)+" and epsilon values of "+str(epsilon))
  sigmas = {'bb_bb_sigma': sigma,'bb_sc_sigma': sigma,'sc_sc_sigma': sigma}
  epsilons = {'bb_bb_eps': epsilon,'bb_sc_eps': epsilon,'sc_sc_eps': epsilon}
  positions = PDBFile("pose_27.pdb").getPositions()
  cgmodel = CGModel(polymer_length=polymer_length,backbone_lengths=backbone_lengths,sidechain_lengths=sidechain_lengths,sidechain_positions=sidechain_positions,masses=masses,sigmas=sigmas,epsilons=epsilons,bond_lengths=bond_lengths,bond_force_constants=bond_force_constants,bond_angle_force_constants=bond_angle_force_constants,torsion_force_constants=torsion_force_constants,equil_bond_angles=equil_bond_angles,equil_torsion_angles=equil_torsion_angles,include_nonbonded_forces=include_nonbonded_forces,include_bond_forces=include_bond_forces,include_bond_angle_forces=include_bond_angle_forces,include_torsion_forces=include_torsion_forces,constrain_bonds=constrain_bonds,positions=positions)

  # Run a replica exchange simulation with this cgmodel
  output_data = str(str(top_directory)+"/sig_"+str(sigma._value)+"_eps_"+str(epsilon._value)+".nc")
#  if not os.path.exists:
#    print("Running simulations.")
  skip = False
  if not skip:
   success = False
   while not success:
    try:
     replica_energies,replica_positions,replica_states = run_replica_exchange(cgmodel.topology,cgmodel.system,cgmodel.positions,temperature_list=temperature_list,simulation_time_step=simulation_time_step,total_simulation_time=total_simulation_time,print_frequency=print_frequency,output_data=output_data)
     success = True
    except:
     cgmodel.positions = random_positions(cgmodel)
     print("Simulation attempt failed, retrying.")
#  else:
#    replica_energies,replica_positions,replica_states = read_replica_exchange_data(system=cgmodel.system,topology=cgmodel.topology,temperature_list=temperature_list,output_data=output_data,print_frequency=print_frequency)

   steps_per_stage = round(total_steps/exchange_attempts)
   plot_replica_exchange_energies(replica_energies,temperature_list,simulation_time_step,steps_per_stage=steps_per_stage)
   plot_replica_exchange_summary(replica_states,temperature_list,simulation_time_step,steps_per_stage=steps_per_stage)

  if skip:
   replica_energies,replica_positions,replica_states = read_replica_exchange_data(system=cgmodel.system,topology=cgmodel.topology,temperature_list=temperature_list,output_data=output_data,print_frequency=print_frequency)
  get_minimum_energy_pose(cgmodel.topology,replica_energies,replica_positions,file_name=str(str(top_directory)+"/sig_"+str(sigma._value)+"_eps_"+str(epsilon._value)+"_re_min.pdb"))
  make_replica_pdb_files(cgmodel.topology,replica_positions)

  num_intermediate_states = 1
  mbar,E_kn,E_expect,dE_expect,new_temp_list = get_mbar_expectation(replica_energies,temperature_list,num_intermediate_states)
  mbar,E_kn,DeltaE_expect,dDeltaE_expect,new_temp_list = get_mbar_expectation(E_kn,temperature_list,num_intermediate_states,mbar=mbar,output='differences')
  mbar,E_kn,E2_expect,dE2_expect,new_temp_list = get_mbar_expectation(E_kn**2,temperature_list,num_intermediate_states,mbar=mbar)
  df_ij,ddf_ij = get_free_energy_differences(mbar)
  C_v,dC_v = calculate_heat_capacity(E_expect,E2_expect,dE_expect,DeltaE_expect,dDeltaE_expect,df_ij,ddf_ij,new_temp_list,len(temperature_list),num_intermediate_states)
  C_v_list.append(C_v)
  dC_v_list.append(dC_v)
  folding_T_list.append(new_temp_list[np.argmax(C_v)])

  file = open(str("Cv_data.dat"),"a")
  for temp in range(len(new_temp_list)):
   file.write(str(round(epsilon._value,2))+" "+str(round(new_temp_list[temp],2))+" "+str(round(C_v[temp],4))+"\n")
  file.close
  file = open(str("dCv_data.dat"),"a")
  for temp in range(len(new_temp_list)):
   file.write(str(round(epsilon._value,2))+" "+str(round(new_temp_list[temp],2))+" "+str(round(dC_v[temp],4))+"\n")
  file.close

file_name = "heat_capacity.png"
figure = pyplot.figure(1)
original_temperature_list = np.array([temperature._value for temperature in temperature_list])
temperatures = np.array([temperature for temperature in new_temp_list])
legend_labels = [ str("$\epsilon$= "+str(round(epsilon._value,2))) for epsilon in epsilon_list]

for C_v,dC_v in zip(C_v_list,dC_v_list):
 C_v = np.array([C_v[i] for i in range(len(C_v))])
 dC_v = np.array([dC_v[i] for i in range(len(dC_v))])
 pyplot.errorbar(temperatures,C_v,yerr=dC_v,figure=figure)

pyplot.xlabel("Temperature ( Kelvin )")
pyplot.ylabel("C$_v$ ( kcal/mol * Kelvin )")
pyplot.title("Heat capacity for variable $\epsilon$")
pyplot.legend(legend_labels)
pyplot.savefig(file_name)
pyplot.show()
pyplot.close()

exit()


from django import forms

from .models import Hospital, Appointment
from doctor.models import Consult

class AppointmentForm(forms.ModelForm):
    class Meta:
        model=Appointment
        fields='__all__'
        widgets={
            'problem':forms.Select(attrs={'type':'text'}),
            'date':forms.DateInput(attrs={'type':'date'}),
            'report': forms.FileInput(attrs={'type':'file','class':'form-control','name':'report'}),
        }

class ConsultationForm(forms.ModelForm):
    class Meta:
        model=Consult
        fields=['username','useremail','doctorname','doctoremail','date','slot','report','problem']
        widgets={
            'problem':forms.TextInput(attrs={'type':'text'}),
            'slot':forms.Select(),
            'date':forms.DateInput(attrs={'type':'date'}),
            'report': forms.FileInput(attrs={'type':'file','name':'report'}),
        }


# version 0 works for the MIT experimental set up
# added output video with results
#
# Removed manual annotation from rat_video_segmentation_JAK1i_annotation
import numpy as np
import cv2
from common import nothing, clock, draw_str
import csv
import os
import pandas as pd
from scipy.signal import medfilt

MHI_DURATION = 1
MAX_TIME_DELTA = 0.5
MIN_TIME_DELTA = 0.05
THRESH_VALUE = 32

def video_results_annotation(videoName,featureCSVFileName, activities,df):
    cam = cv2.VideoCapture(videoName)
    video_len = cam.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT)
    ret, frame = cam.read()
    h, w = frame.shape[:2]

    hsv = np.zeros((h, w, 3), np.uint8)
    hsv[:,:,1] = 255

    fps = 15.0
    fourcc = cv2.cv.CV_FOURCC(*'XVID')

    outputVideoName = "C:\\PostDoctorProjects\VideoEEGData\\20150520_Cam4_Subject_5+6_stitched\\JAK1i_RecognitionResults.avi";
    VideoOutput = cv2.VideoWriter(outputVideoName,fourcc, fps, (w,h))

    ii = 0
    nrow,ncol = df.shape
    startFrame = int(df.loc[0,'iframe'])
    endFrame = int(df.loc[nrow-1,'iframe'])
    #cam.set(cv2.cv.CV_CAP_PROP_POS_FRAMES,ii)

    cam.set(cv2.cv.CV_CAP_PROP_POS_FRAMES,startFrame)

    COM_score = np.array(df['predict'])

    annotationColor = [(255,0,0),(0,255,0),(0,0,255)]
    for ii in range(endFrame-startFrame-1):
        ret, frame = cam.read()
        activityCOM = activities[int(COM_score[ii])]

        cv2.putText(frame, 'COM: '+ activityCOM, (255, 85),
        cv2.FONT_HERSHEY_SIMPLEX, 1.0, annotationColor[int(COM_score[ii])])
        cv2.imshow('Video',frame)
        VideoOutput.write(frame)

        if 0xff & cv2.waitKey(1) == 27:
            break

    cam.release()
    cv2.destroyAllWindows()

if __name__ == '__main__':

    activities = ['0','1-3','4-6']

    featureCSVFileName = 'C:\\PostDoctorProjects\VideoEEGData\\20150520_Cam4_Subject_5+6_stitched\\20150520_Cam4_Subject_5+6_08-20-04_stitched_features_predicted.csv'
    df = pd.read_csv(featureCSVFileName,header = False)

    testVideoName = 'C:\\PostDoctorProjects\VideoEEGData\\20150520_Cam4_Subject_5+6_stitched\\20150520_Cam4_Subject_5+6_08-20-04_stitched.avi'
    video_results_annotation(testVideoName,featureCSVFileName, activities,df)

'''
    for case in range(3,4):
        subFolderPath = folderRoot + '\\' + activities[case]

        videoNames = listdir(subFolderPath)
        actLens = [30,130,594,139,30,68,720,52]

        for ii in range(0,actLens[case]):
            testVideoName = subFolderPath +'\\'+ videoNames[ii]
            real_time_evaluation(testVideoName, featureWriter,classifier, activities, MIN_TIME_DELTA,MAX_TIME_DELTA,MHI_DURATION,THRESH_VALUE,True)
    fout.close()
'''


# -*- coding: utf-8 -*-
"""
Created on Sat May  9 17:23:28 2015

@author: Nicola
"""

from logentries import LogentriesHandler
import logging
from TwitterAPI import TwitterRestPager, TwitterAPI, TwitterRequestError
import couchdb
import time

# Logging setup
log = logging.getLogger('logentries')
log.setLevel(logging.WARN)
log.addHandler(LogentriesHandler(''))

# Twitter application's keys and tokens.
consumer_key = ''
consumer_secret = ''

access_token = ''
access_secret_token = ''

# Connection to CouchDB.
couch = couchdb.Server()

# Accessing 'twitter_raw_data' database.
db = couch['twitter_raw_data']

# Creating the list of languages we want to track by using
# the filter document on CouchDB.
languages = [lang for lang in couch['twitter_analyzed_data']['languagesFilter'].keys() if not lang.startswith('_')]
lang = " OR ".join(languages)

api = TwitterAPI(consumer_key,
                 consumer_secret,
                 access_token,
                 access_secret_token)

# Infinite cycle that gathers tweets using Twitter's REST API.
# The tweet are sent in groups of 100 and are saved on the database.
while True:
    try:
       start_time = time.time()
       r = TwitterRestPager(api, 'search/tweets', {'q':lang, 'count':100})
       for item in r.get_iterator():
           if 'text' in item:
               db.save(item)
    except TwitterRequestError as ex:
        # If we've exceeded the requests limit in the 15 minutes
        # windows the loop stops for the rest of the 15 minutes.
        sleep_time = 900 - (time.time() - start_time)
        log.warn('Request limit exceeded: %s\n' % item['message'])
        log.warn('Going to sleep for {0}s\n'.format(sleep_time))
        time.sleep(sleep_time)
        continue


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

import curses

screen = curses.initscr()
curses.noecho()
screen.border(0)
#screen.nodelay(1)#important to block some crap
screen.refresh()

#test window
extrawin = curses.newwin(10,10,0,0)
extrawin.addstr("testhere")
extrawin.border(0)
string = ''

#input window
inputwin = curses.newwin(10,20,20,20)
inputwin.border(0)
extrawin.refresh()
inputwin.refresh()
while True:

	c = screen.getch()
	if c in range(0,257) and len(string) < 18:
		string+=chr(c)
	if chr(c) == '\x7f':
		string = string[:-1]
	if chr(c)=='\n':
		extrawin.erase()
		extrawin.addstr(1,1,string)
		inputwin.erase()
		string = ''
	inputwin.addstr(1,1,string)
	inputwin.refresh()
	extrawin.refresh()
	inputwin.erase()
	inputwin.border(0)


import random
#imported random library
num = random.randint(1, 100)
count = 0
#created counter variable
#brouth out instructions
print(
    'Guess the number around 1-100: \n '
    'Print 0 for stop the game \n '
    '"very hot" - around 5 \n '
    '"hot" - around 10\n '
    '"cold" - around 30 \n '
    '"very cold - +30 or -30"'
)
#created while cycle for errors
while 1:
    try:
        tr = int(input("Print amount of attempts:  "))
        tr = int(tr)
        break
    except ValueError:
        print("Print only intiger numbers")

print("Let's play! \nPrint your number: ")
#created variable for count remaining attempts
s=tr
#launched while cycle
while count != tr:
    #added condition for errors
    try:
        guess = int(input())
    except ValueError:
        print("Print only intiger numbers")
        continue
    # added condition for exit programm
    if guess == 0:
        print("Program is finish\nThanks for playing my game!\n\n\n <|Made by Esen4iik|>")
        break
    # added condition if player win
    if guess == num:
        count += 1
        print(f'You win from {count} time \nThanks for playing my game!\n')
        # No comments)
        print("""░░█▀░░░░░░░░░░░▀▀███████░░░░
░░█▌░░░░░░░░░░░░░░░▀██████░░░
░█▌░░░░░░░░░░░░░░░░███████▌░░
░█░░░░░░░░░░░░░░░░░████████░░
▐▌░░░░░░░░░░░░░░░░░▀██████▌░░
░▌▄███▌░░░░▀████▄░░░░▀████▌░░
▐▀▀▄█▄░▌░░░▄██▄▄▄▀░░░░████▄▄░
▐░▀░░═▐░░░░░░══░░▀░░░░▐▀░▄▀▌▌
▐░░░░░▌░░░░░░░░░░░░░░░▀░▀░░▌▌
▐░░░▄▀░░░▀░▌░░░░░░░░░░░░▌█░▌▌
░▌░░▀▀▄▄▀▀▄▌▌░░░░░░░░░░▐░▀▐▐░
░▌░░▌░▄▄▄▄░░░▌░░░░░░░░▐░░▀▐░░
░█░▐▄██████▄░▐░░░░░░░░█▀▄▄▀░░
░▐░▌▌░░░░░░▀▀▄▐░░░░░░█▌░░░░░░
░░█░░▄▀▀▀▀▄░▄═╝▄░░░▄▀░▌░░░░░░
░░░▌▐░░░░░░▌░▀▀░░▄▀░░▐░░░░░░░
░░░▀▄░░░░░░░░░▄▀▀░░░░█░░░░░░░
░░░▄█▄▄▄▄▄▄▄▀▀░░░░░░░▌▌░░░░░░
░░▄▀▌▀▌░░░░░░░░░░░░░▄▀▀▄░░░░░
▄▀░░▌░▀▄░░░░░░░░░░▄▀░░▌░▀▄░░░
░░░░▌█▄▄▀▄░░░░░░▄▀░░░░▌░░░▌▄▄
░░░▄▐██████▄▄░▄▀░░▄▄▄▄▌░░░░▄░
░░▄▌████████▄▄▄███████▌░░░░░▄
░▄▀░██████████████████▌▀▄░░░░
▀░░░█████▀▀░░░▀███████░░░▀▄░░
░░░░▐█▀░░░▐░░░░░▀████▌░░░░▀▄░
░░░░░░▌░░░▐░░░░▐░░▀▀█░░░░░░░▀
░░░░░░▐░░░░▌░░░▐░░░░░▌░░░░░░░
░╔╗║░╔═╗░═╦═░░░░░╔╗░░╔═╗░╦═╗░
░║║║░║░║░░║░░░░░░╠╩╗░╠═╣░║░║░
░║╚╝░╚═╝░░║░░░░░░╚═╝░║░║░╩═╝░
\n\n\n <|Made by Esen4iik|>"""
        )
        break
    # added condition for hints
    elif guess <= num + 5 and guess >= num - 5:
        count += 1
        if guess < num:
            print("it's very hot, bigger")
        elif guess > num:
            print("it's very hot, lower")
    # added condition for hints
    elif guess <= num + 10 and guess >= num - 10:
        count += 1
        if guess < num:
            print("it's hot, bigger")
        elif guess > num:
            print("it's hot, lower")
    # added condition for hints
    elif guess <= num + 30 and guess >= num - 30:
        count += 1
        if guess < num:
            print("it's cold, bigger")
        elif guess > num:
            print("it's cold, lower")
    # added condition for hints
    elif guess < (num + 30) and guess > 0 or guess > (num + 30) and guess <= 100:
        count += 1
        if guess < num:
            print("it's very cold, bigger")
        elif guess > num:
            print("it's very cold, lower")
    # added condition if number bigger or lower then range
    else:
        print('Print namber into range')
    #print count remaining attempts
    s-=1
    print(f'You have {s} attempts')
# added condition if attempts ended
if count == tr:
    print(f'\nYour attempts is end\nThe target number was {num}\nThanks for playing my game!\n\n\n <|Made by Esen4iik|>')


#common

CATEGORY_PAGE = 'CATEGORY_PAGE'
SUB_CATEGORY_PAGE='SUB_CATEGORY_PAGE'
PDP_LIST_PAGE='PDP_LIST_PAGE'
PDP_PAGE = 'PDP_PAGE'
PAGINATED_LIST = 'PAGINATED_LIST'

#urls

SOURCE      = 'barneys'

URL         = 'https://www.barneys.com/sitemap?_ga=2.70540944.147060301.1520925905-2073211617.1520925905'

BASE_URL    = 'https://www.barneys.com'

CATEGORIES_GENDER_XPATHS  = [
                                {
                                    "GENDER": "WOMEN",
                                    "CATEGORY": "WOMENSWEAR",
                                    "XPATH": ".//*[@id='atg_store_content']/section/nav[2]/div/ul/ul/li/a/@href"
                                }, {
                                    "GENDER": "MEN",
                                    "CATEGORY": "MENSWEAR",
                                    "XPATH": ".//*[@id='atg_store_content']/section/nav[5]/div/ul/ul/li/a/@href"
                                }, {
                                    "GENDER": "KIDS",
                                    "CATEGORY": "KIDSWEAR",
                                    "XPATH": ".//*[@id='atg_store_content']/section/nav[7]/div/ul/ul/li/a/@href"
                                }
                            ]

PAGE_SIZE = 100

PRODUCT_BLOCK_XPATH = ".//*[contains(@class,'product-tile')]"

PRODUCT_URL_INSIDE_BLOCK_XPATH = ".//a[@class='thumb-link']/@href"

CATEGORY_XPATH = ".//div[@class='upper-breadcrumb']/div/a[last()]/text()"

BRAND_XPATH = ".//span[@id='fp-data']/@data-brand"

ARTICLETYPE_XPATH2 = ".//*[@id='pdp_breadcrumbs']/div/span[last()]/a/span/text()"

ARTICLETYPE_XPATH = ".//span[@id='fp-data']/@data-category"

CURRENCY_XPATH = ".//*[@itemprop='priceCurrency']/@content"

ITEM_COUNT_XPATH = ".//*[@id='resultsCount']/@data-productvalue"

PAGE_COUNT_XPATH = ".//select/@data-totalpagecount"

STYLENAME_XPATH = ".//span[@id='fp-data']/@data-productname"

DEFAULTIMAGE_XPATH = ".//span[@itemprop='image']/@content"

IMAGEURLLIST_XPATH = ".//figure/a/@data-zoom"

DESCRIPTION_XPATH= ".//*[@class='pdpReadMore']//text()"

COLOUR_XPATH = ".//span[@id='fp-data']/@data-color"

GENDER_XPATH = ".//div[@class='upper-breadcrumb']/div/a[1]/text()"

SIZES_XPATH = ".//*[@id='fp_availableSizes']/@value"

SELLING_PRICE_XPATH = ".//span[@id='fp-data']/@data-minprice"

MRP_XPATH = ".//span[@id='fp-data']/@data-maxprice"

STYLEID_XPATH = ".//span[@id='fp-data']/@data-productid"

SKU_PATH = ".//span[@itemprop='sku']/@content"

STOCK_XPATH = ".//*[@itemprop='availability']/@href"


import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K
from PIL import Image
from keras.models import load_model
import numpy as np
import h5py
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import random
import os

os.chdir(r'all')  # 跳转到训练集目录
import string
#
# # CHRS = string.ascii_lowercase + string.digits  # 字符列表
CHRS = string.ascii_lowercase  # 字符列表
#
num_classes = 26  # 共要识别36个字符（所有小写字母+数字），即36类
batch_size = 128
epochs = 12
#
# # 输入图片的尺寸
img_rows, img_cols = 12, 20
# # 根据keras的后端是TensorFlow还是Theano转换输入形式
if K.image_data_format() == 'channels_first':
    input_shape = (1, img_rows, img_cols)
else:
    input_shape = (img_rows, img_cols, 1)

import glob

X, Y = [], []
for f in glob.glob('*.png')[:]:  # 遍历当前目录下所有png后缀的图片

    t = 1.0 * np.array(Image.open(f))
    t = t.reshape(*input_shape)  # reshape后要赋值
    X.append(t)  # 验证码像素列表

    s = f.split('_')[0]  # 获取文件名中的验证码字符
    Y.append(CHRS.index(s))  # 将字符转换为相应的0-35数值

X = np.stack(X)  # 将列表转换为矩阵
Y = np.stack(Y)
# print("y:{}".format(Y))
# print("x:{}".format(X))
# 此时Y形式为 array([26, 27, 28, ..., 23, 24, 25])

# 对Y值进行one-hot编码 # 可尝试 keras.utils.to_categorical(np.array([0,1,1]), 3) 理解
Y = keras.utils.to_categorical(Y, num_classes)
print('lenY:{}'.format(len(Y)))
split_point = len(Y) - 36  # 简单地分割训练集与测试集
print('split_point:{}'.format(split_point))
x_train, y_train, x_test, y_test = X[:split_point], Y[:split_point], X[split_point:], Y[split_point:]

# 以下模型和mnist-cnn相同
# 两层3x3窗口的卷积(卷积核数为32和64)，一层最大池化(MaxPooling2D)
# 再Dropout(随机屏蔽部分神经元)并一维化(Flatten)到128个单元的全连接层(Dense)，最后Dropout输出到36个单元的全连接层（全部字符为36个）
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
                 activation='relu',
                 input_shape=input_shape))
model.add(Conv2D(64, (2, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(3, 3)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.25))
model.add(Dense(num_classes, activation='softmax'))

model.compile(loss=keras.losses.categorical_crossentropy,
              optimizer=keras.optimizers.Adadelta(),
              metrics=['accuracy'])

model.fit(x_train, y_train,
          batch_size=batch_size,
          epochs=epochs,
          verbose=1,
          validation_data=(x_test, y_test))
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
model.save(r'E:\python\2017_9\model_test.h5')


__author__ = 'tingxxu'

import random
from commonstring import *
import time
from manager import manager
import json

class Application:
    def __init__(self):
        self.__speed = 0
        self.__speed_update_time = 0
        self.__acceleration = 0
        self.__fuel = 100
        self.__throttle = 57
        self.__distance = 0
        self.__engine_rpm = 0
        self.__longitude = {value_str: 0, stay_minutes_str: 0, stay_seconds_str: 0}
        self.__latitude = {value_str: 0, stay_minutes_str: 0, stay_seconds_str: 0}

        self.__diagnostic = self.get_diagnotic_data()

        self.__actions = {}
        self.__init_actions()

        self.__receivers = {}
        self.__init_receivers()

        self.speedToAccelerationRatio = 0.28

    def __init_receivers(self):
        self.__receivers[12] = self.receive_engine_rpm
        self.__receivers[13] = self.receive_speed
        self.__receivers[17] = self.receive_throttle
        self.__receivers[47] = self.receive_fuel
        self.__longitude[161] = self.receive_longitude
        self.__longitude[162] = self.receive_latitude

    def __init_actions(self):
        self.__actions[speed_str] = self.get_speed
        self.__actions[engine_str] = self.get_engine_rpm
        self.__actions[fuel_str] = self.get_fuel
        self.__actions[throttle_str] = self.get_throttle
        self.__actions[distance_str] = self.get_distance
        self.__actions[stop_str] = self.get_stops
        self.__actions[acceleration_str] = self.get_acceleration

    def receive(self, data):
        json_data = json.loads(data)
        if json_data["status"] == "ok":
            responses = json_data["responses"]
            keys = self.__receivers.keys()
            # from 1970-01-01 00:00:00
            time_seconds = time.time()
            for pid_item in responses:
                pid = pid_item["pid"]
                if pid in keys:
                    self.__receivers[pid](time_seconds, pid_item["data"])

    def get_data(self, key):
        if key is not None:
            if key in self.__actions:
                return self.__actions[key]()
            else:
                return None

    def get_data_in_keys(self, keys):
        result = {}
        for key in keys:
            if key in self.__actions:
                result[key] = self.__actions[key]()
        return result

    def get_diagnostics(self):
        return self.__diagnostic

    def get_diagnotic_data(self):
        result = []

        engine_status = {}
        engine_status["title"] = "David"
        engine_status["level"] = random.randint(3, 5)

        fuel_system_status = {}
        fuel_system_status["title"] = "Nermeen"
        fuel_system_status["level"] = random.randint(3, 5)

        brake_status = {}
        brake_status["title"] = "Jack"
        brake_status["level"] = random.randint(3, 5)

        tire_status = {}
        tire_status["title"] = "Edwin"
        tire_status["level"] = random.randint(3, 5)

        result.append(engine_status)
        result.append(fuel_system_status)
        result.append(brake_status)
        result.append(tire_status)
        return result

    def get_all(self):
        result = {}
        for key in self.__actions:
            result[key] = self.__actions[key]()

        return result

    def get_speed(self):
        return self.__speed

    def get_acceleration(self):
        return self.__acceleration

    def get_engine_rpm(self):
        return self.__engine_rpm

    def get_fuel(self):
        return self.__fuel

    def get_throttle(self):
        return self.__throttle

    def get_distance(self):
        return self.__distance

    def get_position(self):
        pass

    def get_coordinates(self):
        pass

    def get_stops(self):
        stops = []

        stop1 ={}
        stop1["time"] = "2:30 PM"
        stop1["stayTime"] = "5 minutes"
        stop1["x"] = 100
        stop1["y"] = 18

        stops.append(stop1)

        stop2 ={}
        stop2["time"] = "2:50 PM"
        stop2["stayTime"] = "6 minutes"
        stop2["x"] = 105
        stop2["y"] = 300

        stops.append(stop2)

        stop3 ={}
        stop3["time"] = "3:10 PM"
        stop3["stayTime"] = "1 minutes"
        stop3["x"] = 150
        stop3["y"] = 490

        stops.append(stop3)

        stop4 ={}
        stop4["time"] = "3:30 PM"
        stop4["stayTime"] = "2 minutes"
        stop4["x"] = 200
        stop4["y"] = 12

        stops.append(stop4)

        result ={}
        result[value_str] = stops
        return result

        return

    def get_history(self, keys, seconds):
        result = manager.get_history(keys, seconds)
        return result

    def get_speed_history(self, before_seconds):
        pass

    def get_engine_rpm_history(self):
        pass

    def get_fuel_history(self):
        pass

    def get_throttle_history(self):
        pass

    def get_position_history(self):
        pass

    def get_distance_history(self):
        pass

    def get_coordinates_history(self):
        pass

    # https://en.wikipedia.org/wiki/OBD-II_PIDs
    def receive_engine_rpm(self, time_seconds, data):
        param_a = data[0]
        param_b = data[1]
        rpm = (param_a*256 + param_b)/4
        self.__engine_rpm = rpm
        manager.save_engine_rpm(time_seconds, rpm)

    def receive_speed(self, time_seconds, data):
        param_a = data[0]
        speed = param_a

        manager.save_speed(time_seconds, speed)

        self.__acceleration = (speed - self.__speed)/(time_seconds - self.__speed_update_time)
        manager.save_acceleration(time_seconds, self.__acceleration)

        self.__speed = speed
        self.__speed_update_time = time_seconds

    def receive_throttle(self, time_seconds, data):
        param_a = data[0]
        throttle = param_a * 100 / 255
        self.__throttle = throttle
        manager.save_throttle(time_seconds, throttle)

    def receive_fuel(self, time_seconds, data):
        param_a = data[0]
        fuel = param_a * 100 / 255
        self.__fuel = fuel
        manager.save_fuel(time_seconds, fuel)

    def receive_longitude(self, time_seconds, data):

        degrees = data[0]
        minutes = data[1]
        seconds = data[2]
        self.__longitude = {value_str: degrees, stay_minutes_str: minutes, stay_seconds_str: seconds}
        manager.save_longitude(time_seconds, degrees, minutes, seconds)

    def receive_latitude(self, time_seconds, data):
        degrees = data[0]
        minutes = data[1]
        seconds = data[2]
        self.__longitude = {value_str: degrees, stay_minutes_str: minutes, stay_seconds_str: seconds}
        manager.save_latitude(time_seconds, degrees, minutes, seconds)


import random
from random import choice
import requests
from Modules.menu.colors import *
from Modules.menu.obj.proxies import prowork
from Modules.menu.obj.useragentgen import useragentgen
from Modules.menu.err import *
import json

debug = open("conf.json",'r').read()
debugmode = json.loads(debug)
de = debugmode['debugmode']
if de == "True":
   debugging = "True"
else:
   debugging = "False"

siteheaders =[
  'X-Frame-Options',
  'X-Content-Type-Options',
  'Strict-Transport-Security',
  'Content-Security-Policy',
  'X-Permitted-Cross-Domain-Policies',
  'X-XSS-Protection',
  'Referrer-Policy',
  'Feature-Policy',
  'Permissions-Policy',
  'Clear-Site-Data',
  'Public-Key-Pins',
  'Expect-CT',
  'Cross-Origin-Embedder-Policy',
  'Cross-Origin-Opener-Policy',
  'Cross-Origin-Resource-Policy',
]

def siteheaderscanner(target,proxy):
    print(f"\n  {yellow}[ {gray}• {yellow}]{reset} Looking For Security Headers...\n")
    while True:
                try:
                   if proxy == "True":
                      proxyip = prowork()
                      ua = useragentgen()
                      print(f"{yellow}  [ {yellow}• {yellow}]{reset} {blue}► {reset}Using proxy {yellow}{proxyip}{reset}")
                      print(f"{yellow}  [ {yellow}• {yellow}]{reset} {blue}► {reset}Using Useragent {yellow}{ua}{reset}\n")
                      exploitsite = requests.get(target,proxies={"http": f"{proxyip}"}, headers=ua, timeout = 4).headers
                      amountfound = 0
                      amountinsecure = 0
                      for header in siteheaders:
                         if header in exploitsite:
                              amountfound +=1
                              print(f"{yellow}  [ {green}• {yellow}]  {blue}200,{reset} HEADER FOUND: {yellow}{header}{reset}")
                         else:
                              amountinsecure +=1
                              print(f"{yellow}  [ {red}• {yellow}]  {blue}403,{reset} {reset}MISSING: {yellow}{header}")
                      if amountfound == 0:
                         print(f"{Warnings.noheaders}")
                   else:
                      exploitsite = requests.get(target, timeout = 4).headers
                      amountfound = 0
                      amountinsecure = 0
                      for header in siteheaders:
                         if header in exploitsite:
                              amountfound +=1
                              print(f"{yellow}  [ {green}• {yellow}]  {blue}200,{reset} HEADER FOUND: {yellow}{header}{reset}")
                         else:
                              amountinsecure +=1
                              print(f"{yellow}  [ {red}• {yellow}]  {blue}403,{reset} {reset}MISSING: {yellow}{header}")
                      if amountfound == 0:
                         print(f"{Warnings.noheaders}")
                   break
                except:
                   if debugging == "True":
                      print(f"{yellow}  [ {red}• {yellow}] {red}Proxy Timed Out Switching Server...{reset}")
                   proxyip = prowork()
                   ua = useragentgen()
                   pass


from django.urls import path

from core import views

app_name = 'core'

urlpatterns = [
    path('', views.index, name='index'),
    path('upload/', views.xml_upload, name='upload'),
    path('process/', views.process_files, name='process'),
]


# Definition for a binary tree node.
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
    def findFrequentTreeSum(self, root: TreeNode) -> List[int]:
        mp = {}

        def bfs(root: TreeNode) -> int:
            if not root:
                return 0
            result = root.val + bfs(root.left) + bfs(root.right)
            if result in mp:
                mp[result] += 1
            else:
                mp[result] = 1
            return result
        bfs(root)
        result = []
        maxnum = 0
        for m in mp:
            if mp[m] == maxnum:
                result.append(m)
            elif mp[m] > maxnum:
                result = []
                result.append(m)
                maxnum = mp[m]
        return result


### 1620 나는야 포켓몬 마스터 이다솜
### https://www.acmicpc.net/problem/1620
import sys
N, M = list(map(int, (sys.stdin.readline().split())))
dokam = {}
for i in range(N):
    dokam[sys.stdin.readline().strip()] = i+1
reverseDokam = {value:key for key, value in dokam.items()}
for j in range(M):
    Minput = sys.stdin.readline().strip()
    if Minput in dokam.keys():
        print(dokam.get(Minput))
    else:
        print(reverseDokam.get(int(Minput)))