//
// Copyright (c) 2014 VK.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
package com.vk.sdk.api.httpClient;
import android.os.Handler;
import android.os.Looper;
import com.vk.sdk.api.VKError;
/**
* Class for executing any kind of asynchronous operation
*/
public abstract class VKAbstractOperation {
public enum VKOperationState {
Created,
Ready,
Executing,
Paused,
Finished,
Canceled
}
/**
* Listener called after operation finished
*/
private VKOperationCompleteListener mCompleteListener;
/**
* Current operation state. Checked by stateTransitionIsValid function
*/
private VKOperationState mState = VKOperationState.Created;
/**
* Flag for cancel
*/
private boolean mCanceled = false;
/**
* Handler for notify main thread
*/
private static Handler mMainThreadHandler;
/**
* Return handler for main loop
*
* @return Main loop handler
*/
protected static Handler getMainThreadHandler() {
if (mMainThreadHandler == null) {
mMainThreadHandler = new Handler(Looper.getMainLooper());
}
return mMainThreadHandler;
}
public VKAbstractOperation() {
setState(VKOperationState.Ready);
}
/**
* Entry point for operation
*/
public abstract void start();
/**
* Cancels current operation and finishes it
*/
public void cancel() {
mCanceled = true;
setState(VKOperationState.Canceled);
}
/**
* Finishes current operation. Will call onComplete() function for completeListener
*/
public void finish() {
if (mCompleteListener != null) {
mCompleteListener.onComplete();
}
}
/**
* Set complete listener for current operation
*
* @param listener Complete listener
*/
protected void setCompleteListener(VKOperationCompleteListener listener) {
mCompleteListener = listener;
}
/**
* Returns current operation state
* @return state constant from {@link VKOperationState}
*/
protected VKOperationState state() { return mState; }
/**
* Sets operation state. Checks validity of state transition
*
* @param state New operation state
*/
protected void setState(VKOperationState state) {
if (isStateTransitionInvalid(mState, state, mCanceled)) {
return;
}
mState = state;
if (mState == VKOperationState.Finished ||
mState == VKOperationState.Canceled) {
finish();
}
}
/**
* Checks validity of state transition
*
* @param fromState Old state (current operation state)
* @param toState New state, sets by developer
* @param isCancelled Flag of cancelation
* @return Result of validation
*/
private boolean isStateTransitionInvalid(VKOperationState fromState, VKOperationState toState,
boolean isCancelled) {
switch (fromState) {
case Ready:
switch (toState) {
case Paused:
case Executing:
case Canceled:
return false;
case Finished:
return !isCancelled;
default:
return true;
}
case Executing:
switch (toState) {
case Paused:
case Finished:
case Canceled:
return false;
default:
return true;
}
case Finished:
case Canceled:
return true;
case Paused:
switch (toState) {
case Canceled:
return false;
default:
return toState != VKOperationState.Ready;
}
default:
return false;
}
}
/**
* Post runnable in main loop with delay
*
* @param r Runnable to post
*
*/
public static void postInMainQueueDelayed(Runnable r) {
getMainThreadHandler().postDelayed(r, (long) 300);
}
public static interface VKOperationCompleteListener {
public void onComplete();
}
public static abstract class VKAbstractCompleteListener<OperationType,ResponseType> {
public abstract void onComplete(OperationType operation, ResponseType response);
public abstract void onError(OperationType operation, VKError error);
}
}