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

"""Helper for /etc/network/interfaces on the master
"""

def _gen_mtu_option(name, interface, ctx):
    """Generate the MTU option depending on the method

    Only the ``static`` interface method accept the ``mtu`` option,
    other method requires a ``pre-up`` command.

    :param name: name of the interface
    :type name: `str`
    :param interface: interface description
    :type interface: `dict`

    """
    mtu = ctx.getVar(u'valeur_mtu_{0}'.format(name), None)
    if mtu is not None:
        if interface[u'method'] == 'statique':
            interface[u'mtu'] = mtu
        else:
            interface['options'].append('pre-up ip link set $IFACE mtu {0}'.format(mtu))

    return interface


def _gen_unmanage_interface(name, method, ctx, force_proxyarp=False):
    """Generate unmanage ethernet interfaces

    :param name: name of the interface
    :type name: `str`
    :param method: configuration method like `statique` or `dhcp`
    :type method: `str`
    :param ctx: cheetah template context
    :type ctx:
    :param force_proxyarp: to force proxy_arp to this interface
    :type: `bool`
    :return: interface description
    :rtype: `dict`

    """
    nom_carte = ctx.getVar(u'nom_carte_{0}'.format(name))
    interface = {u'name': nom_carte,
                 u'proto': u'inet',
                 u'method': method,
                 u'options': []}

    interface = _gen_mtu_option(name, interface, ctx)

    interface['options'].append('pre-up ip link set $IFACE up')
    interface['options'].append('post-down ip link set $IFACE down')

    link_speed = ctx.getVar(u'debit_carte_{0}'.format(name), None)
    if link_speed:
        interface['options'].append('pre-up ethtool -s {0} {1}'.format(nom_carte, link_speed))
    if force_proxyarp:
        interface['options'].append('up /sbin/sysctl -w net.ipv4.conf.{0}.proxy_arp=1'.format(nom_carte))

    return interface

def _gen_physical_interface(name, method, ctx):
    """Generate physical ethernet interfaces

    :param name: name of the interface
    :type name: `str`
    :param method: configuration method like `statique` or `dhcp`
    :type method: `str`
    :param ctx: cheetah template context
    :type ctx:
    :return: interface description
    :rtype: `dict`

    """
    nom_carte = ctx.getVar(u'nom_carte_{0}'.format(name))
    nom_zone = ctx.getVar(u'nom_zone_{0}'.format(name))
    interface = {u'name': nom_zone,
                 u'proto': u'inet',
                 u'method': method,
                 u'ip': ctx.getVar(u'adresse_ip_{0}'.format(name), None),
                 u'mask': ctx.getVar(u'adresse_netmask_{0}'.format(name), None),
                 u'bcast': ctx.getVar(u'adresse_broadcast_{0}'.format(name), None),
                 u'network': ctx.getVar(u'adresse_network_{0}'.format(name), None),
                 u'options': []}

    if method == 'manual':
        interface['options'].append('pre-up ip link set $IFACE up')
        interface['options'].append('post-down ip link set $IFACE down')

    interface = _gen_mtu_option(name, interface, ctx)

    if ctx.getVar(u'interface_gw', None) == nom_zone:
        interface.update({u'gw': ctx.getVar('adresse_ip_gw', None)})

    link_speed = ctx.getVar(u'debit_carte_{0}'.format(name), None)
    if link_speed:
        interface['options'].append('pre-up ethtool -s {0} {1}'.format(nom_carte, link_speed))

    return interface


def _gen_pppoe_interface():
    """Generate the dsl-provider pppoe interface

    :return: interface description
    :rtype: `dict`

    """
    interface = {u'name': 'dsl-provider',
                 u'proto': u'inet',
                 u'method': 'ppp',
                 u'options': ['provider dsl-provider']}

    return interface


def _gen_bridge_interface(name, method, ctx):
    """Generate a bridge interface

    :param name: name of the physical interface part of the bridge
    :type name: `str`
    :param method: configuration method like `statique` or `dhcp`
    :type method: `str`
    :param ctx: cheetah template context
    :type ctx:
    :return: interface description
    :rtype: `dict`

    """
    nom_carte = ctx.getVar(u'nom_carte_{0}'.format(name))
    nom_zone = ctx.getVar(u'nom_zone_{0}'.format(name))
    bridge_options = ['bridge_ports {0}'.format(nom_carte),
                      'bridge_fd 2',
                      'bridge_hello 2',
                      'bridge_maxage 12',
                      'bridge_stp off']

    interface = {u'name': nom_zone,
                 u'proto': u'inet',
                 u'method': method,
                 u'ip': ctx.getVar(u'adresse_ip_{0}'.format(name), None),
                 u'mask': ctx.getVar(u'adresse_netmask_{0}'.format(name), None),
                 u'bcast': ctx.getVar(u'adresse_broadcast_{0}'.format(name), None),
                 u'network': ctx.getVar(u'adresse_network_{0}'.format(name), None),
                 u'options': bridge_options}

    interface = _gen_mtu_option(name, interface, ctx)

    return interface


