/*
 *  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 2 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, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef UQM_FLASH_H_
#define UQM_FLASH_H_

/*
 * This code can draw three kinds of flashing areas.
 * - a rectangular highlight area. The brightness of the area oscilates.
 * - an overlay; an image is laid over an area, with oscilating brightness.
 * - a transition/cross-fade between two images.
 *
 * NB. The graphics lock should not be held when any of the Flash functions
 *     is called.
 *
 *
 * Example:
 *
 * // We create the flash context; it is used to manipulate the flash
 * // rectangle while it exists.
 * FlashContext *fc = Flash_createHighlight (gfxContext, rect);
 * 
 * // Specify how bright the flash is at the beginning and ending of the
 * // sequence.
 * Flash_setMergeFactors(fc, 2, 3, 2);
 *
 * // We change the flashing speed from the defaults.
 * Flash_setSpeed (fc, ONE_SECOND, ONE_SECOND, ONE_SECOND, ONE_SECOND);
 * 
 * // During cross-fades, update 8 times per second.
 * Flash_setFrameTime (fc, ONE_SECOND / 8);
 *
 * // We start the flashing. The default is to start from the "off" state.
 * Flash_start (fc);
 *
 * // Some other stuff happens
 * ...
 *
 * // The user has activated the selection. We pause for instance while
 * // a pop-up window is active.
 * Flash_pause (fc);
 *
 * // We set the flashing rectangle full on, to indicate the current
 * // selection while the popup is active.
 * Flash_setState (FlashState_on);
 * ...
 * // Continue the flashing.
 * Flash_continue (fc);
 * ...
 * // Modifying the graphics of the area that is flashing:
 * void Flash_preUpdate (fc);
 * ... // do drawing
 * void Flash_postUpdate (fc);
 * ...
 * // We're done. Terminating the flash restores the flash area to its
 * // original state.
 * Flash_terminate (fc);
 *
 *
 * Periodically, Flash_process() should be called on the flash context,
 * so that the flashing square is updated.
 * You can use Flash_nextTime() to determine when the next update is needed,
 * or just call Flash_process() to try (it does no updates if not needed).
 *
 * Limitations:
 *
 * * Functions that draw to the gfxContext or read the original gfxContext
 *   contents, which is most of them, must be called with gfxContext having
 *   the same clip-rect as it did when other drawing functions were called.
 *   Otherwise, original contents restoration may draw to the wrong area, or
 *   the wrong area may be read.
 *   There may be cases where one would *want* that to happen, and such
 *   cases are not covered by this limitation.
 * * Multiple flashes may be used simultaneously, but don't let them
 *   overlap; artifacts would occur.
 */

#include "libs/gfxlib.h"
#include "libs/timelib.h"

#if defined(__cplusplus)
extern "C" {
#endif

typedef enum {
	FlashState_fadeIn = 0,
			// Someway between on and off, going towards on.
	FlashState_on = 1,
			// The overlay image is visible at 100% opacity.
	FlashState_fadeOut = 2,
			// Someway between on and off, going towards off.
	FlashState_off = 3,
			// The overlay image is not visible.
} FlashState;

typedef struct FlashContext FlashContext;

#ifdef FLASH_INTERNAL
typedef enum {
	FlashType_highlight,
	FlashType_transition,
	FlashType_overlay,
} FlashType;

struct FlashContext {
	CONTEXT gfxContext;
			// The graphics context used for drawing.

	RECT rect;
			// The rectangle to flash.
			
	FRAME original;
			// The original contents of the flash area.

	FlashType type;
			// The type of flash animation.

	union {
		/*struct {
		} highlight;*/
		struct {
			FRAME first;
					// The first image from the transition (cross-fade).
					// (FRAME) 0 means that the original is to be used.
			FRAME final;
					// The last image from the transition.
					// (FRAME) 0 means that the original is to be used.
		} transition;
		struct {
			FRAME frame;
		} overlay;
	} u;

	int startNumer;
			// Numerator for the merge factor for the on state.
	int endNumer;
			// Numerator for the merge factor for the off state.
	int denom;
			// Denominator for the merge factor.
	
	TimeCount fadeInTime;
	TimeCount onTime;
	TimeCount fadeOutTime;
	TimeCount offTime;

	TimeCount frameTime;

	FlashState state;
	TimeCount lastStateTime;
			// Time of the last state change.
	TimeCount lastFrameTime;
			// Time of the last frame draw.

	BOOLEAN started;
	BOOLEAN paused;
	BOOLEAN isPulsing;

	FRAME *cache;
	COUNT cacheSize;

	COUNT lastFrameIndex;
			// Last frame drawn; used to determine whether a frame needs to
			// be redawn. If a cache is used, this is the index in the cache.
			// If no cache is used, this is either 0, 1, or 2, for
			// the respectively first, last, or other frame for the flash
			// animation.
};

#	define Flash_DEFAULT_FADE_IN_TIME   0
#	define Flash_DEFAULT_ON_TIME        (ONE_SECOND / 8)
#	define Flash_DEFAULT_FADE_OUT_TIME  0
#	define Flash_DEFAULT_OFF_TIME       (ONE_SECOND / 8)

#	define Flash_DEFAULT_CACHE_SIZE 9
#endif  /* FLASH_INTERNAL */


FlashContext *Flash_createHighlight (CONTEXT gfxContext, const RECT *rect);
FlashContext *Flash_createTransition (CONTEXT gfxContext,
		const POINT *origin, FRAME first, FRAME final);
FlashContext *Flash_createOverlay (CONTEXT gfxContext,
		const POINT *origin, FRAME overlay);

void Flash_setState (FlashContext *context, FlashState state,
		TimeCount timeSpentInState);
void Flash_start (FlashContext *context);
void Flash_terminate (FlashContext *context);
void Flash_pause (FlashContext *context);
void Flash_continue (FlashContext *context);
void Flash_process (FlashContext *context);
void Flash_setSpeed (FlashContext *context, TimeCount fadeInTime,
		TimeCount onTime, TimeCount fadeOutTime, TimeCount offTime);
void Flash_setMergeFactors(FlashContext *context, int startNumer,
		int endNumer, int denom);
void Flash_setFrameTime (FlashContext *context, TimeCount frameTime);
void Flash_setPulseBox (FlashContext *context, BOOLEAN isPulsing);
BOOLEAN Flash_getPulseBox (FlashContext *context);
TimeCount Flash_nextTime (FlashContext *context);
void Flash_setRect (FlashContext *context, const RECT *rect);
void Flash_getRect (FlashContext *context, RECT *rect);
void Flash_setOverlay(FlashContext *context, const POINT *origin,
		FRAME overlay, BOOLEAN cleanup); 
void Flash_preUpdate (FlashContext *context);
void Flash_postUpdate (FlashContext *context);
void Flash_setCacheSize (FlashContext *context, COUNT size);
COUNT Flash_getCacheSize (const FlashContext *context);
void Flash_UpdateOriginal (FlashContext *context);


#if defined(__cplusplus)
}
#endif

#endif  /* UQM_FLASH_H_ */

