# Copyright 2019 Intel Corporation
#
# 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 binascii
import logging
from os import environ

from utility.hex_utils import is_valid_hex_str

from avalon_client_sdk.utility.tcf_types import WorkerStatus, WorkerType
from avalon_client_sdk.ethereum.ethereum_wrapper import EthereumWrapper
from avalon_client_sdk.interfaces.worker_registry_client \
    import WorkerRegistryClient
from avalon_client_sdk.utility.utils import construct_message, validate_details

logging.basicConfig(
    format="%(asctime)s - %(levelname)s - %(message)s", level=logging.INFO)


class EthereumWorkerRegistryImpl(WorkerRegistryClient):
    """
    This class is to read workers from Ethereum blockchain.
    Detail method description will be available in interface
    """

    def __init__(self, config):
        if self.__validate(config) is True:
            self.__initialize(config)
        else:
            raise Exception("Invalid configuration parameter")

    def worker_lookup(self, worker_type, org_id, application_id):
        """
        Lookup a worker identified worker_type, org_id and application_id
        all fields are optional and if present condition should match for all
        fields. If none passed it should return all workers.
        """
        if (self.__contract_instance is not None):
            if not isinstance(worker_type, WorkerType):
                logging.info("Invalid workerType {}".format(worker_type))
                return construct_message(
                    "failed", "Invalid workerType {}".format(worker_type))
            if not is_valid_hex_str(binascii.hexlify(org_id).decode("utf8")):
                logging.info("Invalid organization id {}".format(org_id))
                return construct_message(
                    "failed", "Invalid organization id {}".format(org_id))
            if not is_valid_hex_str(
                    binascii.hexlify(application_id).decode("utf8")):
                logging.info(
                    "Invalid application id {}".format(application_id))
                return construct_message(
                    "failed",
                    "Invalid application id {}".format(application_id))
            lookupResult = self.__contract_instance.functions.workerLookUp(
                worker_type.value, org_id, application_id).call()
            return lookupResult
        else:
            logging.error(
                "worker registry contract instance is not initialized")
            return construct_message(
                "failed",
                "worker registry contract instance is not initialized")

    def worker_retrieve(self, worker_id):
        """
        Retrieve the worker identified by worker id
        """
        if (self.__contract_instance is not None):
            if not is_valid_hex_str(binascii.hexlify(
                    worker_id).decode("utf8")):
                logging.info("Invalid worker id {}".format(worker_id))
                return construct_message(
                    "failed", "Invalid worker id {}".format(worker_id))

            workerDetails = self.__contract_instance.functions.workerRetrieve(
                worker_id).call()
            return workerDetails
        else:
            logging.error(
                "worker registry contract instance is not initialized")
            return construct_message(
                "failed",
                "worker registry contract instance is not initialized")

    def worker_lookup_next(self, worker_type, org_id, application_id,
                           lookup_tag):
        if (self.__contract_instance is not None):
            if not isinstance(worker_type, WorkerType):
                logging.info("Invalid workerType {}".format(worker_type))
                return construct_message(
                    "failed", "Invalid workerType {}".format(worker_type))
            if not is_valid_hex_str(binascii.hexlify(org_id).decode("utf")):
                logging.info("Invalid organization id {}".format(org_id))
                return construct_message(
                    "failed", "Invalid organization id {}".format(org_id))
            if not is_valid_hex_str(
                    binascii.hexlify(application_id).decode("utf8")):
                logging.info("Invalid application id {}".format(org_id))
                return construct_message(
                    "failed", "Invalid application id {}".format(org_id))
            lookupResult = self.__contract_instance.functions.workerLookUpNext(
                worker_type.value,
                org_id, application_id, lookup_tag).call()
            return lookupResult
        else:
            logging.error(
                "worker registry contract instance is not initialized")
            return construct_message("failed", "worker registry contract instance \
                is not initialized")

    def __validate(self, config):
        """
        validates parameter from config parameters for existence.
        Returns false if validation fails and true if it success
        """
        if config["ethereum"]["worker_registry_contract_file"] is None:
            logging.error("Missing worker registry contract file path!!")
            return False
        if config["ethereum"]["worker_registry_contract_address"] is None:
            logging.error("Missing worker registry contract address!!")
            return False
        return True

    def __initialize(self, config):
        """
        Initialize the parameters from config to instance variables.
        """
        self.__eth_client = EthereumWrapper(config)
        tcf_home = environ.get("TCF_HOME", "../../../")
        contract_file_name = tcf_home + "/" + \
            config["ethereum"]["worker_registry_contract_file"]
        contract_address = \
            config["ethereum"]["worker_registry_contract_address"]
        self.__contract_instance = self.__eth_client.get_contract_instance(
            contract_file_name, contract_address
        )

# Copyright 2019 Intel Corporation
#
# 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 binascii
import logging
from os import environ

from utility.hex_utils import is_valid_hex_str

