import os
import sys
import ast
try:
    from configparser import RawConfigParser
except ImportError:
    # Backward compatibility with python versions earlier to 3.0
    from ConfigParser import RawConfigParser

# Exception
from ec2sys_autotune.ec2_instance_exception import Ec2AutotuneError

EXCLUDE_TAG = "(exclude)"


def fetch_configuration(auto_profile, user_profile, section,
                        cb_user_overridden, cb_user_excluded,
                        cb_auto_generated, cb_dry_run):
    '''

    Core function used by configure_system() to
    read-in configurations and configure the system.
    process_showconfig() also uses this function to
    show the configuration to end user.

    The implementation of this library function is
    generic in that this function accepts call backs
    for each of overridden, excluded, autogenerated and
    dry run. A consumer is free to pick select or all
    of the tunables.

    There are 2 profiles - auto_profile and user_profile.
    auto_profiles are auto generated profiles by system.
    user_profile are profiles customized by end user. Users
    can opt to either:
        1) Override auto generated tunables
        2) Disable auto generated tunables
    '''
    # Read auto generated config file (ini format)
    autocfg_log = RawConfigParser(allow_no_value=True)
    autocfg_log.read(auto_profile)

    # Read user configured config file (ini format)
    usercfg_log = RawConfigParser(allow_no_value=True)
    usercfg_log.read(user_profile)

    override = []
    exclude = []

    # Fetch configuration for the system
    if (autocfg_log.has_section(section) is True):
        options = autocfg_log.options(section)
        if (usercfg_log.has_section(section) is True):
            user_options = usercfg_log.options(section)
            for item in user_options:
                value = usercfg_log.get(section, item)
                if (value == EXCLUDE_TAG):
                    # Tunables that are excluded by user
                    exclude.append(item)
                else:
                    # Tunables that are overridden by user
                    override.append(item)
            user_options = None
        for item in options:
            if (cb_dry_run is not None):
                # Dry run to validate tunables
                try:
                    cb_dry_run(item)
                except Ec2AutotuneError, e:
                    raise e
            if (item in exclude):
                # Excluded tunable
                if (cb_user_excluded is not None):
                    cb_user_excluded(item)
                continue
            else:
                value = None
                if (item in override):
                    # Configure user configured value
                    value = usercfg_log.get(section, item)
                    value = value.split()
                    if (value[0].isdigit() is True):
                        value = map(int, value)
                    if (cb_user_overridden is not None):
                        cb_user_overridden(item, value)
                else:
                    # Configure autotune configured value
                    value = autocfg_log.get(section, item)
                    if (value.find("[") != -1):
                        value = ast.literal_eval(value)
                        if (cb_auto_generated is not None):
                            cb_auto_generated(item, value)
                    else:
                        # Always generated as list
                        continue
    return