/*==LICENSE==*

CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011  Cyan Worlds, Inc.

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/>.

You can contact Cyan Worlds, Inc. by email legal@cyan.com
 or by snail mail at:
      Cyan Worlds, Inc.
      14617 N Newport Hwy
      Mead, WA   99021

*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
//																			//
//	plPlates - Header file for the plates and plPlateManager				//
//																			//
//////////////////////////////////////////////////////////////////////////////

#ifndef _plPlates_h
#define _plPlates_h

#include "hsTypes.h"
#include "hsStlUtils.h"
#include "hsColorRGBA.h"
#include "hsTemplates.h"
#include "hsUtils.h"
#include "hsMatrix44.h"



//// plPlate Class Definition ////////////////////////////////////////////////
//	plPlate is the actual plate object that represents one plate on the 
//	screen. It has a transform matrix (which includes position, scale and
//	rotation), a material, a depth value and a color that is applied to all
//	four corners. All plates are parallelograms. 

class plPlateManager;
class hsGMaterial;
class plMipmap;
class plBitmap;

class plPlate
{
	friend class plPlateManager;

	protected:
		
		hsMatrix44		fXformMatrix;
		hsGMaterial		*fMaterial;
		plMipmap		*fMipmap;
		hsScalar		fDepth, fOpacity;
		UInt32			fFlags;
		char			fTitle[ 64 ];

		plPlate			*fNext;
		plPlate			**fPrevPtr;

		plPlate			**fOwningHandle;

		static UInt32	fMagicUniqueKeyInt;

		plPlate( plPlate** owningHandle );
		virtual ~plPlate();

		void	ILink( plPlate **back );

		void	IUnlink( void )
		{
			hsAssert( fPrevPtr, "Plate not in list" );
			if( fNext )
				fNext->fPrevPtr = fPrevPtr;
			*fPrevPtr = fNext;

			fNext = nil;
			fPrevPtr = nil;
		}

		void ISetResourceAlphas(UInt32 colorKey);

	public:

		enum 
		{
			kFlagVisible		= 0x00000001,
			kFlagLocalMaterial	= 0x00000002,
			kFlagIsAGraph		= 0x00000004
		};

		/// Basic properties

		void	SetTransform( hsMatrix44 &matrix, hsBool reSort = true );
		void	SetMaterial( hsGMaterial *material );
		void	SetTexture(plBitmap *texture); // Creates a new single layer material to use the texture.
		void	SetTitle( const char *title ) { if( title != nil ) strncpy( fTitle, title, sizeof( fTitle ) ); else fTitle[ 0 ] = 0; }

		hsGMaterial		*GetMaterial( void ) { return fMaterial; }
		hsMatrix44		&GetTransform( void ) { return fXformMatrix; }
		const char		*GetTitle( void ) { return fTitle; }
		UInt32			GetFlags( void ) { return fFlags; }

		void	SetVisible( hsBool vis ) { if( vis ) fFlags |= kFlagVisible; else fFlags &= ~kFlagVisible; }
		hsBool	IsVisible( void );

		void	SetOpacity( hsScalar opacity = 1.f );

		plPlate	*GetNext( void ) { return fNext; }


		/// Helper functions
		
		void	SetDepth( hsScalar depth) { fDepth = depth; }
		void	SetPosition( hsScalar x, hsScalar y, hsScalar z = -1.0f );
		void	SetSize( hsScalar width, hsScalar height, bool adjustByAspectRatio = false );

		plMipmap		*CreateMaterial( UInt32 width, UInt32 height, hsBool withAlpha, plMipmap* texture = NULL );
		void			CreateFromResource( const char *resName, UInt32 colorKey = 0x00ff00ff );
		void			ReloadFromResource( const char *resName, UInt32 colorKey = 0x00ff00ff );
		void			CreateFromJPEGResource( const char *resName, UInt32 colorKey = 0x00ff00ff );
		void			ReloadFromJPEGResource( const char *resName, UInt32 colorKey = 0x00ff00ff );
};

//// plGraphPlate Class Definition ///////////////////////////////////////////
//	A derivation of plPlate that maintains a procedural texture which displays
//	a scrolling graph of data.

class plGraphPlate : public plPlate
{
	protected:
		UInt32			fBGHexColor, fAxesHexColor, fGraphHexColor;
		std::vector<UInt32>	fDataHexColors;
		UInt32			fMin, fMax, fLabelMin, fLabelMax;
		std::vector<Int32>	fLastValues;
		std::vector<std::string>	fLabelText;

		UInt32		IMakePow2( UInt32 value );
		void		IDrawNumber( UInt32 number, UInt32 *dataPtr, UInt32 stride, UInt32 color );
		void		IDrawDigit( char digit, UInt32 *dataPtr, UInt32 stride, UInt32 color );

	public:
		plGraphPlate( plPlate **owningHandle );
		virtual ~plGraphPlate();

		void	SetDataRange( UInt32 min, UInt32 max, UInt32 width );
		void	SetDataLabels( UInt32 min, UInt32 max );
		void	SetLabelText( char *text1, char *text2 = nil, char *text3 = nil, char *text4 = nil );
		void	SetLabelText( const std::vector<std::string> & text );
		void	ClearData( void );

		void	AddData( Int32 value, Int32 value2 = -1, Int32 value3 = -1, Int32 value4 = -1 );
		void	AddData( std::vector<Int32> values );

		void	SetColors( UInt32 bgHexColor = 0x80000000, UInt32 axesHexColor = 0xffffffff, UInt32 dataHexColor = 0xff00ff00, UInt32 graphHexColor = 0x80ff0000 );
		void	SetDataColors( UInt32 hexColor1 = 0xff00ff00, UInt32 hexColor2 = 0xff0000ff, UInt32 hexColor3 = 0xffffff00, UInt32 hexColor4 = 0xffff00ff );
		void	SetDataColors( const std::vector<UInt32> & hexColors );

		const char		*GetLabelText( int i ) { return fLabelText[ i ].c_str(); }
		const UInt32	GetDataColor( int i ) { return fDataHexColors[ i ]; }
		const UInt32	GetNumLabels() { return fLabelText.size(); }
		const UInt32	GetNumColors() { return fDataHexColors.size(); }
};

//// plPlateManager Class Definition /////////////////////////////////////////
//	This class handles all the plates--it keeps track of all the plates, 
//	creates and destroys them, and draws them when the pipeline tells it to.

class plPipeline;

class plPlateManager
{
	friend class plPlate;

	private:

		static plPlateManager	*fInstance;

	protected:

		plPlate		*fPlates;
		plPipeline	*fOwner;
		hsBool		fCreatedSucessfully;

		plPlateManager( plPipeline *pipe ) 
		{
			fInstance = this;
			fPlates = nil;
			fOwner = pipe;
			fCreatedSucessfully = true;
		}

		virtual void	IDrawToDevice( plPipeline *pipe ) = 0;

		void			IResortPlate( plPlate *plate, bool fromCurrent );

	public:

		virtual ~plPlateManager();
		
		static plPlateManager	&Instance( void ) { return *fInstance; }
		static bool InstanceValid( void ) { return fInstance != nil; }

		void		CreatePlate( plPlate **handle );
		void		CreatePlate( plPlate **handle, hsScalar width, hsScalar height );
		void		CreatePlate( plPlate **handle, hsScalar x, hsScalar y, hsScalar width, hsScalar height );

		void		CreateGraphPlate( plGraphPlate **handle );

		void		DestroyPlate( plPlate *plate );

		void		SetPlateScreenPos( plPlate *plate, UInt32 x, UInt32 y );
		void		SetPlatePixelSize( plPlate *plate, UInt32 pWidth, UInt32 pHeight );

		UInt32		GetPipeWidth( void );
		UInt32		GetPipeHeight( void );
		void		DrawToDevice( plPipeline *pipe );

		hsBool		IsValid( void ) { return fCreatedSucessfully; }
};

// Sets the hInstance that we load our resources from.  A SceneViewer hack.
void SetHInstance(void *instance);

#endif //_plPlates_h