#!/usr/bin/env python
# encoding: utf-8
"""A factory for creating configuration objects.
"""

#-----------------------------------------------------------------------------
#  Copyright (C) 2008-2009  The IPython Development Team
#
#  Distributed under the terms of the BSD License.  The full license is in
#  the file COPYING, distributed as part of this software.
#-----------------------------------------------------------------------------

#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------

import os

from IPython.utils.ipstruct import Struct

#-----------------------------------------------------------------------------
# Code
#-----------------------------------------------------------------------------


class ConfigLoaderError(Exception):
    pass


class ConfigLoader(object):
    """A object for loading configurations from just about anywhere.
    
    The resulting configuration is packaged as a :class:`Struct`.
    """

    def __init__(self):
        """A base class for config loaders.
        
        Examples
        --------
        
        >>> cl = ConfigLoader()
        >>> config = cl.load_config()
        >>> config
        {}
        """
        self.clear()

    def clear(self):
        self.config = Struct()

    def load_config(self):
        """Load a config from somewhere, return a Struct.
        
        Usually, this will cause self.config to be set and then returned.
        """
        return self.config


class FileConfigLoader(ConfigLoader):
    """A config loader for pure python files.
    
    This calls execfile on a plain python file and looks for attributes
    that are all caps.  These attribute are added to the config Struct.
    """

    def __init__(self, filename, path='.'):
        """Build a config loader for a filename and path.

        Parameters
        ----------
        filename : str
            The file name of the config file.
        path : str, list, tuple
            The path to search for the config file on, or a sequence of
            paths to try in order

        Examples
        --------
        
        
        """
        self.filename = filename
        self.path = path
        self.full_filename = ''
        self.data = None
        ConfigLoader.__init__(self)

    def find_file(self):
        """Implement file finding logic here."""
        self.full_filename = self.filename

    def read_file_as_dict(self):
        if not os.path.isfile(self.full_filename):
            raise IOError("config file does not exist: %r" % self.fullfilename)
        self.data = {}
        execfile(self.full_filename, self.data)

    def convert_to_struct(self):
        if self.data is None:
            ConfigLoaderError('self.data does not exist')
        for k, v in self.data.iteritems():
            if k == k.upper():
                self.config[k] = v

    def load_config(self):
        self.find_file()
        self.read_file_as_dict()
        self.convert_to_struct()
        return self.config

class PyConfigLoader(object):
    pass


class DefaultFileConfigLoader(object):

    def __init__(self, filename, install_location):
        pass

    def load_config(self):
        pass

    def install(self, force=False):
        pass


class CommandLineConfigLoader(ConfigLoader):

    def __init__(self):
        self.parser = None
        self.parsed_data = None
        self.clear()
        

    def clear(self):
        self.config = Struct()

    def load_config(self, args=None):
        self.create_parser()
        self.parse_args(args)
        self.convert_to_struct()
        return self.config

    def create_parser(self):
        """Create self.parser"""

    def parse_args(self, args=None):
        """self.parser->self.parsed_data"""
        if self.parser is None:
            raise ConfigLoaderError('self.parser does not exist')
        if args is None:
            self.parsed_data = parser.parse_args()
        else:
            self.parse_data = parser.parse_args(args)

    def convert_to_struct(self):
        """self.parsed_data->self.config"""
        if self.parsed_data is None:
            raise ConfigLoaderError('self.parsed_data does not exist')
        self.config = Struct(vars(self.parsed_data))


class ArgParseConfigLoader(CommandLineConfigLoader):

    # arguments = [(('-f','--file'),dict(type=str,dest='file'))]
    arguments = []

    def __init__(self, *args, **kw):
        """Create a config loader for use with argparse.
        
        The args and kwargs arguments here are passed onto the constructor
        of :class:`argparse.ArgumentParser`.
        """
        self.args = args
        self.kw = kw
        CommandLineConfigLoader.__init__(self)

    def create_parser(self):
        self.parser = argparse.ArgumentParser(*self.args, **self.kw)
        self.add_arguments()

    def add_arguments(self):
        for argument in self.arguments:
            self.parser.add_argument(*argument[0],**argument[1])