/*
 * Copyright 2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.kuujo.copycat.atomic;

import net.kuujo.copycat.cluster.Cluster;
import net.kuujo.copycat.resource.Resource;
import net.kuujo.copycat.state.Read;
import net.kuujo.copycat.state.StateMachine;
import net.kuujo.copycat.state.Write;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Asynchronous atomic value.
 *
 * @author <a href="http://github.com/kuujo">Jordan Halterman</a>
 */
public class AsyncReference<T> implements Resource<AsyncReference<T>>, AsyncReferenceProxy<T> {
  private final StateMachine<State> stateMachine;
  private final AsyncReferenceProxy<T> proxy;

  @SuppressWarnings("unchecked")
  public AsyncReference(StateMachine<State> stateMachine) {
    this.stateMachine = stateMachine;
    this.proxy = stateMachine.createProxy(AsyncReferenceProxy.class);
  }

  @Override
  public String name() {
    return stateMachine.name();
  }

  @Override
  public Cluster cluster() {
    return stateMachine.cluster();
  }

  @Override
  public CompletableFuture<T> get() {
    return proxy.get();
  }

  @Override
  public CompletableFuture<Void> set(T value) {
    return proxy.set(value);
  }

  @Override
  public CompletableFuture<T> getAndSet(T value) {
    return proxy.getAndSet(value);
  }

  @Override
  public CompletableFuture<Boolean> compareAndSet(T expect, T update) {
    return proxy.compareAndSet(expect, update);
  }

  @Override
  public synchronized CompletableFuture<AsyncReference<T>> open() {
    return stateMachine.open().thenApply(v -> this);
  }

  @Override
  public boolean isOpen() {
    return stateMachine.isOpen();
  }

  @Override
  public synchronized CompletableFuture<Void> close() {
    return stateMachine.close();
  }

  @Override
  public boolean isClosed() {
    return stateMachine.isClosed();
  }

  /**
   * Asynchronous reference state.
   */
  public static class State<T> {
    private AtomicReference<T> value = new AtomicReference<>();

    @Read
    public T get() {
      return this.value.get();
    }

    @Write
    public void set(T value) {
      this.value.set(value);
    }

    @Write
    public T getAndSet(T value) {
      return this.value.getAndSet(value);
    }

    @Write
    public boolean compareAndSet(T expect, T update) {
      return this.value.compareAndSet(expect, update);
    }
  }

}

@@ -762,16 +762,57 @@
 e.Read;%0A
+import net.kuujo.copycat.state.StateLog;%0A
 import n
@@ -848,16 +848,16 @@
 achine;%0A
-
 import n
@@ -1190,16 +1190,212 @@
 xy%3CT%3E %7B%0A
+%0A  /**%0A   * Returns a new asynchronous reference builder.%0A   *%0A   * @return A new asynchronous reference builder.%0A   */%0A  public static %3CT%3E Builder%3CT%3E builder() %7B%0A    return new Builder%3C%3E();%0A  %7D%0A%0A
   privat
@@ -1412,32 +1412,35 @@
 ateMachine%3CState
+%3CT%3E
 %3E stateMachine;%0A
@@ -1519,16 +1519,16 @@
 ecked%22)%0A
-
   public
@@ -1561,16 +1561,19 @@
 ne%3CState
+%3CT%3E
 %3E stateM
@@ -3187,10 +3187,666 @@
  %7D%0A  %7D%0A%0A
+  /**%0A   * Asynchronous set builder.%0A   */%0A  public static class Builder%3CT%3E implements net.kuujo.copycat.Builder%3CAsyncReference%3CT%3E%3E %7B%0A    private final StateMachine.Builder%3CState%3CT%3E%3E builder = StateMachine.%3CState%3CT%3E%3Ebuilder().withState(new State%3C%3E());%0A%0A    private Builder() %7B%0A    %7D%0A%0A    /**%0A     * Sets the reference state log.%0A     *%0A     * @param stateLog The reference state log.%0A     * @return The reference builder.%0A     */%0A    public Builder%3CT%3E withLog(StateLog stateLog) %7B%0A      builder.withLog(stateLog);%0A      return this;%0A    %7D%0A%0A    @Override%0A    public AsyncReference%3CT%3E build() %7B%0A      return new AsyncReference%3C%3E(builder.build());%0A    %7D%0A  %7D%0A%0A
 %7D%0A

Add atomic reference builder.