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

Additional permissions under GNU GPL version 3 section 7

If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.

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; }
		const plMipmap	*GetMipmap( void ) { return fMipmap; }

		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 );
		void			ReloadFromResource( const char *resName );
};

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