# -*- coding: utf-8 -*-

""" Génération de la configuration pour le dhcp

Copyright (C) Frédéric Pauget
Licence : GPLv2
"""
import os
import sys
from socket import gethostname
import struct

if '/usr/scripts' not in sys.path:
    sys.path.append('/usr/scripts')

from gestion.iptools import AddrInNet
from gestion.gen_confs import gen_config
from gestion.config import NETs
from gestion.config.services import services
from gestion import secrets_new as secrets

# Relative imports
from pypureomapi import pack_ip, pack_mac, OMAPI_OP_UPDATE
from pypureomapi import Omapi, OmapiMessage, OmapiError, OmapiErrorNotFound

hostname = gethostname().split(".")[0]

class dydhcp:
    def __init__(self, server):
        self.dhcp_omapi_keyname = secrets.get('dhcp_omapi_keyname')
        self.dhcp_omapi_key = secrets.get('dhcp_omapi_keys')[server]
        self.server = server.lower()

    def add_host(self, ip, mac,name=None):
        """
        @type ip: str
        @type mac: str
        @type name: str
        @raises ValueError:
        @raises OmapiError:
        @raises socket.error:
        """
        if '<automatique>' in [ip, mac]:
            return
        msg = OmapiMessage.open(b"host")
        msg.message.append((b"create", struct.pack("!I", 1)))
        msg.message.append((b"exclusive", struct.pack("!I", 1)))
        msg.obj.append((b"hardware-address", pack_mac(mac)))
        msg.obj.append((b"hardware-type", struct.pack("!I", 1)))
        msg.obj.append((b"ip-address", pack_ip(ip)))
        # See patch for hostnames at
        # http://jpmens.net/2011/07/20/dynamically-add-static-leases-to-dhcpd/
        if name:
            statem = b'supersede host-name "%s";' % bytes(name)
            msg.obj.append((b"name", bytes(name)))
            msg.obj.append((b"statements", statem))
        conn=Omapi(self.server, 9991,self.dhcp_omapi_keyname, self.dhcp_omapi_key)
        response = conn.query_server(msg)
        # print response.dump() # DEBUG purpose (repr() marche po)
        conn.close()

    def del_host(self, ip,mac):
        """
        @type ip: str
        @type mac: str
        @raises ValueError:
        @raises OmapiError:
        @raises socket.error:
        """
        if '<automatique>' in [ip, mac]:
            return
        msg = OmapiMessage.open(b"host")
        msg.obj.append((b"hardware-address", pack_mac(mac)))
        msg.obj.append((b"hardware-type", struct.pack("!I", 1)))
        msg.obj.append((b"ip-address", pack_ip(ip)))
        conn=Omapi(self.server,9991,self.dhcp_omapi_keyname, self.dhcp_omapi_key)
        response = conn.query_server(msg)
        if response.opcode == OMAPI_OP_UPDATE:
            response = conn.query_server(OmapiMessage.delete(response.handle))
        conn.close()

class dhcp(gen_config) :
    """ Génération du fichier de déclaration des hosts.
    Chaque réseau servi doit être une clef du dictionnaire reseaux,
    la valeur correspondante est une chaine contenant le nom du fichier
    associé à ce réseau.

    Chaque machine possède ensuite une entrée de la forme de host_template.
    """
    ######################################PARTIE DE CONFIGURATION
    # Fichier à écire
    if hostname in services.get('isc-dhcp-server', []):
        restart_cmd = '/usr/bin/monit restart isc-dhcp-server'
        reseaux = { '138.231.136.0/21' : '/etc/dhcp3/generated/adherents.liste',
                    '10.42.0.0/16' : '/etc/dhcp3/generated/gratuit.liste',
                    '10.2.9.0/24' : '/etc/dhcp3/generated/appartements.liste',
                    '138.231.144.0/21' : '/etc/dhcp3/generated/wifi.liste' }
    else:
        restart_cmd = ''
        reseaux = {}
    dhcplease='/var/lib/dhcp/dhcpd.leases'

    host_template = """
    host %(nom)s {
        hardware ethernet %(mac)s;
        fixed-address %(ip)s;
        option host-name "%(host)s";
    }
"""

    ### Verbosité
    # Si =1 ralera (chaine warnings) si machines hors zone trouvée
    # Si =0 ralera seulement si réseau vide
    verbose = 1

    ######################################FIN PARTIE DE CONFIGURATION
    def __str__(self) :
        return 'dhcp'

    def lease_clean(self):
        f=open(self.dhcplease)
        w=open(self.dhcplease+'.new','w')
        config=""
        line=f.readline()
        write=True
        while line:
            if line.strip().startswith('host'):
                write=False
            if write:
                w.write(line)
            if not write and line.strip().endswith('}'):
                write=True
            line=f.readline()
        f.close()
        w.close()
        os.rename(self.dhcplease+'.new',self.dhcplease)
        return

    def _gen(self) :
        """Construction de la liste des machines appartenant à un réseau
        """

        warnings = ''

        ### Construction de la partie du fichier contenant les machines
        hosts = {}

        self.anim.iter = len(self.machines)
        for machine in self.machines :
            self.anim.cycle()
            for net in self.reseaux.keys() :
                if '<automatique>' not in [machine.ip(), machine.mac()] and \
                   AddrInNet(machine.ip(), net):
                    host_template = self.host_template
                    # variable pour remplir le template
                    #d = { 'nom' : machine.nom().split('.')[0] , 'mac' : machine.mac() , 'ip' : machine.ip() }
                    d = { 'nom' : machine.nom() , 'host' : machine.nom().split('.', 1)[0],'mac' : machine.mac() , 'ip' : machine.ip() }
                    try :
                        hosts[net] += host_template % d
                    except : hosts[net] = host_template % d

        ### Ecriture du fichier
        for net, fichier in self.reseaux.items() :
            fd0 = self._open_conf(fichier, '#')
            if hosts.has_key(net):
                fd0.write(hosts[net])
            fd0.close()
        try:
            self.lease_clean()
        except:
            print("An error append during cleaning of dhcp lease")

        return warnings
