/*
 * Copyright 2015 Open Networking Laboratory
 *
 * 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.
 */
package org.onosproject.vtnrsc.router.impl;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;

import java.util.Collection;
import java.util.Collections;
import java.util.Set;

import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.util.KryoNamespace;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.EventuallyConsistentMap;
import org.onosproject.store.service.EventuallyConsistentMapEvent;
import org.onosproject.store.service.EventuallyConsistentMapListener;
import org.onosproject.store.service.StorageService;
import org.onosproject.store.service.WallClockTimestamp;
import org.onosproject.vtnrsc.DefaultRouter;
import org.onosproject.vtnrsc.FixedIp;
import org.onosproject.vtnrsc.Router;
import org.onosproject.vtnrsc.RouterGateway;
import org.onosproject.vtnrsc.RouterId;
import org.onosproject.vtnrsc.SubnetId;
import org.onosproject.vtnrsc.TenantId;
import org.onosproject.vtnrsc.TenantNetworkId;
import org.onosproject.vtnrsc.VirtualPortId;
import org.onosproject.vtnrsc.router.RouterEvent;
import org.onosproject.vtnrsc.router.RouterListener;
import org.onosproject.vtnrsc.router.RouterService;
import org.onosproject.vtnrsc.subnet.SubnetService;
import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
import org.onosproject.vtnrsc.virtualport.VirtualPortService;
import org.slf4j.Logger;

import com.google.common.collect.Sets;

/**
 * Provides implementation of the Router service.
 */
@Component(immediate = true)
@Service
public class RouterManager implements RouterService {

    private static final String ROUTER_ID_NULL = "Router ID cannot be null";
    private static final String ROUTER_NOT_NULL = "Router cannot be null";
    private static final String ROUTER = "vtn-router-store";
    private static final String VTNRSC_APP = "org.onosproject.vtnrsc";
    private static final String LISTENER_NOT_NULL = "Listener cannot be null";
    private static final String EVENT_NOT_NULL = "event cannot be null";

    private final Logger log = getLogger(getClass());
    private final Set<RouterListener> listeners = Sets.newCopyOnWriteArraySet();
    private EventuallyConsistentMapListener<RouterId, Router> routerListener = new InnerRouterStoreListener();
    protected EventuallyConsistentMap<RouterId, Router> routerStore;
    protected ApplicationId appId;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected StorageService storageService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected CoreService coreService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected TenantNetworkService tenantNetworkService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected VirtualPortService virtualPortService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected SubnetService subnetService;

    @Activate
    public void activate() {
        appId = coreService.registerApplication(VTNRSC_APP);
        KryoNamespace.Builder serializer = KryoNamespace
                .newBuilder()
                .register(KryoNamespaces.API)
                .register(Router.class, RouterId.class, DefaultRouter.class,
                          TenantNetworkId.class, TenantId.class,
                          VirtualPortId.class, DefaultRouter.class,
                          RouterGateway.class, Router.Status.class,
                          SubnetId.class);
        routerStore = storageService
                .<RouterId, Router>eventuallyConsistentMapBuilder()
                .withName(ROUTER).withSerializer(serializer)
                .withTimestampProvider((k, v) -> new WallClockTimestamp())
                .build();
        routerStore.addListener(routerListener);
        log.info("Started");
    }

    @Deactivate
    public void deactivate() {
        routerStore.removeListener(routerListener);
        routerStore.destroy();
        listeners.clear();
        log.info("Stopped");
    }

    @Override
    public boolean exists(RouterId routerId) {
        checkNotNull(routerId, ROUTER_ID_NULL);
        return routerStore.containsKey(routerId);
    }

    @Override
    public Collection<Router> getRouters() {
        return Collections.unmodifiableCollection(routerStore.values());
    }

    @Override
    public Router getRouter(RouterId routerId) {
        checkNotNull(routerId, ROUTER_ID_NULL);
        return routerStore.get(routerId);
    }

