
# Copyright 2017-present Open Networking Foundation
#
# 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.

#from __future__ import absolute_import

import requests
import urllib
from requests.auth import HTTPBasicAuth
from xossynchronizer.steps.syncstep import SyncStep
from xossynchronizer.modelaccessor import SwitchPort, PortInterface, FabricIpAddress, model_accessor

from xosconfig import Config
from multistructlog import create_logger

from helpers import Helpers

log = create_logger(Config().get('logging'))


class SyncFabricPort(SyncStep):
    provides = [SwitchPort]
    observes = [SwitchPort, PortInterface, FabricIpAddress]

    def sync_record(self, model):

        if model.leaf_model_name == "PortInterface":
            log.info("Received update for PortInterface", port=model.port.portId, interface=model)
            return self.sync_record(model.port)

        if model.leaf_model_name == "FabricIpAddress":
            log.info("Received update for FabricIpAddress",
                     port=model.interface.port.portId,
                     interface=model.interface.name,
                     ip=model.ip)
            return self.sync_record(model.interface.port)

        log.info("Adding port %s/%s to onos-fabric" % (model.switch.ofId, model.portId))
        interfaces = []
        for intf in model.interfaces.all():
            i = {
                "name": intf.name,
                "ips": [i.ip for i in intf.ips.all()]
            }
            if intf.vlanUntagged:
                i["vlan-untagged"] = intf.vlanUntagged
            interfaces.append(i)

        # Send port config to onos-fabric netcfg
        data = {
            "ports": {
                "%s/%s" % (model.switch.ofId, model.portId): {
                    "interfaces": interfaces,
                    "hostLearning": {
                        "enabled": model.host_learning
                    }
                }
            }
        }

        log.debug("Port %s/%s data" % (model.switch.ofId, model.portId), data=data)

        onos = Helpers.get_onos_fabric_service(self.model_accessor)

        url = 'http://%s:%s/onos/v1/network/configuration/' % (onos.rest_hostname, onos.rest_port)

        r = requests.post(url, json=data, auth=HTTPBasicAuth(onos.rest_username, onos.rest_password))

        if r.status_code != 200:
            log.error(r.text)
            raise Exception("Failed to add port  %s/%s into ONOS" % (model.switch.ofId, model.portId))
        else:
            try:
                log.info("Port %s/%s response" % (model.switch.ofId, model.portId), json=r.json())
            except Exception:
                log.info("Port %s/%s response" % (model.switch.ofId, model.portId), text=r.text)

        # Now set the port's administrative state.
        # TODO(smbaker): See if netcfg allows us to specify the portstate instead of using a separate REST call

        url = 'http://%s:%s/onos/v1/devices/%s/portstate/%s' % (onos.rest_hostname,
                                                                onos.rest_port,
                                                                model.switch.ofId,
                                                                model.portId)
        data = {"enabled": True if model.admin_state == "enabled" else False}
        log.debug("Sending portstate %s to %s/%s" % (data, model.switch.ofId, model.portId))
        r = requests.post(url, json=data, auth=HTTPBasicAuth(onos.rest_username, onos.rest_password))

        if r.status_code != 200:
            log.error(r.text)
            raise Exception("Failed to set portstate  %s/%s into ONOS" % (model.switch.ofId, model.portId))
        else:
            try:
                log.info("Portstate %s/%s response" % (model.switch.ofId, model.portId), json=r.json())
            except Exception:
                log.info("Portstate %s/%s response" % (model.switch.ofId, model.portId), text=r.text)

    def delete_netcfg_item(self, partial_url):
        onos = Helpers.get_onos_fabric_service(self.model_accessor)
        url = 'http://%s:%s/onos/v1/network/configuration/ports/%s' % (onos.rest_hostname, onos.rest_port, partial_url)

        r = requests.delete(url, auth=HTTPBasicAuth(onos.rest_username, onos.rest_password))

        if r.status_code != 204:
            log.error(r.text)
            raise Exception("Failed to %s port %s from ONOS" % url)

    def delete_record(self, model):
        if model.leaf_model_name == "PortInterface":
            log.info("Received update for PortInterface", port=model.port.portId, interface=model.name)
            log.info("Removing port interface %s from port %s/%s in onos-fabric" %
                     (model.name, model.port.switch.ofId, model.port.portId))

            # resync the existing interfaces
            return self.sync_record(model.port)

        if model.leaf_model_name == "FabricIpAddress":
            # TODO add unit tests
            log.info(
                "Received update for FabricIpAddress",
                port=model.interface.port.portId,
                interface=model.interface.name,
                ip=model.ip)
            log.info("Removing IP %s from interface %s, on port %s/%s in onos-fabric" %
                     (model.ip, model.interface.name, model.interface.port.switch.ofId, model.interface.port.portId))

            # resync the existing interfaces
            return self.sync_record(model.interface.port)

        log.info("Removing port %s/%s from onos-fabric" % (model.switch.ofId, model.portId))

        key = "%s/%s" % (model.switch.ofId, model.portId)
        key = urllib.quote(key, safe='')

        # deleting the port
        self.delete_netcfg_item(key)