from avalon_client_sdk.utility.tcf_types import WorkerStatus, WorkerType
from avalon_client_sdk.ethereum.ethereum_wrapper import EthereumWrapper
from avalon_client_sdk.interfaces.worker_registry_client \
    import WorkerRegistryClient
from avalon_client_sdk.utility.utils import construct_message, validate_details

logging.basicConfig(
    format="%(asctime)s - %(levelname)s - %(message)s", level=logging.INFO)


class EthereumWorkerRegistryImpl(WorkerRegistryClient):
    """
    This class is to read workers from Ethereum blockchain.
    Detail method description will be available in interface
    """

    def __init__(self, config):
        if self.__validate(config) is True:
            self.__initialize(config)
        else:
            raise Exception("Invalid configuration parameter")

    def worker_lookup(self, worker_type, org_id, application_id):
        """
        Lookup a worker identified worker_type, org_id and application_id
        all fields are optional and if present condition should match for all
        fields. If none passed it should return all workers.
        """
        if (self.__contract_instance is not None):
            if not isinstance(worker_type, WorkerType):
                logging.info("Invalid workerType {}".format(worker_type))
                return construct_message(
                    "failed", "Invalid workerType {}".format(worker_type))
            if not is_valid_hex_str(binascii.hexlify(org_id).decode("utf8")):
                logging.info("Invalid organization id {}".format(org_id))
                return construct_message(
                    "failed", "Invalid organization id {}".format(org_id))
            if not is_valid_hex_str(
                    binascii.hexlify(application_id).decode("utf8")):
                logging.info(
                    "Invalid application id {}".format(application_id))
                return construct_message(
                    "failed",
                    "Invalid application id {}".format(application_id))
            lookupResult = self.__contract_instance.functions.workerLookUp(
                worker_type.value, org_id, application_id).call()
            return lookupResult
        else:
            logging.error(
                "worker registry contract instance is not initialized")
            return construct_message(
                "failed",
                "worker registry contract instance is not initialized")

    def worker_retrieve(self, worker_id):
        """
        Retrieve the worker identified by worker id
        """
        if (self.__contract_instance is not None):
            if not is_valid_hex_str(binascii.hexlify(
                    worker_id).decode("utf8")):
                logging.info("Invalid worker id {}".format(worker_id))
                return construct_message(
                    "failed", "Invalid worker id {}".format(worker_id))

            workerDetails = self.__contract_instance.functions.workerRetrieve(
                worker_id).call()
            return workerDetails
        else:
            logging.error(
                "worker registry contract instance is not initialized")
            return construct_message(
                "failed",
                "worker registry contract instance is not initialized")

    def worker_lookup_next(self, worker_type, org_id, application_id,
                           lookup_tag):
        if (self.__contract_instance is not None):
            if not isinstance(worker_type, WorkerType):
                logging.info("Invalid workerType {}".format(worker_type))
                return construct_message(
                    "failed", "Invalid workerType {}".format(worker_type))
            if not is_valid_hex_str(binascii.hexlify(org_id).decode("utf")):
                logging.info("Invalid organization id {}".format(org_id))
                return construct_message(
                    "failed", "Invalid organization id {}".format(org_id))
            if not is_valid_hex_str(
                    binascii.hexlify(application_id).decode("utf8")):
                logging.info("Invalid application id {}".format(org_id))
                return construct_message(
                    "failed", "Invalid application id {}".format(org_id))
            lookupResult = self.__contract_instance.functions.workerLookUpNext(
                worker_type.value,
                org_id, application_id, lookup_tag).call()
            return lookupResult
        else:
            logging.error(
                "worker registry contract instance is not initialized")
            return construct_message("failed", "worker registry contract instance \
                is not initialized")

    def __validate(self, config):
        """
        validates parameter from config parameters for existence.
        Returns false if validation fails and true if it success
        """
        if config["ethereum"]["worker_registry_contract_file"] is None:
            logging.error("Missing worker registry contract file path!!")
            return False
        if config["ethereum"]["worker_registry_contract_address"] is None:
            logging.error("Missing worker registry contract address!!")
            return False
        return True

    def __initialize(self, config):
        """
        Initialize the parameters from config to instance variables.
        """
        self.__eth_client = EthereumWrapper(config)
        tcf_home = environ.get("TCF_HOME", "../../../")
        contract_file_name = tcf_home + "/" + \
            config["ethereum"]["worker_registry_contract_file"]
        contract_address = \
            config["ethereum"]["worker_registry_contract_address"]
        self.__contract_instance = self.__eth_client.get_contract_instance(
            contract_file_name, contract_address
        )

# Copyright 2019 Intel Corporation # # 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. This class is to read workers from Ethereum blockchain.     Detail method description will be available in interface Lookup a worker identified worker_type, org_id and application_id         all fields are optional and if present condition should match for all         fields. If none passed it should return all workers. Retrieve the worker identified by worker id validates parameter from config parameters for existence.         Returns false if validation fails and true if it success Initialize the parameters from config to instance variables.