import json
import os

from .base_config import BaseConfig


class DiceboxConfig(BaseConfig):

    def __init__(self, config_file: str = 'dicebox.config'):
        super().__init__(config_file=config_file)

        ###############################################################################
        # Data Set Options
        ###############################################################################

        # Load user defined config
        if 'DATASET' in os.environ:
            self.DATASET = os.environ['DATASET']

        if 'DICEBOX_COMPLIANT_DATASET' in os.environ:
            if os.environ['DICEBOX_COMPLIANT_DATASET'] == 'True':
                self.DICEBOX_COMPLIANT_DATASET = True
            elif os.environ['DICEBOX_COMPLIANT_DATASET'] == 'False':
                self.DICEBOX_COMPLIANT_DATASET = False
            else:
                raise

        if 'NB_CLASSES' in os.environ:
            self.NB_CLASSES = int(os.environ['NB_CLASSES'])

        if 'IMAGE_WIDTH' in os.environ:
            self.IMAGE_WIDTH = int(os.environ['IMAGE_WIDTH'])

        if 'IMAGE_HEIGHT' in os.environ:
            self.IMAGE_HEIGHT = int(os.environ['IMAGE_HEIGHT'])

        if 'DATA_BASE_DIRECTORY' in os.environ:
            self.DATA_BASE_DIRECTORY = os.environ['DATA_BASE_DIRECTORY']

        ###############################################################################
        # Build Calculated Configs
        ###############################################################################
        self.NETWORK_NAME = "%s_%ix%i" % (self.DATASET, self.IMAGE_WIDTH, self.IMAGE_HEIGHT)
        self.INPUT_SHAPE = (self.IMAGE_WIDTH, self.IMAGE_HEIGHT, 3)  # 3 indicates the number of channels (RGB) so 3.
        self.DATA_DIRECTORY = "%s/%s/data/" % (self.DATA_BASE_DIRECTORY, self.NETWORK_NAME)

        ###############################################################################
        # Neural Network Taxonomy Options
        ###############################################################################
        if 'MIN_NEURONS' in os.environ:
            self.MIN_NEURONS = int(os.environ['MIN_NEURONS'])

        if 'MAX_NEURONS' in os.environ:
            self.MAX_NEURONS = int(os.environ['MAX_NEURONS'])

        if 'MIN_LAYERS' in os.environ:
            self.MIN_LAYERS = int(os.environ['MIN_LAYERS'])

        if 'MAX_LAYERS' in os.environ:
            self.MAX_LAYERS = int(os.environ['MAX_LAYERS'])

        if 'LAYER_TYPES' in os.environ:
            self.LAYER_TYPES = os.environ['LAYER_TYPES']

        if 'ACTIVATION' in os.environ:
            self.ACTIVATION = os.environ['ACTIVATION']

        if 'OPTIMIZER' in os.environ:
            self.OPTIMIZER = os.environ['OPTIMIZER']

        self.TAXONOMY = {
            'min_neurons': self.MIN_NEURONS,
            'max_neurons': self.MAX_NEURONS,
            'min_layers': self.MIN_LAYERS,
            'max_layers': self.MAX_LAYERS,
            'layer_types': json.loads(self.LAYER_TYPES),
            'activation': json.loads(self.ACTIVATION),
            'optimizer': json.loads(self.OPTIMIZER)
        }

        ###############################################################################
        # Evolution Options
        ###############################################################################
        if 'EPOCHS' in os.environ:
            self.EPOCHS = int(os.environ['EPOCHS'])

        # Number of times to evolve the population.
        if 'GENERATIONS' in os.environ:
            self.GENERATIONS = int(os.environ['GENERATIONS'])

        # Number of networks in each generation.
        if 'POPULATION' in os.environ:
            self.POPULATION = int(os.environ['POPULATION'])

        if 'NOISE' in os.environ:
            self.NOISE = float(os.environ['NOISE'])

        ###############################################################################
        # Training Options / Settings for the 1920x1080 dataset
        ###############################################################################
        if 'BATCH_SIZE' in os.environ:
            self.BATCH_SIZE = int(os.environ['BATCH_SIZE'])

        if 'TRAIN_BATCH_SIZE' in os.environ:
            self.TRAIN_BATCH_SIZE = int(os.environ['TRAIN_BATCH_SIZE'])

        if 'TEST_BATCH_SIZE' in os.environ:
            self.TEST_BATCH_SIZE = int(os.environ['TEST_BATCH_SIZE'])

        if 'LOAD_BEST_WEIGHTS_ON_START' in os.environ:
            if os.environ['LOAD_BEST_WEIGHTS_ON_START'] == 'False':
                self.LOAD_BEST_WEIGHTS_ON_START = False
            elif os.environ['LOAD_BEST_WEIGHTS_ON_START'] == 'True':
                self.LOAD_BEST_WEIGHTS_ON_START = True
            else:
                raise

        ###############################################################################
        # Direcrtory Options
        ###############################################################################
        if 'LOGS_DIR' in os.environ:
            self.LOGS_DIR = os.environ['LOGS_DIR']

        if 'WEIGHTS_DIR' in os.environ:
            self.WEIGHTS_DIR = os.environ['WEIGHTS_DIR']

        if 'TMP_DIR' in os.environ:
            self.TMP_DIR = os.environ['TMP_DIR']

        if 'POPULATION_DIR' in os.environ:
            self.POPULATION_DIR = os.environ['POPULATION_DIR']

        ###############################################################################
        # Server Options
        ###############################################################################
        if 'API_ACCESS_KEY' in os.environ:
            self.API_ACCESS_KEY = os.environ['API_ACCESS_KEY']

        if 'API_VERSION' in os.environ:
            self.API_VERSION = os.environ['API_VERSION']

        if 'LISTENING_HOST' in os.environ:
            self.LISTENING_HOST = os.environ['LISTENING_HOST']

        if 'FLASK_DEBUG' in os.environ:
            if os.environ['FLASK_DEBUG'] == 'True':
                self.FLASK_DEBUG = True
            elif os.environ['FLASK_DEBUG'] == 'False':
                self.FLASK_DEBUG = False
            else:
                raise

        if 'MODEL_WEIGHTS_FILENAME' in os.environ:
            self.MODEL_WEIGHTS_FILENAME = os.environ['MODEL_WEIGHTS_FILENAME']

        ###############################################################################
        # Sensory Service Options
        ###############################################################################
        if 'SENSORY_SERVER' in os.environ:
            self.SENSORY_SERVER = os.environ['SENSORY_SERVER']

        if 'SENSORY_PORT' in os.environ:
            self.SENSORY_PORT = int(os.environ['SENSORY_PORT'])

        if 'SENSORY_URI' in os.environ:
            self.SENSORY_URI = os.environ['SENSORY_URI']

        if 'SENSORY_SERVICE_RABBITMQ_EXCHANGE' in os.environ:
            self.SENSORY_SERVICE_RABBITMQ_EXCHANGE = os.environ['SENSORY_SERVICE_RABBITMQ_EXCHANGE']

        if 'SENSORY_SERVICE_RABBITMQ_BATCH_REQUEST_ROUTING_KEY' in os.environ:
            self.SENSORY_SERVICE_RABBITMQ_BATCH_REQUEST_ROUTING_KEY = os.environ[
                'SENSORY_SERVICE_RABBITMQ_BATCH_REQUEST_ROUTING_KEY']

        if 'SENSORY_SERVICE_RABBITMQ_BATCH_REQUEST_TASK_QUEUE' in os.environ:
            self.SENSORY_SERVICE_RABBITMQ_BATCH_REQUEST_TASK_QUEUE = os.environ[
                'SENSORY_SERVICE_RABBITMQ_BATCH_REQUEST_TASK_QUEUE']

        if 'SENSORY_SERVICE_RABBITMQ_URI' in os.environ:
            self.SENSORY_SERVICE_RABBITMQ_URI = os.environ['SENSORY_SERVICE_RABBITMQ_URI']

        if 'SENSORY_SERVICE_RABBITMQ_USERNAME' in os.environ:
            self.SENSORY_SERVICE_RABBITMQ_USERNAME = os.environ['SENSORY_SERVICE_RABBITMQ_USERNAME']

        if 'SENSORY_SERVICE_RABBITMQ_PASSWORD' in os.environ:
            self.SENSORY_SERVICE_RABBITMQ_PASSWORD = os.environ['SENSORY_SERVICE_RABBITMQ_PASSWORD']

        if 'SENSORY_SERVICE_RABBITMQ_SERVER' in os.environ:
            self.SENSORY_SERVICE_RABBITMQ_SERVER = os.environ['SENSORY_SERVICE_RABBITMQ_SERVER']

        if 'SENSORY_SERVICE_RABBITMQ_PORT' in os.environ:
            self.SENSORY_SERVICE_RABBITMQ_PORT = int(os.environ['SENSORY_SERVICE_RABBITMQ_PORT'])

        if 'SENSORY_SERVICE_RABBITMQ_VHOST' in os.environ:
            self.SENSORY_SERVICE_RABBITMQ_VHOST = os.environ['SENSORY_SERVICE_RABBITMQ_VHOST']

        self.SENSORY_SERVICE_RABBITMQ_URL = "%s%s:%s@%s:%s/%s" % (
            self.SENSORY_SERVICE_RABBITMQ_URI,
            self.SENSORY_SERVICE_RABBITMQ_USERNAME,
            self.SENSORY_SERVICE_RABBITMQ_PASSWORD,
            self.SENSORY_SERVICE_RABBITMQ_SERVER,
            self.SENSORY_SERVICE_RABBITMQ_PORT,
            self.SENSORY_SERVICE_RABBITMQ_VHOST
        )

        if 'SENSORY_SERVICE_SHARD_SIZE' in os.environ:
            self.SENSORY_SERVICE_SHARD_SIZE = int(os.environ['SENSORY_SERVICE_SHARD_SIZE'])

        ###############################################################################
        # Training Service Options
        ###############################################################################

        if 'TRAINING_SERVICE_RABBITMQ_EXCHANGE' in os.environ:
            self.TRAINING_SERVICE_RABBITMQ_EXCHANGE = os.environ['TRAINING_SERVICE_RABBITMQ_EXCHANGE']

        if 'TRAINING_SERVICE_RABBITMQ_TRAINING_REQUEST_ROUTING_KEY' in os.environ:
            self.TRAINING_SERVICE_RABBITMQ_TRAINING_REQUEST_ROUTING_KEY = os.environ[
                'TRAINING_SERVICE_RABBITMQ_TRAINING_REQUEST_ROUTING_KEY']

        if 'TRAINING_SERVICE_RABBITMQ_TRAIN_REQUEST_TASK_QUEUE' in os.environ:
            self.TRAINING_SERVICE_RABBITMQ_TRAIN_REQUEST_TASK_QUEUE = os.environ[
                'TRAINING_SERVICE_RABBITMQ_TRAIN_REQUEST_TASK_QUEUE']

        if 'TRAINING_SERVICE_RABBITMQ_RABBITMQ_URI' in os.environ:
            self.TRAINING_SERVICE_RABBITMQ_RABBITMQ_URI = os.environ['TRAINING_SERVICE_RABBITMQ_RABBITMQ_URI']

        if 'TRAINING_SERVICE_RABBITMQ_USERNAME' in os.environ:
            self.TRAINING_SERVICE_RABBITMQ_USERNAME = os.environ['TRAINING_SERVICE_RABBITMQ_USERNAME']

        if 'TRAINING_SERVICE_RABBITMQ_PASSWORD' in os.environ:
            self.TRAINING_SERVICE_RABBITMQ_PASSWORD = os.environ['TRAINING_SERVICE_RABBITMQ_PASSWORD']

        if 'TRAINING_SERVICE_RABBITMQ_SERVER' in os.environ:
            self.TRAINING_SERVICE_RABBITMQ_SERVER = os.environ['TRAINING_SERVICE_RABBITMQ_SERVER']

        if 'TRAINING_SERVICE_RABBITMQ_PORT' in os.environ:
            self.TRAINING_SERVICE_RABBITMQ_PORT = int(os.environ['TRAINING_SERVICE_RABBITMQ_PORT'])

        if 'TRAINING_SERVICE_RABBITMQ_VHOST' in os.environ:
            self.TRAINING_SERVICE_RABBITMQ_VHOST = os.environ['TRAINING_SERVICE_RABBITMQ_VHOST']

        self.TRAINING_SERVICE_RABBITMQ_URL = "%s%s:%s@%s:%s/%s" % (
            self.TRAINING_SERVICE_RABBITMQ_RABBITMQ_URI,
            self.TRAINING_SERVICE_RABBITMQ_USERNAME,
            self.TRAINING_SERVICE_RABBITMQ_PASSWORD,
            self.TRAINING_SERVICE_RABBITMQ_SERVER,
            self.TRAINING_SERVICE_RABBITMQ_PORT,
            self.TRAINING_SERVICE_RABBITMQ_VHOST
        )

        ###############################################################################
        # Training Processor Options
        ###############################################################################

        if 'TRAINING_PROCESSOR_SERVICE_RABBITMQ_EXCHANGE' in os.environ:
            self.TRAINING_PROCESSOR_SERVICE_RABBITMQ_EXCHANGE = os.environ[
                'TRAINING_PROCESSOR_SERVICE_RABBITMQ_EXCHANGE']

        if 'TRAINING_PROCESSOR_SERVICE_RABBITMQ_TRAINING_REQUEST_ROUTING_KEY' in os.environ:
            self.TRAINING_PROCESSOR_SERVICE_RABBITMQ_TRAINING_REQUEST_ROUTING_KEY = os.environ[
                'TRAINING_PROCESSOR_SERVICE_RABBITMQ_TRAINING_REQUEST_ROUTING_KEY']

        if 'TRAINING_PROCESSOR_SERVICE_RABBITMQ_TRAIN_REQUEST_TASK_QUEUE' in os.environ:
            self.TRAINING_PROCESSOR_SERVICE_RABBITMQ_TRAIN_REQUEST_TASK_QUEUE = os.environ[
                'TRAINING_PROCESSOR_SERVICE_RABBITMQ_TRAIN_REQUEST_TASK_QUEUE']

        if 'TRAINING_PROCESSOR_SERVICE_RABBITMQ_URI' in os.environ:
            self.TRAINING_PROCESSOR_SERVICE_RABBITMQ_URI = os.environ[
                'TRAINING_PROCESSOR_SERVICE_RABBITMQ_URI']

        if 'TRAINING_PROCESSOR_SERVICE_RABBITMQ_USERNAME' in os.environ:
            self.TRAINING_PROCESSOR_SERVICE_RABBITMQ_USERNAME = os.environ[
                'TRAINING_PROCESSOR_SERVICE_RABBITMQ_USERNAME']

        if 'TRAINING_PROCESSOR_SERVICE_RABBITMQ_PASSWORD' in os.environ:
            self.TRAINING_PROCESSOR_SERVICE_RABBITMQ_PASSWORD = os.environ[
                'TRAINING_PROCESSOR_SERVICE_RABBITMQ_PASSWORD']

        if 'TRAINING_PROCESSOR_SERVICE_RABBITMQ_SERVER' in os.environ:
            self.TRAINING_PROCESSOR_SERVICE_RABBITMQ_SERVER = os.environ['TRAINING_PROCESSOR_SERVICE_RABBITMQ_SERVER']

        if 'TRAINING_PROCESSOR_SERVICE_RABBITMQ_PORT' in os.environ:
            self.TRAINING_PROCESSOR_SERVICE_RABBITMQ_PORT = int(os.environ['TRAINING_PROCESSOR_SERVICE_RABBITMQ_PORT'])

        if 'TRAINING_PROCESSOR_SERVICE_RABBITMQ_VHOST' in os.environ:
            self.TRAINING_PROCESSOR_SERVICE_RABBITMQ_VHOST = os.environ['TRAINING_PROCESSOR_SERVICE_RABBITMQ_VHOST']

        self.TRAINING_PROCESSOR_SERVICE_RABBITMQ_URL = "%s%s:%s@%s:%s/%s" % (
            self.TRAINING_PROCESSOR_SERVICE_RABBITMQ_URI,
            self.TRAINING_PROCESSOR_SERVICE_RABBITMQ_USERNAME,
            self.TRAINING_PROCESSOR_SERVICE_RABBITMQ_PASSWORD,
            self.TRAINING_PROCESSOR_SERVICE_RABBITMQ_SERVER,
            self.TRAINING_PROCESSOR_SERVICE_RABBITMQ_PORT,
            self.TRAINING_PROCESSOR_SERVICE_RABBITMQ_VHOST
        )

        ###############################################################################
        # Client Options
        ###############################################################################

        if 'CLASSIFICATION_SERVER' in os.environ:
            self.CLASSIFICATION_SERVER = os.environ['CLASSIFICATION_SERVER']

        if 'CLASSIFICATION_SERVER_PORT' in os.environ:
            self.CLASSIFICATION_SERVER_PORT = int(os.environ['CLASSIFICATION_SERVER_PORT'])

        if 'CLASSIFICATION_SERVER_URI' in os.environ:
            self.CLASSIFICATION_SERVER_URI = os.environ['CLASSIFICATION_SERVER_URI']
