#!/usr/bin/env python

"""This script contains helper functions."""

# ############################ LICENSE INFORMATION ############################
# This file is part of the E3 RESOLVE Model.

# Copyright (C) 2019 Energy and Environmental Economics, Inc.
# For contact information, go to www.ethree.com

# The E3 RESOLVE Model is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# The E3 RESOLVE Model is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.

# You should have received a copy of the GNU Affero General Public License
# along with the E3 RESOLVE Model (in the file LICENSE.TXT). If not,
# see <http://www.gnu.org/licenses/>.
# #############################################################################

import datetime
import logging
import os
import sys

import fileio


def get_new_logger(dir_str):
    """Create a new customer logger that prints to scenario results directory.

    Args:
        dir_str: DirectoryStructure object

    Returns:
        logger: Logging object
    """
    logger = logging.getLogger('resolve_model')
    logger.setLevel(logging.DEBUG)

    # Create handlers
    c_handler = logging.StreamHandler(sys.stdout)
    f_handler = logging.FileHandler(
        os.path.join(dir_str.SCENARIO_RESULTS_DIRECTORY, 'summary', 'warnings.log'),
        mode='w+'
    )
    c_handler.setLevel(logging.DEBUG)
    f_handler.setLevel(logging.DEBUG)

    # Create formatters and add it to handlers
    c_format = logging.Formatter('%(levelname)s - %(message)s')
    f_format = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    c_handler.setFormatter(c_format)
    f_handler.setFormatter(f_format)

    # Add handlers to the logger
    logger.addHandler(c_handler)
    logger.addHandler(f_handler)

    # Print scenario name to warnings log
    logger.info('{}'.format(dir_str.scenario_name))

    return logger


class Logger:
    """Logs output from code.

    The print statement will call the write() method of any object you assign to sys.stdout,
    so assign the terminal (stdout) and a log file as output destinations.
    """

    def __init__(self, directory_structure):
        self.terminal = sys.stdout
        timestamp = datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
        self.log_file_path = os.path.join(
            directory_structure.LOGS_DIRECTORY,
            directory_structure.scenario_name,
            '{}_{}.log'
            .format(timestamp, directory_structure.scenario_name)
        )
        self.log_file = fileio.filewriter(self.log_file_path, buffering=1)
        self.ilp_file_path = os.path.join(
            directory_structure.LOGS_DIRECTORY,
            directory_structure.scenario_name,
            '{}_{}.ilp'
            .format(timestamp, directory_structure.scenario_name)
        )

    def write(self, message):
        self.terminal.write(message)
        self.log_file.write(message)

    def flush(self):
        self.terminal.flush()
        self.log_file.flush()


class DirStructure:
    """Directory and file structure."""

    def __init__(self, code_directory, scenario_name):
        """Initialize directory structure based on scenario name

        Args:
            code_directory (str): Path to `resolve_code` directory.
            scenario_name (str): Name of scenario to run.
        """
        self.scenario_name = scenario_name
        self.CODE_DIRECTORY = code_directory
        self.DIRECTORY = os.path.join(self.CODE_DIRECTORY, "..")
        self.INPUTS_DIRECTORY = os.path.join(self.DIRECTORY, "inputs")
        self.RESULTS_DIRECTORY = os.path.join(self.DIRECTORY, "results")
        self.LOGS_DIRECTORY = os.path.join(self.DIRECTORY, "logs")
        self.SCENARIO_INPUTS_DIRECTORY = os.path.join(self.INPUTS_DIRECTORY, self.scenario_name)
        self.SCENARIO_RESULTS_DIRECTORY = os.path.join(self.RESULTS_DIRECTORY, self.scenario_name)
        self.SCENARIO_RESULTS_SUMMARY_DIRECTORY = os.path.join(self.RESULTS_DIRECTORY, self.scenario_name, 'summary')
        self.SCENARIO_LOGS_DIRECTORY = os.path.join(self.LOGS_DIRECTORY, self.scenario_name)

    def make_directories(self):
        for folder in [
            self.RESULTS_DIRECTORY,
            self.SCENARIO_RESULTS_DIRECTORY,
            self.SCENARIO_RESULTS_SUMMARY_DIRECTORY,
            self.LOGS_DIRECTORY,
            self.SCENARIO_LOGS_DIRECTORY
        ]:
            if not os.path.exists(folder):
                os.mkdir(folder)

    def get_feature_toggles(self):
        self.feature_toggles = fileio.dictfromfile(
            os.path.join(self.SCENARIO_INPUTS_DIRECTORY, 'feature_toggles.csv'),
            header_as_keys=False,
            num_columns_as_keys=1,
            removerowblanks=True
        )