/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * The contents of this file are subject to the Netscape Public License
 * Version 1.0 (the "NPL"); you may not use this file except in
 * compliance with the NPL.  You may obtain a copy of the NPL at
 * http://www.mozilla.org/NPL/
 *
 * Software distributed under the NPL is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
 * for the specific language governing rights and limitations under the
 * NPL.
 *
 * The Initial Developer of this code under the NPL is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
 * Reserved.
 */
 
#pragma once

//========================================================================================
// This file contains a suite of classes that allow posting and deferred execution
// of tasks in any powerplant application (except for CDeferredCloseTask, which is
// specific to Communicator).

// CDeferredTaskManager:	A singleton class, manages each per-window queue of tasks,
//							together with one global "nil" queue. It is created only when
//							a task is first posted, and is deleted as soon as no more
//							tasks exist.
// CDeferredTaskQueue:		A queue of tasks.  Each task belongs to a window (except that
//							one global "nil" queue is allowed), and tasks for
//							different windows are in different queues.  A queue is created
//							only when needed and is deleted immediately it becomes empty.

// CDeferredTask:			The abstract base class for tasks that can be posted.
// CDeferredCommand			This is an example of a deferred task object.  Its ExecuteSelf()
//							method calls ObeyCommand
// CDeferredMessage			This is another example, but calls ListenToMessage instead.
// CDeferredCloseTask		Another example.  Closes a window when it's safe.
//========================================================================================

#include <LPeriodical.h>

class CDeferredTaskQueue; // forward.
class CDeferredTask; // forward.

//========================================================================================
class CDeferredTaskManager
//	On each idle, the task manager will walk the queue list.  For each queue, it will
//	take the following action:
//		Tell the first task to execute.  If the task returns true, the task is then
//		deleted. If it returns false, it is left in the queue to be tried on the next idle.
//	There are only a few public entry points: Post and Remove.  Each of these has
//	an LPane* parameter that is used to work out which window, and hence which queue, the
//	task belongs to.  When posting, a new queue will be opened for the window in question,
//	if none exists.  When removing, the queue is deleted if no more tasks remain in it.
//========================================================================================
:	public LPeriodical
{
	public:		// ----------   BEGIN PUBLIC API ------------- //
		static void							Post(CDeferredTask* inTask, LPane* inPane, 
													bool inUnique = false);
												// Post a task to the end of the queue. If
												// inUnique is true all others of the same
												// type will be removed.
		static void							Remove(CDeferredTask*& inTask, LPane* inPane);
												// Remove  task.
		static void							ClearQueue(LPane* inPane);
												// Remove all tasks from this queue.
		static void							DoQuit(Int32 inSaveOption);
												// Finish all the close tasks.
				// ----------    END PUBLIC API  ------------- //
	protected:
											CDeferredTaskManager();
											~CDeferredTaskManager();
		virtual void						SpendTime(const EventRecord&);
		void								DoExecuteTasks();
		void								DoPost(
												CDeferredTask* inTask,
												LPane* inPane,
												Boolean inUnique);
		void								DoRemove(
												CDeferredTask*& inTask,
												LPane* inPane);
		void								DoRemove(
												CDeferredTask*& inTask,
												LWindow* inWindow);
		void								DoClearQueue(LPane* inPane);
		void								DoClearQueue(LWindow* inWindow);
		void								RemoveNextQueueAfter(
												CDeferredTaskQueue* inPreviousQueue);
//	data
	protected:
		CDeferredTaskQueue*					mQueueList;
		static CDeferredTaskManager*		sManager;
}; // class CDeferredTaskManager

//========================================================================================
class CDeferredTaskQueue
//	There is one queue per window, and optionally one global one (with mQueueWindow
//	== nil).  The first task in each queue "blocks" any subsequent tasks in the same queue.
//	FIFO order is thus guaranteed.
//========================================================================================
{
	friend class CDeferredTaskManager;
	protected:
											CDeferredTaskQueue(LWindow* inWindow);
											~CDeferredTaskQueue();
		void								DoPost(CDeferredTask* inTask);
		void								DoRemove(CDeferredTask*& inTask);
		void								DoRemoveType(CDeferredTask* inTask);
		void								DoClearSelf();
//	data
	protected:
		LWindow*							mQueueWindow;
		CDeferredTaskQueue*					mNext;
		CDeferredTask*						mFrontTask;
}; // class CDeferredWindowTaskQueue

//========================================================================================
class CDeferredTask
// Base class for various useful types of deferred tasks.  Derived classes must implement
// ExecuteSelf(), returning an ExecuteResult value of:
//	eWaitStayFront		task is to be tried again, and wishes to remain blocking the queue
//	eWaitDoneDelete		task has done its work and is to be deleted
//	eWaitStepBack		task is to be tried again, but willing to step back in the queue
//						to give the next task a chance. (background, low priority)
//========================================================================================
{
	protected:
		enum ExecuteResult { eWaitStayFront, eDoneDelete, eWaitStepBack };
											CDeferredTask();
		virtual								~CDeferredTask();
		virtual ExecuteResult				ExecuteSelf() = 0;
	private:
		ExecuteResult						Execute();
	// data
	protected:
		friend class CDeferredTaskManager;
		friend class CDeferredTaskQueue;
		CDeferredTask*						mNext;
		Boolean								mExecuting; // reentrancy protection.
#if DEBUG
		UInt32								mExecuteAttemptCount;
#endif
}; // class CDeferredTask

class LCommander;

//========================================================================================
class CDeferredCommand
// This is an example of a CDeferredTask.  This one calls ObeyCommand on a commander.
//========================================================================================
:	public CDeferredTask
{
	public:
											CDeferredCommand(
												LCommander* inCommander,
												CommandT	inCommand,
												void*		ioParam);
		virtual ExecuteResult					ExecuteSelf();
	// data
		LCommander*							mCommander;
		CommandT							mCommand;
		void*								mParam;
}; // class CDeferredCommand

class LListener;

//========================================================================================
class CDeferredMessage
// This is an example of a CDeferredTask.  This one calls ListenToMessage on a listener.
//========================================================================================
:	public CDeferredTask
{
	public:
											CDeferredMessage(
												LListener*	inListener,
												MessageT	inMessage,
												void*		ioParam);
		virtual ExecuteResult				ExecuteSelf();
	// data
		LListener*							mListener;
		MessageT							mMessage;
		void*								mParam;
}; // class CDeferredMessage

class CNetscapeWindow;

//========================================================================================
class CDeferredCloseTask
// This guy closes a window at a later, safer time.  The parameter to the constructor is
// any pane (usually the calling pane), from which the window object is deduced.  This
// only works for CNetscapeWindows
//========================================================================================
:	public CDeferredTask
{
	public:
											CDeferredCloseTask(LPane* inPane);
		static CDeferredCloseTask*			DeferredClose(LPane* inPane);
	protected:
		virtual ExecuteResult				ExecuteSelf();
// data
	protected:
		CNetscapeWindow*					mWindow;
}; // class CDeferredCloseTask
