#!/usr/bin/env python3
#
# Copyright (C) 2023 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import argparse
from vyos.configquery import ConfigTreeQuery


def convert_to_set_commands(config_dict, parent_key=''):
    """
    Converts a configuration dictionary into a list of set commands.

    Args:
        config_dict (dict): The configuration dictionary.
        parent_key (str): The parent key for nested dictionaries.

    Returns:
        list: A list of set commands.
    """
    commands = []
    for key, value in config_dict.items():
        current_key = parent_key + key if parent_key else key

        if isinstance(value, dict):
            if not value:
                commands.append(f"set {current_key}")
            else:
                commands.extend(
                    convert_to_set_commands(value, f"{current_key} "))

        elif isinstance(value, str):
            commands.append(f"set {current_key} '{value}'")

    return commands


def change_rule_numbers(config_dict, start, step):
    """
    Changes rule numbers in the configuration dictionary.

    Args:
        config_dict (dict): The configuration dictionary.
        start (int): The starting rule number.
        step (int): The step to increment the rule numbers.

    Returns:
        None
    """
    if 'rule' in config_dict:
        rule_dict = config_dict['rule']
        updated_rule_dict = {}
        rule_num = start
        for rule_key in sorted(rule_dict.keys()):
            updated_rule_dict[str(rule_num)] = rule_dict[rule_key]
            rule_num += step
        config_dict['rule'] = updated_rule_dict

    for key in config_dict:
        if isinstance(config_dict[key], dict):
            change_rule_numbers(config_dict[key], start, step)


def convert_rule_keys_to_int(config_dict):
    """
    Converts rule keys in the configuration dictionary to integers.

    Args:
        config_dict (dict or list): The configuration dictionary or list.

    Returns:
        dict or list: The modified dictionary or list.
    """
    if isinstance(config_dict, dict):
        new_dict = {}
        for key, value in config_dict.items():
            # Convert key to integer if possible
            new_key = int(key) if key.isdigit() else key

            # Recur for nested dictionaries
            if isinstance(value, dict):
                new_value = convert_rule_keys_to_int(value)
            else:
                new_value = value

            new_dict[new_key] = new_value

        return new_dict
    elif isinstance(config_dict, list):
        return [convert_rule_keys_to_int(item) for item in config_dict]
    else:
        return config_dict


if __name__ == "__main__":
    # Parse command-line arguments
    parser = argparse.ArgumentParser(description='Convert dictionary to set commands with rule number modifications.')
    parser.add_argument('--start', type=int, default=100, help='Start rule number')
    parser.add_argument('--step', type=int, default=10, help='Step for rule numbers (default: 10)')
    args = parser.parse_args()

    config = ConfigTreeQuery()
    if not config.exists('firewall'):
        print('Firewall is not configured')
        exit(1)

    config_dict = config.get_config_dict('firewall')

    # Remove global-options, group and flowtable as they don't need sequencing
    if 'global-options' in config_dict['firewall']:
        del config_dict['firewall']['global-options']

    if 'group' in config_dict['firewall']:
        del config_dict['firewall']['group']

    if 'flowtable' in config_dict['firewall']:
        del config_dict['firewall']['flowtable']
    
    # Convert rule keys to integers, rule "10" -> rule 10
    # This is necessary for sorting the rules
    config_dict = convert_rule_keys_to_int(config_dict)

    # Apply rule number modifications
    change_rule_numbers(config_dict, start=args.start, step=args.step)

    # Convert to 'set' commands
    set_commands = convert_to_set_commands(config_dict)

    print()
    for command in set_commands:
        print(command)
    print()