#!python
# -*- coding: utf-8 -*-
#PYTHON_ARGCOMPLETE_OK
"""braise - a dynamic firewall

"""

import argparse
import argcomplete
import pickle
import json
from sys import argv
from servicewall import parser_helpers
from servicewall.network_helpers import get_realm_id


conf_dir = "/etc/servicewall/"
lib_dir = "/usr/lib/servicewall/"
realm_defs_dict = conf_dir + "realms.json"
service_defs_pickle = lib_dir + "services.p"
definitions_dir = "/etc/gufw/app_profiles"

with open(realm_defs_dict, "rb") as fd:
    realm_defs = json.load(fd)
with open(service_defs_pickle, "rb") as fd:
    service_defs = pickle.load(fd)


# Find allowed services to help autocompletion know what to delete. - TODO doesn't
# work when the realm is unknown
try:
    realm_id = get_realm_id()
    online = True
except KeyError:
    # No network (but servicewall might still be enabled).
    realm_id = None
    online = False
if online:
    try:
        allowed_services = [ service_def for service_def in realm_defs[realm_id].keys() ]
    except KeyError:
        allowed_services = []
else:
    allowed_services = []

def parser_helper(function_name):
    """This function will return a pointer to a function named "function_name"
    in parser_helpers. This pointer will only be evaluated when it is called,
    ie after parser is done.
    """
    def wrapper(args):
        eval("parser_helpers." + function_name)(args)
    return wrapper

parser = argparse.ArgumentParser()

# parser fails badly when invoked without argument ; let's invoke basic help
# instead (see def no_arg_provided(args) in parser_helpers.py)
#parser.set_defaults(func=parser_helper("no_arg_provided"))
#parser.set_defaults(func=parser.print_help())
#defarg = parser.add_argument("-s", action='store_true')
#defarg.set_defaults(func=parser.print_help())

subparser = parser.add_subparsers()


#
# SUBPARSERS : enable | disable | status | reload
#

parser_enable = subparser.add_parser(
    "enable",
    help="enable the firewall"
)
parser_enable.set_defaults(func=parser_helper("enable"))

parser_disable = subparser.add_parser(
    "disable",
    help="disable the firewall"
)
parser_disable.set_defaults(func=parser_helper("disable"))

parser_show_status = subparser.add_parser(
    "status",
    help="show iptables rules controlled by this firewall"
)
parser_show_status.set_defaults(func=parser_helper("status"))

parser_reload = subparser.add_parser(
    "reload",
    help="reload rules"
)
parser_reload.set_defaults(func=parser_helper("reload"))


#
# SUBPARSERS : show { logs | realms | services | service }
#

parser_show = subparser.add_parser(
    "show",
    help="show different useful things"
)
show_subparser = parser_show.add_subparsers()

parser_show_logs = show_subparser.add_parser(
    "logs",
    help="show a digest of logs of the firewall"
)
parser_show_logs.set_defaults(func=parser_helper("show_logs"))
show_logs_subparser = parser_show_logs.add_subparsers()
parser_show_logs_time = show_logs_subparser.add_parser(
    "since",
    help="restrict logs to those since [period] seconds"
)
parser_show_logs_time.add_argument("period", type=int)
parser_show_logs_time.set_defaults(func=parser_helper("show_logs"))
parser_show_logs_limit = show_logs_subparser.add_parser(
    "limit",
    help="limit to last LIMIT logs"
)
parser_show_logs_limit.add_argument("limit", type=int)
parser_show_logs_limit.set_defaults(func=parser_helper("show_logs"))

parser_show_realms = show_subparser.add_parser(
    "realms",
    help="show realm definitions"
)
parser_show_realms.set_defaults(func=parser_helper("show_realms"))

parser_show_services = show_subparser.add_parser(
    "services",
    help="show services list"
)
parser_show_services.set_defaults(func=parser_helper("show_services"))

parser_show_input_chain = show_subparser.add_parser(
    "input_chain",
    help="show services allowed in current realm"
)
parser_show_input_chain.set_defaults(func=parser_helper("show_input_chain"))

# For "show service", don't define help ; instead overwrite usage because it
# prints the possible arguments twice, which is way too long.
# TODO could tell to search for services with braise show services
# and then don't display "positional arguments" - see
# https://docs.python.org/3.2/library/argparse.html#formatter-class
parser_show_service = show_subparser.add_parser(
    "service",
    usage="%s %s service_name - prints the service definition" %
    (parser_show.prog, "service")
)
parser_show_service.add_argument("service_name", choices=service_defs)
parser_show_service.set_defaults(func=parser_helper("show_service"))

parser_show_port = show_subparser.add_parser(
    "port",
    help="show services associated to port"
)
parser_show_port.add_argument("port_name")
parser_show_port.set_defaults(func=parser_helper("show_port"))


#
# SUBPARSERS : { allow | disallow } service
#

parser_allow = subparser.add_parser("allow")
allow_subparser = parser_allow.add_subparsers()
parser_allow_service = allow_subparser.add_parser(
    "service",
    usage="%s service service_name - add a service to authorized list" %
    parser_allow.prog
)
parser_allow_service.add_argument("service_name", choices=service_defs)
parser_allow_service.set_defaults(func=parser_helper("allow_service"))

parser_disallow = subparser.add_parser("disallow")
disallow_subparser = parser_disallow.add_subparsers()
# We could have used parser_add_service, but the choices aren't the same :
parser_disallow_service = disallow_subparser.add_parser(
    "service",
    usage="%s service service_name - remove a service from authorized list" %
    parser_disallow.prog
)
parser_disallow_service.add_argument("service_name", choices=allowed_services)
parser_disallow_service.set_defaults(func=parser_helper("disallow_service"))


argcomplete.autocomplete(parser)

if len(argv) == 1:
    # display help message when no args are passed.
    parser.print_help()
    raise SystemExit()

# Here, argcomplete stops.
args = parser.parse_args()
# Here, helper callbacks get evaluated.
args.func(args)

