#! /usr/bin/env python3
# -*- coding: utf-8 -*-
###########################################################################
#
# Eole NG
# Copyright Pole de Competence Eole  (Ministere Education - Academie Dijon)
# Licence CeCill  http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html
# eole@ac-dijon.fr
#
###########################################################################

"""
Script de generation de regles iptables a partir d'un modele ERA.

%prog [options] era_model_file.xml
"""

import os, sys
from os.path import join, isfile
from era.noyau.storage import CSVStorage
from era.noyau.path import CONFIG_FILE, ACTIVE_TAGS, ERA_DEBUG
from era.noyau.models import update_hidden_directive


def parse_command_line():
    """Construit le parser d'options de la ligne de commande,
    parse la ligne de commande, et retourne
    le couple (options, fichier_modele_era.xml)
    """

    from optparse import OptionParser
    parser = OptionParser(__doc__, version = '%prog v1.0a')

    parser.add_option("-i", "--init-file", dest = "config_file",
                      help="Specify the config file (.ini) to user",
                      default = CONFIG_FILE,
                      metavar = "CONFIG_FILE")

    parser.add_option("-o", "--output",
                      dest = "output_filename", default = None,
                      help = "use this file rather than stdout")
    parser.add_option("-O", "--output_inclusion",
                      dest = "output_inclusion", default = None,
                      help = "use this file rather than stdout")
    # ead.csv en input
    parser.add_option("-d", "--external_csv",
                      dest = "external_csv", default = None,
                      help = "use an external csv optionnal directive file")
    parser.add_option("-t", "--tmpl_file",
                      dest = "tmpl_file", default = None,
                      help = "use an external tmpl optionnal directive file")

    parser.add_option("-a", "--active-file", dest = "active_file",
                      help="Specify the file with hidden tags to activate",
                      default = ACTIVE_TAGS,
                      metavar = "ACTIVE_FILE")

    parser.add_option("-s", "--set", dest = "ipsetdir",
                      help="Specify the ipset directory",
                      default = '/tmp',
                      metavar = "IPSETSDIR")

    parser.add_option("-r", "--rules", dest = "rules_file",
                      help="Specify the iptables-restore file",
                      default = None,
                      metavar = "IPSETSDIR")
    # ead.csv en output
    #parser.add_option("-g", "--gen_external",
    #                  dest = "gen_external_file", default = None,
    #                  help = "generate an external csv file from the actual xml source"
    #                  )

    options, args = parser.parse_args()
    # On doit avoir 1 et 1 seul argument en plus des options
    # <=> le nom du modele era a utiliser
    if len(args) != 1:
        parser.error("Need one (and only one) era model file")

    return options, args[0]

def run():
    """Traite les options passees en ligne de commande, et lance la
    compilation avec les bons parametres"""

    # internationalisation
    import locale, gettext
    APP = 'editeur'
    DIR = 'i18n'
    # locale.setlocale (locale.LC_ALL, '')
    gettext.bindtextdomain (APP, DIR)
    gettext.textdomain (APP)
    # installons la fonction _() dans les builtins
    if sys.version_info[0] < 3:
        gettext.install (APP, DIR, unicode=1)
    else:
        gettext.install (APP, DIR)

    # lancement de l'appliquation
    from era.backend.compiler import Compiler
    from era.backend.iptwriter import IPTWriter
    from era.noyau.initialize import initialize_app

    options, model_file = parse_command_line()

    ipsetdir = options.ipsetdir

    if options.output_filename:
        output = open(options.output_filename,'w')
    else:
        output = sys.stdout
    if options.output_inclusion:
        output_inclusion = open(options.output_inclusion, 'w')
    else:
        output_inclusion = sys.stdout
    try:
        matrix_model = initialize_app(model_file)
    except Exception as e :
        print(e)
        if ERA_DEBUG:
            import traceback
            traceback.print_exc()
        else:
            print("Pour obtenir plus d'informations, exécuter 'ERA_DEBUG=1 /usr/sbin/bastion regen'")
        sys.exit(1)

    if options.external_csv and options.tmpl_file:
        csv_file = options.external_csv

        # parsing du csv provenant de l'ead
        # si il existe, on met a jour la matrice en fonctions des regles activees ou non
        try:
            if os.path.isfile(csv_file):
                csv_data = CSVStorage(csv_file).get_data()
                # mise en forme et conversion de type pour les donnees
                update_list = []
                for d in csv_data:
                    # update_list est de la forme : [( tag, int(attrs) )]
                    update_list.append([d['tag'],int(d['attrs'])])
                # maj de la matrice
                matrix_model.visit_directives(update_list)
        except:
            # on catche l'exception si le fichier est vide
            pass

         # liste des directives optionnelles

        optional = matrix_model.get_active_list(hidden=False)
        tmpl_file = options.tmpl_file
        # on fait un 'touch' sur le fichier (si le fichier n'existe pas, le creer)
        if not isfile(tmpl_file):
            fh = open(tmpl_file, 'w')
            fh.write("")
            fh.close()
        c = CSVStorage(tmpl_file)
        c.set_data(optional)
        c.write_data()

        # parsing des regles cachées
        if os.path.isfile(options.active_file):
            # on lit les tags actives
            update_hidden_directive(matrix_model, options.active_file)
    try:
        compiler = Compiler(IPTWriter, output, options.config_file,
                            ipsetdir=ipsetdir,
                            output_inclusion=output_inclusion,
                            rules_file=options.rules_file)
        compiler.compile(matrix_model)
    except Exception as e:
        print()
        print("#--------------------------------------------------")
        print("Attention, erreur de coherence des directives Era")
        print(str(e))
        print("#--------------------------------------------------")
        if ERA_DEBUG:
            import traceback
            traceback.print_exc()
        else:
            print("Pour obtenir plus d'informations, exécuter 'ERA_DEBUG=1 /usr/sbin/bastion regen'")
        sys.exit(1)


if __name__ == '__main__':
    run()
