/*
 * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.bgpcep.topology.provider.bgp;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
import org.opendaylight.controller.md.sal.common.api.data.DataModification;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.Route;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;

public abstract class AbstractLocRIBListener<T extends Route> implements LocRIBListener {
	private static final Logger LOG = LoggerFactory.getLogger(AbstractLocRIBListener.class);
	private final InstanceIdentifier<Topology> topology;
	private final Item<T> item;

	protected AbstractLocRIBListener(final InstanceIdentifier<Topology> topology, final Class<T> idClass) {
		this.topology = Preconditions.checkNotNull(topology);
		this.item = new Item<T>(Preconditions.checkNotNull(idClass));
	}

	public final InstanceIdentifier<Topology> getTopology() {
		return topology;
	}

	protected abstract void createObject(DataModification<InstanceIdentifier<?>, DataObject> trans, InstanceIdentifier<T> id, T value);
	protected abstract void removeObject(DataModification<InstanceIdentifier<?>, DataObject> trans, InstanceIdentifier<T> id, T value);

	private InstanceIdentifier<T> changedObject(final InstanceIdentifier<?> id) {
		final List<PathArgument> p = id.getPath();

		final int i = p.indexOf(item);
		Preconditions.checkArgument(i > -1, "Class %s not found in identifier %s", item.getType(), id);
		return new InstanceIdentifier<>(p.subList(0, i + 1), item.getType());
	}

	@Override
	public final void onLocRIBChange(final DataModification<InstanceIdentifier<?>, DataObject> trans,
			final DataChangeEvent<InstanceIdentifier<?>, DataObject> event) {

		final Set<InstanceIdentifier<T>> ids = new HashSet<>();
		for (final InstanceIdentifier<?> i : event.getRemovedOperationalData()) {
			ids.add(Preconditions.checkNotNull(changedObject(i)));
		}
		for (final InstanceIdentifier<?> i : event.getUpdatedOperationalData().keySet()) {
			ids.add(Preconditions.checkNotNull(changedObject(i)));
		}
		for (final InstanceIdentifier<?> i : event.getCreatedOperationalData().keySet()) {
			ids.add(Preconditions.checkNotNull(changedObject(i)));
		}

		final Map<InstanceIdentifier<?>, DataObject> o = event.getOriginalOperationalData();
		final Map<InstanceIdentifier<?>, DataObject> n = event.getUpdatedOperationalData();
		for (final InstanceIdentifier<T> i : ids) {
			final T oldValue = item.getType().cast(o.get(i));
			final T newValue = item.getType().cast(n.get(i));

			LOG.debug("Updating object {} value {} -> {}", i, oldValue, newValue);
			if (oldValue != null) {
				removeObject(trans, i, oldValue);
			}
			if (newValue != null) {
				createObject(trans, i, newValue);
			}
		}
	}
}

@@ -451,16 +451,88 @@
 l.Set;%0A%0A
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;%0A
 import o
@@ -1162,24 +1162,81 @@
 thArgument;%0A
+import org.opendaylight.yangtools.yang.common.RpcResult;%0A
 import org.s
@@ -1325,16 +1325,183 @@
 ditions;
+%0Aimport com.google.common.util.concurrent.FutureCallback;%0Aimport com.google.common.util.concurrent.Futures;%0Aimport com.google.common.util.concurrent.JdkFutureAdapters;
 %0A%0Apublic
@@ -3882,14 +3882,417 @@
 %09%09%09%7D%0A%09%09%7D
+%0A%0A%09%09Futures.addCallback(JdkFutureAdapters.listenInPoolThread(trans.commit()),%0A%09%09%09%09new FutureCallback%3CRpcResult%3CTransactionStatus%3E%3E() %7B%0A%09%09%09@Override%0A%09%09%09public void onSuccess(final RpcResult%3CTransactionStatus%3E result) %7B%0A%09%09%09%09// Nothing to do%0A%09%09%09%7D%0A%0A%09%09%09@Override%0A%09%09%09public void onFailure(final Throwable t) %7B%0A%09%09%09%09LOG.error(%22Failed to propagate change by listener %7B%7D%22, AbstractLocRIBListener.this);%0A%09%09%09%7D%0A%09%09%7D);
 %0A%09%7D%0A%7D%0A

Fix transaction not being committed