    @Override
    public boolean createRouters(Collection<Router> routers) {
        checkNotNull(routers, ROUTER_NOT_NULL);
        for (Router router : routers) {
            verifyRouterData(router);
            routerStore.put(router.id(), router);
            if (!routerStore.containsKey(router.id())) {
                log.debug("The router is created failed whose identifier is {}",
                          router.id().toString());
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean updateRouters(Collection<Router> routers) {
        checkNotNull(routers, ROUTER_NOT_NULL);
        for (Router router : routers) {
            if (!routerStore.containsKey(router.id())) {
                log.debug("The routers is not exist whose identifier is {}",
                          router.id().toString());
                throw new IllegalArgumentException(
                                                   "routers ID doesn't exist");
            }
            verifyRouterData(router);
            routerStore.put(router.id(), router);
            if (!router.equals(routerStore.get(router.id()))) {
                log.debug("The router is updated failed whose identifier is {}",
                          router.id().toString());
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean removeRouters(Collection<RouterId> routerIds) {
        checkNotNull(routerIds, ROUTER_ID_NULL);
        for (RouterId routerId : routerIds) {
            if (!routerStore.containsKey(routerId)) {
                log.debug("The router is not exist whose identifier is {}",
                          routerId.toString());
                throw new IllegalArgumentException(
                                                   "router ID doesn't exist");
            }
            Router router = routerStore.get(routerId);
            routerStore.remove(routerId, router);
            if (routerStore.containsKey(routerId)) {
                log.debug("The router deleted is failed whose identifier is {}",
                          routerId.toString());
                return false;
            }
        }
        return true;
    }

    @Override
    public void addListener(RouterListener listener) {
        checkNotNull(listener, LISTENER_NOT_NULL);
        listeners.add(listener);
    }

    @Override
    public void removeListener(RouterListener listener) {
        checkNotNull(listener, LISTENER_NOT_NULL);
        listeners.remove(listener);
    }

    /**
     * Verifies validity of Router data.
     *
     * @param routers router instance
     */
    private void verifyRouterData(Router routers) {
        checkNotNull(routers, ROUTER_NOT_NULL);
        if (routers.gatewayPortid() != null
                && !virtualPortService.exists(routers.gatewayPortid())) {
            log.debug("The gateway port ID is not exist whose identifier is {}",
                      routers.gatewayPortid().toString());
            throw new IllegalArgumentException("gateway port ID doesn't exist");
        }

        if (routers.externalGatewayInfo() != null) {
            RouterGateway routerGateway = routers.externalGatewayInfo();
            if (!tenantNetworkService.exists(routerGateway.networkId())) {
                log.debug("The network ID of gateway info is not exist whose identifier is {}",
                          routers.id().toString());
                throw new IllegalArgumentException(
                                                   "network ID of gateway info doesn't exist");
            }
            Iterable<FixedIp> fixedIps = routerGateway.externalFixedIps();
            for (FixedIp fixedIp : fixedIps) {
                if (!subnetService.exists(fixedIp.subnetId())) {
                    log.debug("The subnet ID of gateway info is not exist whose identifier is {}",
                              routers.id().toString());
                    throw new IllegalArgumentException(
                                                       "subnet ID of gateway info doesn't exist");
                }
            }
        }
    }

    private class InnerRouterStoreListener
            implements EventuallyConsistentMapListener<RouterId, Router> {

        @Override
        public void event(EventuallyConsistentMapEvent<RouterId, Router> event) {
            checkNotNull(event, EVENT_NOT_NULL);
            Router router = event.value();
            if (EventuallyConsistentMapEvent.Type.PUT == event.type()) {
                notifyListeners(new RouterEvent(RouterEvent.Type.ROUTER_PUT,
                                                router));
            }
            if (EventuallyConsistentMapEvent.Type.REMOVE == event.type()) {
                notifyListeners(new RouterEvent(RouterEvent.Type.ROUTER_DELETE,
                                                router));
            }
        }
    }

    /**
     * Notifies specify event to all listeners.
     *
     * @param event Floating IP event
     */
    private void notifyListeners(RouterEvent event) {
        checkNotNull(event, EVENT_NOT_NULL);
        listeners.forEach(listener -> listener.event(event));
    }
}