def _gen_alias_interfaces(name, ctx):
    """Generate an alias interface

    :param name: name of the interface
    :type name: `str`
    :param ctx: cheetah template context
    :type ctx:
    :return: interface description
    :rtype: `dict`

    """
    interfaces = []
    nom_zone = ctx.getVar(u'nom_zone_{0}'.format(name))
    master_name = u'alias_ip_{0}'.format(name)
    aliases = ctx.getVar(master_name)
    idx = 1
    for alias in aliases:
        interface = {u'name': u'{0}:{1}'.format(nom_zone, idx),
                     u'proto': u'inet',
                     u'method': u'statique',
                     u'ip': str(alias),
                     u'mask': getattr(alias, u'alias_netmask_{0}'.format(name)),
                     u'bcast': getattr(alias, u'alias_broadcast_{0}'.format(name)),
                     u'network': getattr(alias, u'alias_network_{0}'.format(name)),
                     u'gw': getattr(alias, u'alias_gw_{0}'.format(name), None),
                     u'options': []}

        interfaces.append(interface)
        idx += 1

    return interfaces

def _gen_vlan_interfaces(name, ctx):
    """Generate VLAN interface

    :param name: name of the interface
    :type name: `str`
    :param ctx: cheetah template context
    :type ctx:
    :return: interface description
    :rtype: `dict`

    """
    interfaces = []
    nom_zone = ctx.getVar(u'nom_zone_{0}'.format(name))
    master_name = u'vlan_id_{0}'.format(name)
    vlans = ctx.getVar(master_name)
    for vlan in vlans:
        interface = {u'name': u'{0}.{1}'.format(nom_zone, vlan),
                     u'proto': u'inet',
                     u'method': u'statique',
                     u'ip': getattr(vlan, u'vlan_ip_{0}'.format(name)),
                     u'mask': getattr(vlan, u'vlan_netmask_{0}'.format(name)),
                     u'bcast': getattr(vlan, u'vlan_broadcast_{0}'.format(name)),
                     u'network': getattr(vlan, u'vlan_network_{0}'.format(name)),
                     u'gw': getattr(vlan, u'vlan_gw_{0}'.format(name), None),
                     u'options': ['vlan_raw_device {0}'.format(nom_zone)]}

        interfaces.append(interface)

    return interfaces


def get_master_interfaces(ctx):
    """Get interfaces for master

    :param ctx: cheetah template context
    :type ctx:
    :return: interface descriptions
    :rtype: `list` of `dict`

    """
    interfaces = []
    n_interfaces = int(ctx.getVar(u'nombre_interfaces'))
    for idx in range(0, n_interfaces):
        interface_name = u'eth{0}'.format(idx)
        # Non regular attribut name
        interface_method = ctx.getVar(u'{0}_method'.format(interface_name), u'manuel')
        if ctx.getVar('zone_is_bridge_{0}'.format(interface_name)) == 'oui':
            #if interface is in a bridge
            interfaces.append(_gen_unmanage_interface(interface_name,
                                                      'manual',
                                                      ctx, True))
            interfaces.append(_gen_bridge_interface(interface_name,
                                                    interface_method,
                                                    ctx))
        elif interface_method == u'manuel':
            interfaces.append(_gen_unmanage_interface(interface_name,
                                                      'manual',
                                                      ctx))
        elif interface_method == u'pppoe':
            interfaces.append(_gen_unmanage_interface(interface_name,
                                                      'manual',
                                                      ctx))
            interfaces.append(_gen_pppoe_interface())
        else:
            interfaces.append(_gen_physical_interface(interface_name,
                                                      interface_method,
                                                      ctx))
            if ctx.getVar(u'alias_{0}'.format(interface_name), u'non') == u'oui':
                interfaces.extend(_gen_alias_interfaces(interface_name, ctx))
            if ctx.getVar(u'vlan_{0}'.format(interface_name), u'non') == u'oui':
                interfaces.extend(_gen_vlan_interfaces(interface_name, ctx))

    # Restart rsyslog on last interface
    interfaces[-1]['options'].append('up service rsyslog restart')
    return interfaces
