import sys
import string

class ResourceFile(object):
    def __init__(self):
        self.key_value = {}
        self.accessed = {}

    def load(self, infile):
        """ Reads in a json, yaml or toml resource file. If multiple files
            are loaded, resources between them are merged. An error 
            occurs if the same key is loaded multiple times and different
            values are defined for it
        """
        if infile.endswith("json"):
            self.load_json(infile)
        elif infile.endswith("yml") or infile.endswith("yaml"):
            self.load_yaml(infile)
        elif infile.endswith("tml") or infile.endswith("toml"):
            self.load_toml(infile)
        else:
            print "Unrecognized extension for file '%s'. Please use json, yaml or toml" % infile
            sys.exit(1)
    
    def get(self, key, default=None, replace_table=None):
        """ Returns the resource value associated with the provided key.

            Arguments:
                *key* (text) Name of resource

                *default* (text) Value to be returned if key isn't found

                *replace_table* (dict) Substrings that are to be replaced
                in resource string. E.g., if replace_table = { foo: "bar" }
                then all instances of "foo" in the resource string will be
                replaced with "bar"

            Returns:
                Resource string if found and default value if not, with
                applied substitutions from replace_table
        """
        self.accessed[key] = True
        val = self.key_value.get(key, default)
        if replace_table is not None:
            for k,v in replace_table.iteritems():
                val = string.replace(val, k, v)
        return val

    def report(self):
        """ Reports all resources that were defined but not used
        """
        err = False
        print "-------------------------------"
        print "---     Resource report      --"
        for k,v in self.accessed.iteritems():
            if not v:
                if not err:
                    err = True
                print "\t'%s' not used" % k
        if not err:
            print "all defined resources were used"
        print "-------------------------------"

    ####################################################################
    # internal procedure to load json file
    def load_json(self, infile):
        """ Reads input json, yaml or toml file
        """
        import json
        try:
            with open(infile, 'r') as f:
                resources = json.load(f)
                f.close()
        except IOError:
            print "Unable to open input json file '%s'" % infile
            sys.exit(1)
        self.read_keys(resources)

    # internal procedure to load yaml
    def load_yaml(self, infile):
        try:
            import yaml
            try:
                with open(infile, 'r') as f:
                    resources = yaml.load(f)
                    f.close()
            except IOError:
                print "Unable to open input yaml file '%s'" % infile
                sys.exit(1)
            self.read_keys(resources)
        except ImportError:
            print "*** yaml not available -- please pip install pyyaml"
            sys.exit(1)

    # internal procedure to load toml
    def load_toml(self, infile):
        try:
            import toml
            try:
                with open(infile, 'r') as f:
                    resources = toml.load(f)
                    f.close()
            except IOError:
                print "Unable to open input toml file '%s'" % infile
                sys.exit(1)
            self.read_keys(resources)
        except ImportError:
            print "*** toml not available -- please pip install toml"
            sys.exit(1)


    # internal procedure to read keys out of dictionary recursively
    def read_keys(self, resources):
        err = False
        for k,v in resources.iteritems():
            if isinstance(v, dict):
                self.read_keys(v)
            else:
                if k in self.key_value and v != self.key_value[k]:
                    print "Error -- inconsistent values for key '%s'" % k
                    err = True
                self.key_value[k] = v
                self.accessed[k] = False
        if err:
            sys.exit(1)


class ResourceFileTest(object):
    def create_json(self, fname, rsrc):
        import json
        d = {}
        d["jone"] = "json one"
        d["jtwo"] = "json one"
        d["jsub"] = {}
        d["jsub"]["jthree"] = "json three"
        with open(fname, 'w') as f:
            json.dump(d, f, indent=2)
        f.close()
        rsrc.load(fname)

    def create_yaml(self, fname, rsrc):
        try:
            import yaml
            d = {}
            d["yone"] = "yaml one"
            d["ytwo"] = "yaml one"
            d["ysub"] = {}
            d["ysub"]["ythree"] = "yaml three"
            with open(fname, 'w') as f:
                yaml.dump(d, f, indent=2)
            f.close()
            rsrc.load(fname)
        except ImportError:
            print "*** yaml not available -- please pip install pyyaml"

    def create_toml(self, fname, rsrc):
        try:
            import toml
            d = {}
            d["tone"] = "toml one"
            d["ttwo"] = "toml one"
            d["tsub"] = {}
            d["tsub"]["tthree"] = "toml three"
            with open(fname, 'w') as f:
                toml.dump(d, f)
            f.close()
            rsrc.load(fname)
        except ImportError:
            print "*** toml not available -- please pip install toml"

    def run(self):
        # create and load json, yaml and toml files
        rsrc = ResourceFile()
        self.create_json("tmp.json", rsrc)
        self.create_yaml("tmp.yaml", rsrc)
        self.create_toml("tmp.toml", rsrc)
        # print resource from each
        print rsrc.get("jone", "json error")
        print rsrc.get("yone", "** yaml error")
        print rsrc.get("tone", "** toml error")
        print rsrc.get("jthree", "json error")
        print rsrc.get("ythree", "** yaml error")
        print rsrc.get("tthree", "** toml error")
        # run report
        rsrc.report()

