/*
 * Copyright (c) 2014 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.controller.cluster.raft;

import com.google.common.base.Stopwatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import scala.concurrent.duration.FiniteDuration;

public class FollowerLogInformationImpl implements FollowerLogInformation {

    private final String id;

    private final AtomicLong nextIndex;

    private final AtomicLong matchIndex;

    private final Stopwatch stopwatch;

    private final long followerTimeoutMillis;

    public FollowerLogInformationImpl(String id, long nextIndex,
        long matchIndex, FiniteDuration followerTimeoutDuration) {
        this.id = id;
        this.nextIndex = new AtomicLong(nextIndex);
        this.matchIndex = new AtomicLong(matchIndex);
        this.stopwatch = new Stopwatch();
        this.followerTimeoutMillis = followerTimeoutDuration.toMillis();
    }

    @Override
    public long incrNextIndex(){
        return nextIndex.incrementAndGet();
    }

    @Override
    public long decrNextIndex() {
        return nextIndex.decrementAndGet();
    }

    @Override
    public void setNextIndex(long nextIndex) {
        this.nextIndex.set(nextIndex);
    }

    @Override
    public long incrMatchIndex(){
        return matchIndex.incrementAndGet();
    }

    @Override
    public void setMatchIndex(long matchIndex) {
        this.matchIndex.set(matchIndex);
    }

    @Override
    public String getId() {
        return id;
    }

    @Override
    public long getNextIndex() {
        return nextIndex.get();
    }

    @Override
    public long getMatchIndex() {
        return matchIndex.get();
    }

    @Override
    public boolean isFollowerActive() {
        long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS);
        return (stopwatch.isRunning()) && (elapsed <= followerTimeoutMillis);
    }

    @Override
    public void markFollowerActive() {
        if (stopwatch.isRunning()) {
            stopwatch.reset();
        }
        stopwatch.start();
    }

    @Override
    public void markFollowerInActive() {
        if (stopwatch.isRunning()) {
            stopwatch.stop();
        }
    }
}

@@ -477,16 +477,28 @@
 omicLong
+FieldUpdater
 ;%0Aimport
@@ -617,17 +617,16 @@
 ation %7B%0A
-%0A
     priv
@@ -633,55 +633,162 @@
 ate 
-final String id;%0A%0A    private final AtomicLong 
+static final AtomicLongFieldUpdater%3CFollowerLogInformationImpl%3E NEXT_INDEX_UPDATER = AtomicLongFieldUpdater.newUpdater(FollowerLogInformationImpl.class, %22
 next
@@ -788,27 +788,28 @@
 , %22nextIndex
+%22)
 ;%0A
-%0A
     private 
@@ -804,24 +804,31 @@
     private 
+static 
 final Atomic
@@ -831,27 +831,190 @@
 omicLong
- matchIndex
+FieldUpdater%3CFollowerLogInformationImpl%3E MATCH_INDEX_UPDATER = AtomicLongFieldUpdater.newUpdater(FollowerLogInformationImpl.class, %22matchIndex%22);%0A%0A    private final String id
 ;%0A%0A    p
@@ -1045,16 +1045,34 @@
 topwatch
+ = new Stopwatch()
 ;%0A%0A    p
@@ -1113,16 +1113,93 @@
 illis;%0A%0A
+    private volatile long nextIndex;%0A%0A    private volatile long matchIndex;%0A%0A
     publ
@@ -1369,31 +1369,16 @@
 Index = 
-new AtomicLong(
 nextInde
@@ -1374,25 +1374,24 @@
  = nextIndex
-)
 ;%0A        th
@@ -1410,76 +1410,18 @@
 x = 
-new AtomicLong(matchIndex);%0A        this.stopwatch = new Stopwatch()
+matchIndex
 ;%0A  
@@ -1560,25 +1560,34 @@
  return 
-nextIndex
+NEXT_INDEX_UPDATER
 .increme
@@ -1587,32 +1587,36 @@
 incrementAndGet(
+this
 );%0A    %7D%0A%0A    @O
@@ -1672,25 +1672,34 @@
  return 
-nextIndex
+NEXT_INDEX_UPDATER
 .decreme
@@ -1699,32 +1699,36 @@
 decrementAndGet(
+this
 );%0A    %7D%0A%0A    @O
@@ -1804,21 +1804,19 @@
 extIndex
-.set(
+ = 
 nextInde
@@ -1812,25 +1812,24 @@
  = nextIndex
-)
 ;%0A    %7D%0A%0A   
@@ -1888,26 +1888,35 @@
  return 
-matchIndex
+MATCH_INDEX_UPDATER
 .increme
@@ -1924,16 +1924,20 @@
 tAndGet(
+this
 );%0A    %7D
@@ -2028,13 +2028,11 @@
 ndex
-.set(
+ = 
 matc
@@ -2037,17 +2037,16 @@
 tchIndex
-)
 ;%0A    %7D%0A
@@ -2181,30 +2181,24 @@
 rn nextIndex
-.get()
 ;%0A    %7D%0A%0A   
@@ -2271,14 +2271,8 @@
 ndex
-.get()
 ;%0A  

use AtomicLongfieldUpdater in FollowerLogInformationImpl