/* ownCloud Android client application
 *   Copyright (C) 2011  Bartek Przybylski
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
package com.owncloud.android.operations;

import android.os.Handler;

import eu.alefzero.webdav.WebdavClient;

/**
 * Operation which execution involves one or several interactions with an ownCloud server.
 * 
 * Provides methods to execute the operation both synchronously or asynchronously.
 * 
 * @author David A. Velasco 
 */
public abstract class RemoteOperation implements Runnable {
	
	/** Object to interact with the ownCloud server */
	private WebdavClient mClient = null;
	
	/** Callback object to notify about the execution of the remote operation */
	private OnRemoteOperationListener mListener = null;
	
	/** Handler to the thread where mListener methods will be called */
	private Handler mListenerHandler = null;

	
	/**
	 *  Abstract method to implement the operation in derived classes.
	 */
	protected abstract RemoteOperationResult run(WebdavClient client); 
	
	
	/**
	 * Synchronously executes the remote operation
	 * 
	 * @param client	Client object to reach an ownCloud server during the execution of the operation.
	 * @return			Result of the operation.
	 */
	public final RemoteOperationResult execute(WebdavClient client) {
		if (client == null)
			throw new IllegalArgumentException("Trying to execute a remote operation with a NULL WebdavClient");
		mClient = client;
		return run(client);
	}

	
	/**
	 * Asynchronously executes the remote operation
	 * 
	 * @param client			Client object to reach an ownCloud server during the execution of the operation.
	 * @param listener			Listener to be notified about the execution of the operation.
	 * @param listenerHandler	Handler associated to the thread where the methods of the listener objects must be called.
	 * @return					Thread were the remote operation is executed.
	 */
	public final Thread execute(WebdavClient client, OnRemoteOperationListener listener, Handler listenerHandler) {
		if (client == null) {
			throw new IllegalArgumentException("Trying to execute a remote operation with a NULL WebdavClient");
		}
		mClient = client;
		
		if (listener == null) {
			throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a listener to notiy the result");
		}
		mListener = listener;
		
		if (listenerHandler == null) {
			throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a handler to the listener's thread");
		}
		mListenerHandler = listenerHandler;
		
		Thread runnerThread = new Thread(this);
		runnerThread.start();
		return runnerThread;
	}
	
    /**
     * Synchronously retries the remote operation using the same WebdavClient in the last call to {@link RemoteOperation#execute(WebdavClient)}
     * 
     * @param listener          Listener to be notified about the execution of the operation.
     * @param listenerHandler   Handler associated to the thread where the methods of the listener objects must be called.
     * @return                  Thread were the remote operation is executed.
     */
    public final RemoteOperationResult retry() {
        return execute(mClient);
    }
    
    /**
     * Asynchronously retries the remote operation using the same WebdavClient in the last call to {@link RemoteOperation#execute(WebdavClient, OnRemoteOperationListener, Handler)}
     * 
     * @param listener          Listener to be notified about the execution of the operation.
     * @param listenerHandler   Handler associated to the thread where the methods of the listener objects must be called.
     * @return                  Thread were the remote operation is executed.
     */
    public final Thread retry(OnRemoteOperationListener listener, Handler listenerHandler) {
        return execute(mClient, listener, listenerHandler);
    }
	
	
	/**
	 * Asynchronous execution of the operation 
	 * started by {@link RemoteOperation#execute(WebdavClient, OnRemoteOperationListener, Handler)}, 
	 * and result posting.
	 */
    @Override
    public final void run() {
    	final RemoteOperationResult result = execute(mClient);
    	
        if (mListenerHandler != null && mListener != null) {
        	mListenerHandler.post(new Runnable() {
                @Override
                public void run() {
                    mListener.onRemoteOperationFinish(RemoteOperation.this, result);
                }
            });
        }
    }
	
	
}
