/*
 * Copyright (c) 2015 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.pcep.topology.provider;

import static java.util.Objects.requireNonNull;

import com.google.common.util.concurrent.ListenableFuture;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import org.opendaylight.mdsal.binding.api.DataBroker;
import org.opendaylight.mdsal.binding.api.ReadTransaction;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev200720.PathComputationClient1;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev200720.Stateful1;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev200720.Tlvs3Builder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev200720.lsp.db.version.tlv.LspDbVersion;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev200720.speaker.entity.id.tlv.SpeakerEntityIdBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Tlvs1;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.open.object.open.TlvsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.Node1;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.PathComputationClient;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

final class PCEPStatefulPeerProposal {

    private static final Logger LOG = LoggerFactory.getLogger(PCEPStatefulPeerProposal.class);

    private final DataBroker dataBroker;
    private final InstanceIdentifier<Topology> topologyId;

    private PCEPStatefulPeerProposal(final DataBroker dataBroker, final InstanceIdentifier<Topology> topologyId) {
        this.dataBroker = requireNonNull(dataBroker);
        this.topologyId = requireNonNull(topologyId);
    }

    public static PCEPStatefulPeerProposal createStatefulPeerProposal(final DataBroker dataBroker,
            final InstanceIdentifier<Topology> topologyId) {
        return new PCEPStatefulPeerProposal(dataBroker, topologyId);
    }

    void setPeerProposal(final NodeId nodeId, final TlvsBuilder openTlvsBuilder, final byte[] speakerId) {
        if (isSynOptimizationEnabled(openTlvsBuilder)) {
            Optional<LspDbVersion> result = Optional.empty();
            try (ReadTransaction rTx = this.dataBroker.newReadOnlyTransaction()) {
                final ListenableFuture<Optional<LspDbVersion>> future = rTx.read(
                        LogicalDatastoreType.OPERATIONAL,
                        this.topologyId.child(Node.class, new NodeKey(nodeId)).augmentation(Node1.class)
                                .child(PathComputationClient.class).augmentation(PathComputationClient1.class)
                                .child(LspDbVersion.class));
                try {
                    result = future.get();
                } catch (final InterruptedException | ExecutionException e) {
                    LOG.warn("Failed to read toplogy {}.", InstanceIdentifier.keyOf(
                            PCEPStatefulPeerProposal.this.topologyId), e);

                }
            }
            if (speakerId == null && !result.isPresent()) {
                return;
            }
            final Tlvs3Builder syncBuilder = new Tlvs3Builder();

            if (result.isPresent()) {
                syncBuilder.setLspDbVersion(result.get());
            }
            if (speakerId != null) {
                syncBuilder.setSpeakerEntityId(new SpeakerEntityIdBuilder().setSpeakerEntityIdValue(speakerId).build());
            }
            openTlvsBuilder.addAugmentation(syncBuilder.build()).build();
        }
    }

    private static boolean isSynOptimizationEnabled(final TlvsBuilder openTlvsBuilder) {
        final Tlvs1 statefulTlv = openTlvsBuilder.augmentation(Tlvs1.class);
        if (statefulTlv != null && statefulTlv.getStateful() != null) {
            return statefulTlv.getStateful().augmentation(Stateful1.class) != null;
        }
        return false;
    }
}

@@ -3461,21 +3461,16 @@
 n rTx = 
-this.
 dataBrok
@@ -3496,24 +3496,120 @@
 action()) %7B%0A
+                // FIXME: we should be listening for this configuration and keep a proper cache%0A
             
@@ -3681,33 +3681,8 @@
 ead(
-%0A                        
 Logi
@@ -3727,37 +3727,32 @@
                 
-this.
 topologyId.child
@@ -4960,21 +4960,19 @@
   final 
-Tlvs1
+var
  statefu
@@ -5056,37 +5056,96 @@
 null
- && statefulTlv.getStateful()
+) %7B%0A            final var stateful = statefulTlv.getStateful();%0A            if (stateful
  != 
@@ -5144,32 +5144,36 @@
 eful != null) %7B%0A
+    
             retu
@@ -5183,33 +5183,16 @@
 stateful
-Tlv.getStateful()
 .augment
@@ -5223,16 +5223,30 @@
 = null;%0A
+            %7D%0A
         

Mark PCEPStatefulPeerProposal for evolution