def parse_config_file(self):
        config = yamlbro.load_yaml(self.requirements_file)

        if 'target-folder' in config.keys() and self.output_folder is None:
            print("Info: Files and Configuration will be stored in %s" % self.output_folder)
            self.output_folder = os.path.expanduser(config['target-folder'])

            if not os.path.exists(self.output_folder):
                os.makedirs(self.output_folder)

        if 'Bukkit' in config.keys():
            bukkit_data = config['Bukkit']

            for plugin_name in bukkit_data.keys():
                data = bukkit_data[plugin_name]
                version = data['version']
                configure_after_download = False
                configure_options = {}
                configure_script = None
                template_file = None
                defaults_file = None
                plugin_folder = None
                kwargs = {}

                if 'configure' in data.keys():
                    if 'options' in data['configure']:
                        configure_after_download = True
                        for option, value in data['configure']['options'].items():
                            configure_options[option] = value

                    if 'args' in data['configure'].keys():
                        for key, value in data['configure']['args'].items():
                            kwargs[key] = value

                    if 'script' in data['configure'].keys():
                        configure_script = data['configure']['script']
                        print("Script found: %s" % configure_script)

                    if 'template' in data['configure'].keys():
                        template_file = data['configure']['template']

                    if 'defaults' in data['configure'].keys():
                        defaults_file = data['configure']['defaults']

                    if 'plugin-data-folder' in data['configure'].keys():
                        plugin_folder = data['configure']['plugin-data-folder']

                    if (template_file is not None and defaults_file is None) or (
                                    defaults_file is not None and template_file is None):
                        template_file = None
                        defaults_file = None
                        configure_after_download = False

                        print(textwrap.dedent("""\n
                            +==================================================================+
                                    Configuration Error for {name} ({version})
                            +==================================================================+

                                Generating a plugins configuration file via template & default configuration
                                requires the 'template', 'plugin-data-folder', and 'defaults' node to be present, and valid
                                inside your requirements file ({configuration}).

                                Using one without the others nulls the functionality, as a template has placeholders
                                for your config data, and the defaults file fills in the blanks where you
                                have not specified values. Using either without a plugin data folder doesn't make sense,
                                as you'd want to keep the template and defaults once it's generated.

                                McResolver will continue to download these plugins, though configuration cannot happen
                                unless you provide a template, plugin data folder, and defaults file, or a script that
                                handles the configuration.

                            +==================================================================+
                            """).format(name=plugin_name, version=version, configuration=self.requirements_file))

                if isinstance(plugin_name, int) or plugin_name.isdigit():
                    print("Invalid Bukkit plugin '%s', plugin name or slug (in plugins url) is required")
                    continue

                try:
                    bukkit_resource = BukkitResource.from_name(plugin_name)
                except ValueError:
                    print("Unable to retrieve Bukkit plugin %s (v. %s)" % (plugin_name, version))

                if not bukkit_resource.has_version(version=version):
                    if not self.retrieve_latest_on_version_error:
                        print("Unable to retrieve version %s for %s" % (version, plugin_name))
                        continue
                    else:
                        self.bukkit_resources[plugin_name] = {
                            'version': 'latest',
                            'name': plugin_name,
                            'resource': bukkit_resource,
                            'configure': configure_after_download,
                            'script': configure_script,
                            'configure-options': configure_options,
                            'kwargs': kwargs,
                            'template': template_file,
                            'defaults': defaults_file,
                            'plugin-folder': plugin_folder,
                        }
                else:
                    self.bukkit_resources[plugin_name] = {
                        'version': version,
                        'name': plugin_name,
                        'resource': bukkit_resource,
                        'configure': configure_after_download,
                        'script': configure_script,
                        'configure-options': configure_options,
                        'kwargs': kwargs,
                        'template': template_file,
                        'defaults': defaults_file,
                        'plugin-folder': plugin_folder,

                    }

                print("Bukkit information retrieved on %s (v: %s)" % (
                    plugin_name, self.bukkit_resources[plugin_name]['version']))

        # Go ahead and collect all the Spigot resources in the yml file
        # and their desired versions (or latest)
        if 'Spigot' in config.keys():
            spigot_plugins = config['Spigot']
            for plugin_id in spigot_plugins.keys():
                data = spigot_plugins[plugin_id]
                spigot_resource = None
                version = data['version']
                name = data['name']
                configure_after_download = False
                configure_script = None
                configure_options = {}
                template_file = None
                defaults_file = None
                plugin_folder = None
                kwargs = {}
                if 'configure' in data.keys():
                    if 'options' in data['configure']:
                        configure_after_download = True
                        for option, value in data['configure']['options'].items():
                            configure_options[option] = value

                    if 'args' in data['configure'].keys():
                        for key, value in data['configure']['args'].items():
                            kwargs[key] = value

                    if 'script' in data['configure'].keys():
                        configure_script = data['configure']['script']

                    if 'template' in data['configure'].keys():
                        template_file = data['configure']['template']

                    if 'defaults' in data['configure'].keys():
                        defaults_file = data['configure']['defaults']

                    if 'plugin-data-folder' in data['configure'].keys():
                        plugin_folder = data['configure']['plugin-data-folder']

                    if (template_file is not None and defaults_file is None) or (
                                    defaults_file is not None and template_file is None):
                        template_file = None
                        defaults_file = None
                        configure_after_download = False
                        print(textwrap.dedent("""\n
                            +==================================================================+
                                    Configuration Error for {name} ({version})
                            +==================================================================+

                                Generating a plugins configuration file via template & default configuration
                                requires the 'template', 'plugin-data-folder', and 'defaults' node to be present, and valid
                                inside your requirements file ({configuration}).

                                Using one without the others nulls the functionality, as a template has placeholders
                                for your config data, and the defaults file fills in the blanks where you
                                have not specified values. Using either without a plugin data folder doesn't make sense,
                                as you'd want to keep the template and defaults once it's generated.

                                McResolver will continue to download these plugins, though configuration cannot happen
                                unless you provide a template, plugin data folder, and defaults file, or a script that
                                handles the configuration.

                            +==================================================================+
                            """).format(name=name, version=version, configuration=self.requirements_file))

                if isinstance(plugin_id, int) or plugin_id.isdigit():
                    spigot_resource = SpigotResource.from_id(plugin_id)
                else:
                    print(
                        "Unable to retrieve Spigot plugin (%s) via its name... Potential feature in the future!" % name)
                    continue

                if spigot_resource is None:
                    print("Invalid plugin %s (v: %s)" % (name, version))
                    continue

                if not spigot_resource.has_version(version=version):
                    if not self.retrieve_latest_on_version_error:
                        print("Unable to retrieve version %s for %s" % (version, name))
                        continue

                    self.spigot_resources[plugin_id] = {
                        'version': 'latest',
                        'name': name,
                        'resource': spigot_resource,
                        'configure': configure_after_download,
                        'script': configure_script,
                        'configure-options': configure_options,
                        'kwargs': kwargs,
                        'template': template_file,
                        'defaults': defaults_file,
                        'plugin-folder': plugin_folder,

                    }
                else:
                    self.spigot_resources[plugin_id] = {
                        'version': version,
                        'name': name,
                        'resource': spigot_resource,
                        'configure': configure_after_download,
                        'script': configure_script,
                        'configure-options': configure_options,
                        'kwargs': kwargs,
                        'template': template_file,
                        'defaults': defaults_file,
                        'plugin-folder': plugin_folder,
                    }

                if isinstance(plugin_id, int):
                    print("Spigot information retrieved on %s [id. %s] (v. %s)" % (name, plugin_id,
                                                                                   self.spigot_resources[plugin_id][
                                                                                       'version']))
    def generate_templates(self):
        def get_name_from_key(key):
            return key.lower().replace('-', '_').replace('.', '_')

        def assign_dict_nested_path(dict, path, value):
            def get(d, keys):
                for key in keys:
                    if key not in d:
                        d[key] = OrderedDict()  # TODO Investigate? Might need to instance another object
                        #     # print("Assigned empty value to path %s" % path)
                    d = d[key]
                return d

            def set(d, keys, value):
                d = get(d, keys[:-1])
                d[keys[-1]] = value

            if '.' in path:
                set(dict, path.split('.'), value)
            else:
                dict[path] = value

        def recursive_dictionary_collect(template_dict, parent_key, data):
            for key, value in data.items():
                new_key = key if parent_key is None else "%s.%s" % (parent_key, key)
                if isinstance(value, dict) or isinstance(value, OrderedDict):
                    recursive_dictionary_collect(template_dict, new_key, value)
                else:
                    if isinstance(value, list):
                        depth = len(new_key.split('.')) * 2
                        value.append('mcresolverdepth=%s' % depth)
                    template_dict[new_key] = value

        flat_key_template = OrderedDict()

        default_pluginfile_data = yamlbro.load_yaml(self.generate_base_config_file)

        for key, value in default_pluginfile_data.items():
            if isinstance(value, dict) or isinstance(value, OrderedDict):
                # replica_dict[key] = value
                recursive_dictionary_collect(flat_key_template, key, value)
            else:
                if isinstance(value, list):
                    value.append(
                        'mcresolverdepth=1')  # Hack around the template, and add the depth to prepend to the node
                flat_key_template[key] = value

        template_default_node_values = OrderedDict()
        node_value_types = {}

        for key, value in flat_key_template.items():
            node_name = key
            if '.' in key:
                node_split = key.split('.')
                if len(node_split) >= 2:
                    node_name = ".".join(node_split[-2:])
                else:
                    node_name = node_split[-1]

            node_name = get_name_from_key(node_name)
            # print("Key [%s] Node-Name %s" % (key, node_name))
            # node_name = get_name_from_key(node_name)
            value_type = value.__class__.__name__

            try:
                tdval = type(value)(value)
                if value_type == "bool":
                    tdval = str(tdval).lower()

                template_default_node_values[node_name] = tdval
                node_value_types[node_name] = value_type
                node_type = tdval.__class__.__name__
            except:
                template_default_node_values[node_name] = value
                node_value_types[node_name] = value_type
                node_type = value_type.__class__.__name__

            flat_key_template[key] = "{{{{{node}}}}}".format(node=node_name)

        expanded_key_config_template = OrderedDict()

        for key, value in flat_key_template.items():
            assign_dict_nested_path(expanded_key_config_template, key, value)

        config_template = yaml.dump(expanded_key_config_template, default_flow_style=False, indent=2,
                                    width=1000)

        with open(self.generate_base_config_file, 'r') as default_configuration_data:
            default_plugin_config = default_configuration_data.read()

        config_template = restore_yaml_comments(config_template, default_plugin_config)

        # Loop through all the nodes and their values, then change the jinja2 template
        # Variable to follow the format required for that item..
        # The reason we do this is to re-assign types to values (via their template-names)
        # As by default they all are quoted and are treated as strings.
        # We don't want this!
        for node, type in node_value_types.items():
            if type == "bool" or type == "int" or type == "float":
                config_template = config_template.replace("'{{{{{node}}}}}'".format(node=node),
                                                          "{{{{{node}}}}}".format(node=node))
            elif type == "str":
                continue
            elif type == "list":
                # If the value of the item is a list
                # Then there's quite a few things we have to do in order to preserve the format of the file!
                # First of all involves getting the depth (via a default value generated and added into the list)
                # Though this won't wind up in the final template. We do this because we need to have
                # The valid number of spaces before the list items, otherwise YAML Will break.
                node_list_values = template_default_node_values[node].copy()
                depth = 0
                for line in node_list_values:
                    if 'mcresolverdepth' in line:
                        # The depth of the item will be indexed by this!
                        # Depth is determined by how many parent keys, are above the child node
                        # Multiplied by 2, for yaml conventions.
                        # Example: Top-Level lists only have 2 spaces
                        # Whereas a list under top.level.list would have 4
                        depth = int(line.split('=')[1])
                        break

                # Collect all the nodes list items that dont have a depth attribute
                node_list_values = [line for line in node_list_values if 'mcresolverdepth' not in line]
                # Then reassign this value to the template defaults,
                # as we don't want the depth to be inside the users
                template_default_node_values[node] = node_list_values
                # Next we generate a loop statement for inside the template
                # On our node, to assure all the items in the list are processed
                loop_statement = "\n{{% for {node}_item in {node} %}}{depth}- {{{{list_item}}}}\n{{% endfor %}}".format(
                    depth=' ' * depth, node=node
                )

                # Lastly, for this part, replace the previous {{node}} item with the new list-generating statement
                # That was created above.
                config_template = config_template.replace(" '{{{{{node}}}}}'".format(node=node),
                                                          loop_statement)

        # Get the file contents for the default template nodes and their values in a yaml output!
        defaults_file_contents = yaml.dump(template_default_node_values, default_flow_style=False)
        # Next up, we need to remove all the 'none' values inside of this file, as it's really not a good idea
        # to have yaml parse "none" values... It'd return a string. So we make them blank instead.
        defaults_file_contents = defaults_file_contents.replace(": none", ": ")
        write_file(os.path.join(self.output_folder, '%s-template.yml' % self.generate_plugin_name),
                   config_template)
        write_file(os.path.join(self.output_folder, '%s-defaults.yml' % self.generate_plugin_name),
                   defaults_file_contents)