#!/usr/bin/env python
#
# Copyright 2016 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

"""
PON Simulator process, able to move packets across NNI and UNIs, as well
as take MGMT calls via gRPC.
It can only work on Linux.
"""
import argparse
import os

import yaml
from twisted.internet.defer import inlineCallbacks

from common.structlog_setup import setup_logging
from grpc_server import GrpcServer
from ponsim import PonSim
from realio import RealIo

defs = dict(
    config=os.environ.get('CONFIG', './ponsim.yml'),
    grpc_port=int(os.environ.get('GRPC_PORT', 50060)),
    name=os.environ.get('NAME', 'pon1'),
    onus=int(os.environ.get("ONUS", 1))
)


def load_config(args):
    path = args.config
    if path.startswith('.'):
        dir = os.path.dirname(os.path.abspath(__file__))
        path = os.path.join(dir, path)
    path = os.path.abspath(path)
    with open(path) as fd:
        config = yaml.load(fd)
    return config


banner = r'''
 ____   __   __ _  ____  __  _  _
(  _ \ /  \ (  ( \/ ___)(  )( \/ )
 ) __/(  O )/    /\___ \ )( / \/ \
(__)   \__/ \_)__)(____/(__)\_)(_/
'''

def print_banner(log):
    for line in banner.strip('\n').splitlines():
        log.info(line)
    log.info('(to stop: press Ctrl-C)')


def parse_args():

    parser = argparse.ArgumentParser()

    _help = ('Path to chameleon.yml config file (default: %s). '
             'If relative, it is relative to main.py of chameleon.'
             % defs['config'])
    parser.add_argument('-c', '--config',
                        dest='config',
                        action='store',
                        default=defs['config'],
                        help=_help)

    _help = ('port number of the GRPC service exposed by voltha (default: %s)'
             % defs['grpc_port'])
    parser.add_argument('-g', '--grpc-port',
                        dest='grpc_port',
                        action='store',
                        default=defs['grpc_port'],
                        help=_help)

    _help = ('number of ONUs to simulate (default: %d)' % defs['onus'])
    parser.add_argument('-o', '--onus',
                        dest='onus',
                        action='store',
                        type=int,
                        default=defs['onus'],
                        help=_help)

    _help = ('name of the PON natework used as a prefix for all network'
             ' resource created on behalf of the PON (default: %s)' %
             defs['name'])
    parser.add_argument('-N', '--name',
                        dest='name',
                        action='store',
                        default=defs['name'],
                        help=_help)

    _help = "suppress debug and info logs"
    parser.add_argument('-q', '--quiet',
                        dest='quiet',
                        action='count',
                        help=_help)

    _help = 'enable verbose logging'
    parser.add_argument('-v', '--verbose',
                        dest='verbose',
                        action='count',
                        help=_help)

    _help = 'omit startup banner log lines'
    parser.add_argument('-n', '--no-banner',
                        dest='no_banner',
                        action='store_true',
                        default=False,
                        help=_help)

    args = parser.parse_args()

    return args


class Main(object):

    def __init__(self):

        self.args = args = parse_args()
        self.config = load_config(args)

        verbosity_adjust = (args.verbose or 0) - (args.quiet or 0)
        self.log = setup_logging(self.config.get('logging', {}),
                                 args.name,
                                 verbosity_adjust=verbosity_adjust)

        # components
        self.io = None
        self.ponsim = None
        self.grpc_server = None

        if not args.no_banner:
            print_banner(self.log)

        self.startup_components()

    def start(self):
        self.start_reactor()  # will not return except Keyboard interrupt

    @inlineCallbacks
    def startup_components(self):
        try:
            self.log.info('starting-internal-components')

            iface_map = self.setup_networking_assets(self.args.name,
                                                     self.args.onus)
            self.io = yield RealIo(iface_map).start()
            self.ponsim = PonSim(self.args.onus, self.io.egress)
            self.io.register_ponsim(self.ponsim)

            self.grpc_server = GrpcServer(self.args.grpc_port, self.ponsim)
            yield self.grpc_server.start()

            self.log.info('started-internal-services')

        except Exception, e:
            self.log.exception('startup-failed', e=e)

    @inlineCallbacks
    def shutdown_components(self):
        """Execute before the reactor is shut down"""
        self.log.info('exiting-on-keyboard-interrupt')
        try:
            if self.io is not None:
                yield self.io.stop()
            self.teardown_networking_assets(self.args.name, self.args.onus)
            if self.grpc_server is not None:
                yield self.grpc_server.stop()
        except Exception, e:
            self.log.exception('shutdown-failed', e=e)

    def start_reactor(self):
        from twisted.internet import reactor
        reactor.callWhenRunning(
            lambda: self.log.info('twisted-reactor-started'))
        reactor.addSystemEventTrigger('before', 'shutdown',
                                      self.shutdown_components)
        reactor.run()

    def setup_networking_assets(self, prefix, n_unis):
        # setup veth pairs for NNI and each UNI, using prefix and port numbers
        port_map = dict()
        for portnum in [0] + range(128, 128 + n_unis):
            external_name = '%s_%d' % (prefix, portnum)
            internal_name = external_name + 'sim'
            os.system('sudo ip link add dev {} type veth peer name {}'.format(
                external_name, internal_name
            ))
            os.system('sudo ip link set {} up'.format(external_name))
            os.system('sudo ip link set {} up'.format(internal_name))
            if portnum == 0:
                os.system('sudo brctl addif ponmgmt {}'.format(external_name))
            port_map[portnum] = internal_name
        return port_map

    def teardown_networking_assets(self, prefix, n_unis):
        # undo all the networking stuff
        for portnum in [0] + range(128, 128 + n_unis):
            external_name = '%s_%d' % (prefix, portnum)
            os.system('sudo ip link del {}'.format(external_name))


if __name__ == '__main__':
    Main().start()
