package org.opendaylight.controller.sal.binding.impl.connect.dom;

import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.RpcService;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;

import com.google.common.base.Optional;

/**
 * Manager responsible for instantiating forwarders responsible for
 * forwarding of RPC invocations from DOM Broker to Binding Aware Broker
 *
 */
class DomToBindingRpcForwardingManager implements
    RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>,
    RpcProviderRegistryImpl.RouterInstantiationListener,
    RpcProviderRegistryImpl.GlobalRpcRegistrationListener, RpcRegistrationListener {

    private final Map<Class<? extends RpcService>, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>();
    private final BindingIndependentMappingService mappingService;
    private final RpcProvisionRegistry biRpcRegistry;
    private final RpcProviderRegistry baRpcRegistry;
    private RpcProviderRegistryImpl registryImpl;

    DomToBindingRpcForwardingManager(final BindingIndependentMappingService mappingService, final RpcProvisionRegistry biRpcRegistry,
        final RpcProviderRegistry baRpcRegistry) {
        this.mappingService = mappingService;
        this.biRpcRegistry = biRpcRegistry;
        this.baRpcRegistry = baRpcRegistry;
    }

    public RpcProviderRegistryImpl getRegistryImpl() {
        return registryImpl;
    }

    public void setRegistryImpl(final RpcProviderRegistryImpl registryImpl) {
        this.registryImpl = registryImpl;
    }

    @Override
    public void onGlobalRpcRegistered(final Class<? extends RpcService> cls) {
        getRpcForwarder(cls, null).registerToDOMBroker();
    }

    @Override
    public void onGlobalRpcUnregistered(final Class<? extends RpcService> cls) {
        // NOOP
    }

    @Override
    public void onRpcRouterCreated(final RpcRouter<?> router) {
        Class<? extends BaseIdentity> ctx = router.getContexts().iterator().next();
        getRpcForwarder(router.getServiceType(), ctx);
    }

    @Override
    public void onRouteChange(final RouteChange<RpcContextIdentifier, InstanceIdentifier<?>> change) {
        for (Map.Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry : change.getAnnouncements().entrySet()) {
            bindingRoutesAdded(entry);
        }
    }

    private void bindingRoutesAdded(final Map.Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry) {
        Class<? extends BaseIdentity> context = entry.getKey().getRoutingContext();
        Class<? extends RpcService> service = entry.getKey().getRpcService();
        if (context != null) {
            getRpcForwarder(service, context).registerPaths(context, service, entry.getValue());
        }
    }

    private DomToBindingRpcForwarder getRpcForwarder(final Class<? extends RpcService> service,
        final Class<? extends BaseIdentity> context) {
        DomToBindingRpcForwarder potential = forwarders.get(service);
        if (potential != null) {
            return potential;
        }
        if (context == null) {
            potential = new DomToBindingRpcForwarder(service, mappingService, biRpcRegistry, baRpcRegistry,registryImpl);
        } else {
            potential = new DomToBindingRpcForwarder(service, context, mappingService, biRpcRegistry, baRpcRegistry,registryImpl);
        }

        forwarders.put(service, potential);
        return potential;
    }

    @Override
    public void onRpcImplementationAdded(final QName name) {

        final Optional<Class<? extends RpcService>> rpcInterface = mappingService.getRpcServiceClassFor(
            name.getNamespace().toString(), name.getFormattedRevision());
        if (rpcInterface.isPresent()) {
            getRpcForwarder(rpcInterface.get(), null).registerToBindingBroker();
        }
    }

    @Override
    public void onRpcImplementationRemoved(final QName name) {

    }
}

@@ -71,21 +71,89 @@
 ort 
-java.util.Map
+com.google.common.base.Optional;%0Aimport java.util.Map;%0Aimport java.util.Map.Entry
 ;%0Aim
@@ -202,17 +202,16 @@
 ashMap;%0A
-%0A
 import o
@@ -1127,49 +1127,8 @@
 e;%0A%0A
-import com.google.common.base.Optional;%0A%0A
 /**%0A
@@ -3031,24 +3031,58 @@
 %3E change) %7B%0A
+        // Process removals first%0A
         for 
@@ -3082,20 +3082,16 @@
    for (
-Map.
 Entry%3CRp
@@ -3160,20 +3160,15 @@
 .get
-Announcement
+Removal
 s().
@@ -3197,32 +3197,214 @@
     
-bindingRoutesAdded(entry
+final Class%3C? extends BaseIdentity%3E context = entry.getKey().getRoutingContext();%0A            if (context != null) %7B%0A                final Class%3C? extends RpcService%3E service = entry.getKey().getRpcService(
 );%0A 
@@ -3414,63 +3414,137 @@
     
-%7D%0A
     
-%7D%0A%0A
     
-private void bindingRoutesAdded(final Map.
+getRpcForwarder(service, context).removePaths(context, service, entry.getValue());%0A            %7D%0A        %7D%0A%0A        for (
 Entr
@@ -3600,16 +3600,55 @@
 %3E%3E entry
+ : change.getAnnouncements().entrySet()
 ) %7B%0A    
@@ -3643,32 +3643,42 @@
 et()) %7B%0A        
+    final 
 Class%3C? extends 
@@ -3737,32 +3737,81 @@
 text();%0A        
+    if (context != null) %7B%0A                final 
 Class%3C? extends 
@@ -3872,35 +3872,8 @@
     
-    if (context != null) %7B%0A
     
@@ -3957,32 +3957,46 @@
 ry.getValue());%0A
+            %7D%0A
         %7D%0A    %7D%0A

handle RPC route removal