#!/usr/bin/python3
# -*- coding: UTF-8 -*-
#
# pwan-configure-networking -- Convert networking configuration for private WAN
#

import os
import shutil
import sys
import tempfile
import time


INTERFACES = '/etc/network/interfaces'
BRIDGE_NAME = 'ext'
IGNORED_INTERFACE_NAMES = ['lo']


def get_backup_filename():
    filename = '{}.before-pwan-{}'.format(INTERFACES, time.strftime('%Y-%m-%d'))
    candidate = filename
    count = None
    while os.path.exists(candidate):
        if count is None:
            count = 0
        else:
            count += 1
        candidate = '{}-{}'.format(filename, count)
    return candidate


def make_backup(interfaces):
    filename = get_backup_filename()
    with open(filename, 'w') as f:
        f.write(interfaces)
    return filename


def get_interface_names(interface):
    names = []
    for line in interface.split('\n'):
        if line.startswith('iface '):
            name = line.split()[1]
            if name not in IGNORED_INTERFACE_NAMES:
                names.append(name)
    return names


def make_config(interfaces, bridge_port, vlan_trunk):
    found_auto = False
    config = ''

    for line in interfaces.split('\n'):
        output = None
        if line.startswith('iface {} '.format(bridge_port)):
            output = 'iface {} {}\n    bridge_ports {}'.format(BRIDGE_NAME, line.split(' ', 2)[2], bridge_port)
        elif line.startswith('iface {} '.format(vlan_trunk)):
            output = 'iface {} {}\n    pre-up ifconfig $IFACE up\n    post-down ifconfig $IFACE down'.format(vlan_trunk, line.split(' ', 2)[2])
        elif line.strip() in ('auto {}'.format(bridge_port), 'allow-hotplug {}'.format(bridge_port)):
            if not found_auto:
                found_auto = True
                output = 'auto {}'.format(BRIDGE_NAME)
        else:
            output = line

        if output is not None:
            config += '{output}\n'.format(output=output)
    return config


def update_file(contents):
    f = tempfile.NamedTemporaryFile(mode='w', delete=False)
    f.write(contents)
    f.close()
    shutil.move(f.name, INTERFACES)


if __name__ == '__main__':
    if not os.path.exists(INTERFACES):
        print('No {} file found. Cannot continue.'.format(INTERFACES))
        sys.exit(1)

    with open(INTERFACES) as interfaces_file:
        interfaces = interfaces_file.read()

    if BRIDGE_NAME in interfaces:
        print('{} appears to be up-to-date.'.format(INTERFACES))
        sys.exit(0)

    interface_names = get_interface_names(interfaces)
    if not interface_names:
        print('Could not detect any interfaces in {}.'.format(INTERFACES))
        sys.exit(1)

    print('There are two ways to connect the private WAN router to the core network:')
    print('1. Use a single interface for all traffic (default).')
    print('2. Use a separate interface for space VLAN traffic.')
    ans = input('Which option? [1/2] ')

    vlan_trunk = None
    if ans and ans[0] == '2':
        if len(interface_names) > 1:
            print('Select an interface from the following list to be used for the VLAN trunk interface: {}.'.format(', '.join(interface_names)))
            for name in interface_names:
                ans = input('Use {}? [y/N] '.format(name))
                if ans and ans.lower()[0] == 'y':
                    vlan_trunk = name
                    break

            if not vlan_trunk:
                print('No interface selected. Aborting.')
                sys.exit(0)

            interface_names.remove(vlan_trunk)
            print('You need to specify {} as the VLAN trunk interface on the PWAN router\'s page in the web application.\n'.format(vlan_trunk))
        else:
            print('There is only one available interface, choosing default configuration.\n')

    print('For private WAN operation, a bridge named {} will be created.'.format(BRIDGE_NAME))
    print('The new bridge will use the old configuration of the selected interface.')
    print('Select an interface from the following list to assign to this bridge: {}.'.format(', '.join(interface_names)))
    bridge_port = None
    for name in interface_names:
        ans = input('Add {} to bridge? [y/N] '.format(name))
        if ans and ans.lower()[0] == 'y':
            bridge_port = name
            break

    if not bridge_port:
        print('No interface selected. Aborting.')
        sys.exit(0)

    config = make_config(interfaces, bridge_port, vlan_trunk)
    print('{} will be updated to match the following configuration:'.format(INTERFACES))
    print('='*8)
    print(config)
    print('='*8)
    ans = input('Is this correct? [y/N] ')
    if ans and ans.lower()[0] == 'y':
        filename = make_backup(interfaces)
        print('Backing up old {} file to {}.'.format(INTERFACES, filename))
        print('Creating {} with bridge port {}.'.format(BRIDGE_NAME, bridge_port))

        if vlan_trunk:
            print('Configuring VLAN trunk interface {}.'.format(vlan_trunk))
        try:
            update_file(config)
        except EnvironmentError as e:
            print('Failed to write file: {}'.format(e))
            sys.exit(1)

        print('{} updated. You will need to reboot for the changes to take effect.'.format(INTERFACES))
    else:
        print('Configuration rejected. Aborting.')
        sys.exit(0)
