/*******************************************************************************
 * Copyright (c) 1999, 2014 IBM Corp.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Eclipse Distribution License v1.0 which accompany this distribution. 
 *
 * The Eclipse Public License is available at 
 *    http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at 
 *   http://www.eclipse.org/org/documents/edl-v10.php.
 */
package org.eclipse.paho.android.service;

import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttAsyncClient;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttSecurityException;

/**
 * <p>
 * Implementation of the IMqttToken interface for use from within the
 * MqttAndroidClient implementation
 */

class MqttTokenAndroid implements IMqttToken {

  private IMqttActionListener listener;

  private volatile boolean isComplete;

  private volatile MqttException lastException;

  private Object waitObject = new Object();

  private MqttAndroidClient client;

  private Object userContext;

  private String[] topics;

  private IMqttToken delegate; // specifically for getMessageId

  private MqttException pendingException;

  /**
   * Standard constructor
   * 
   * @param client used to pass MqttAndroidClient object
   * @param userContext used to pass context
   * @param listener optional listener that will be notified when the action completes. Use null if not required.
   */
  MqttTokenAndroid(MqttAndroidClient client,
      Object userContext, IMqttActionListener listener) {
    this(client, userContext, listener, (String[]) null);
  }

  /**
   * Constructor for use with subscribe operations
   * 
   * @param client used to pass MqttAndroidClient object
   * @param userContext used to pass context
   * @param listener optional listener that will be notified when the action completes. Use null if not required.
   * @param topics topics to subscribe to, which can include wildcards.
   */
  MqttTokenAndroid(MqttAndroidClient client,
      Object userContext, IMqttActionListener listener, String[] topics) {
    this.client = client;
    this.userContext = userContext;
    this.listener = listener;
    this.topics = topics;
  }

  /**
   * @see org.eclipse.paho.client.mqttv3.IMqttToken#waitForCompletion()
   */
  @Override
  public void waitForCompletion() throws MqttException, MqttSecurityException {
    synchronized (waitObject) {
      try {
        waitObject.wait();
      }
      catch (InterruptedException e) {
        // do nothing
      }
    }
    if (pendingException != null) {
      throw pendingException;
    }
  }

  /**
   * @see org.eclipse.paho.client.mqttv3.IMqttToken#waitForCompletion(long)
   */
  @Override
  public void waitForCompletion(long timeout) throws MqttException,
      MqttSecurityException {
    synchronized (waitObject) {
      try {
        waitObject.wait(timeout);
      }
      catch (InterruptedException e) {
        // do nothing
      }
      if (!isComplete) {
        throw new MqttException(MqttException.REASON_CODE_CLIENT_TIMEOUT);
      }
      if (pendingException != null) {
        throw pendingException;
      }
    }
  }

  /**
   * notify successful completion of the operation
   */
  void notifyComplete() {
    synchronized (waitObject) {
      isComplete = true;
      waitObject.notifyAll();
      if (listener != null) {
        listener.onSuccess(this);
      }
    }
  }

  /**
   * notify unsuccessful completion of the operation
   */
  void notifyFailure(Throwable exception) {
    synchronized (waitObject) {
      isComplete = true;
      if (exception instanceof MqttException) {
        pendingException = (MqttException) exception;
      }
      else {
        pendingException = new MqttException(exception);
      }
      waitObject.notifyAll();
      if (exception instanceof MqttException) {
        lastException = (MqttException) exception;
      }
      if (listener != null) {
        listener.onFailure(this, exception);
      }
    }

  }

  /**
   * @see org.eclipse.paho.client.mqttv3.IMqttToken#isComplete()
   */
  @Override
  public boolean isComplete() {
    return isComplete;
  }

  void setComplete(boolean complete) {
    isComplete = complete;
  }

  /**
   * @see org.eclipse.paho.client.mqttv3.IMqttToken#getException()
   */
  @Override
  public MqttException getException() {
    return lastException;
  }

  void setException(MqttException exception) {
    lastException = exception;
  }

  /**
   * @see org.eclipse.paho.client.mqttv3.IMqttToken#getClient()
   */
  @Override
  public IMqttAsyncClient getClient() {
    return client;
  }

  /**
   * @see org.eclipse.paho.client.mqttv3.IMqttToken#setActionCallback(IMqttActionListener)
   */
  @Override
  public void setActionCallback(IMqttActionListener listener) {
    this.listener = listener;
  }

  /**
   * @see org.eclipse.paho.client.mqttv3.IMqttToken#getActionCallback()
   */
  @Override
  public IMqttActionListener getActionCallback() {
    return listener;
  }

  /**
   * @see org.eclipse.paho.client.mqttv3.IMqttToken#getTopics()
   */
  @Override
  public String[] getTopics() {
    return topics;
  }

  /**
   * @see org.eclipse.paho.client.mqttv3.IMqttToken#setUserContext(Object)
   */
  @Override
  public void setUserContext(Object userContext) {
    this.userContext = userContext;

  }

  /**
   * @see org.eclipse.paho.client.mqttv3.IMqttToken#getUserContext()
   */
  @Override
  public Object getUserContext() {
    return userContext;
  }

  void setDelegate(IMqttToken delegate) {
    this.delegate = delegate;
  }

  /**
   * @see org.eclipse.paho.client.mqttv3.IMqttToken#getMessageId()
   */
  @Override
  public int getMessageId() {
    return (delegate != null) ? delegate.getMessageId() : 0;
  }
}

@@ -868,16 +868,85 @@
 ception;
+%0Aimport org.eclipse.paho.client.mqttv3.internal.wire.MqttWireMessage;
 %0A%0A/**%0A *
@@ -6075,11 +6075,200 @@
 : 0;%0A  %7D
+%0A%0A@Override%0Apublic int%5B%5D getGrantedQos() %7B%0A%09return null;%0A%7D%0A%0A@Override%0Apublic MqttWireMessage getResponse() %7B%0A%09return null;%0A%7D%0A%0A@Override%0Apublic boolean getSessionPresent() %7B%0A%09return false;%0A%7D
 %0A%7D%0A

Change MqttTokenAndroid.java to consist with changes in IMqttToken.java in paho java