/*
 * Copyright © 2017 SNLab 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.alto.ext.impl;

import com.google.common.util.concurrent.CheckedFuture;
import com.google.common.util.concurrent.Futures;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.alto.bwmonitor.rev150105.*;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.alto.bwmonitor.rev150105.speeds.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.alto.bwmonitor.rev150105.speeds.NodeBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.alto.bwmonitor.rev150105.speeds.NodeKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.Future;

public class BwmonitorImpl implements AltoBwmonitorService{
    private DataBroker db;
    private static final Logger LOG = LoggerFactory.getLogger(BwmonitorImpl.class);
    private boolean dataTreeInitialized = false;

    public BwmonitorImpl(DataBroker dataBroker ){
        this.db = dataBroker;
    }

    private boolean initializeDataTree(){
        WriteTransaction transaction = db.newWriteOnlyTransaction();
        InstanceIdentifier<Speeds> iid = InstanceIdentifier.create(Speeds.class);
        Speeds speeds = new SpeedsBuilder().build();
        transaction.put(LogicalDatastoreType.OPERATIONAL, iid, speeds);
        CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
        Futures.addCallback(future, new LoggingFuturesCallBack<Void>("Failed to create speeds", LOG));

        try {
            future.checkedGet();
        } catch (TransactionCommitFailedException e) {
            LOG.error(e.getMessage());
            return false;
        }
        dataTreeInitialized = true;
        return true;
    }

    private boolean writeToSpeeds(BwmonitorRegisterInput input){
        WriteTransaction transaction = db.newWriteOnlyTransaction();
        InstanceIdentifier<Node> iid = toInstanceIdentifier(input);
        Node node = new NodeBuilder().setNodeId(input.getNodeId()).setSpeed(0).build();
        transaction.put(LogicalDatastoreType.OPERATIONAL, iid, node);
        CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
        Futures.addCallback(future, new LoggingFuturesCallBack<Void>("Failed to write node to speeds", LOG));

        try {
            future.checkedGet();
        } catch (TransactionCommitFailedException e) {
            LOG.error(e.getMessage());
            return false;
        }
        return true;
    }

    private InstanceIdentifier<Node> toInstanceIdentifier(BwmonitorRegisterInput input){
        InstanceIdentifier<Node> iid = InstanceIdentifier.create(Speeds.class)
                .child(Node.class, new NodeKey(input.getNodeId()));
        return iid;
    }

    @Override
    public Future<RpcResult<BwmonitorRegisterOutput>> bwmonitorRegister(BwmonitorRegisterInput input) {
        LOG.error("Get Input: " + input.getNodeId());
        boolean success = true;
        if(!dataTreeInitialized) success = initializeDataTree();
        if(success) success = writeToSpeeds(input);
        BwmonitorRegisterOutput output = new BwmonitorRegisterOutputBuilder()
                .setResult(success).build();
        return RpcResultBuilder.success(output).buildFuture();
    }

    @Override
    public Future<RpcResult<BwmonitorQueryOutput>> bwmonitorQuery(BwmonitorQueryInput input) {
        return null;
    }
}

@@ -327,16 +327,56 @@
 .impl;%0A%0A
+import com.google.common.base.Optional;%0A
 import c
@@ -423,16 +423,16 @@
 Future;%0A
-
 import c
@@ -535,24 +535,95 @@
 DataBroker;%0A
+import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;%0A
 import org.o
@@ -762,16 +762,95 @@
 reType;%0A
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;%0A
 import o
@@ -1373,16 +1373,75 @@
 odeKey;%0A
+import org.opendaylight.yangtools.yang.binding.DataObject;%0A
 import o
@@ -1678,16 +1678,64 @@
 ctory;%0A%0A
+import java.util.concurrent.ExecutionException;%0A
 import j
@@ -4494,19 +4494,875 @@
     
-return null
+ReadTransaction transaction = db.newReadOnlyTransaction();%0A        InstanceIdentifier%3CNode%3E iid = InstanceIdentifier.create(Speeds.class).child(Node.class, new NodeKey(input.getNodeId()));%0A        try %7B%0A            Optional%3CNode%3E nodeData = transaction.read(LogicalDatastoreType.OPERATIONAL, iid).get();%0A            if(nodeData.isPresent())%7B%0A                BwmonitorQueryOutput output = new BwmonitorQueryOutputBuilder()%0A                        .setBandwidth(nodeData.get().getSpeed()).build();%0A                return RpcResultBuilder.success(output).buildFuture();%0A            %7D%0A        %7D catch (InterruptedException%7CExecutionException e)%7B%0A            LOG.error(e.getMessage());%0A        %7D%0A        BwmonitorQueryOutput output = new BwmonitorQueryOutputBuilder()%0A                .setBandwidth(-1).build();%0A        return RpcResultBuilder.success(output).buildFuture()
 ;%0A  

Complete bandwith query RPC implementation