/*
* ESF Class Menu
* @version 1-05-06
* @author Joseph 'Pcjoe' Florencio
*/

#ifndef VGUI_ESFCLASSMENU_H
#define VGUI_ESFCLASSMENU_H
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>

// Pcjoe: Rotate Input Signal
class CRotateInputSignal : public InputSignal
{
public:
	// Mouse pressed
	virtual void mousePressed(MouseCode code,Panel* panel)
	{	gViewPort->m_pESFClassMenu->setCurrentlyRotating( true );
		gViewPort->m_pESFClassMenu->setMouseXPrev(-1);
	}
	virtual void mouseReleased(MouseCode code,Panel* panel)
	{	gViewPort->m_pESFClassMenu->setCurrentlyRotating( false );
		gViewPort->m_pESFClassMenu->setMouseXPrev(-1);
	}

	virtual void cursorMoved(int x,int y,Panel* panel) {}
	virtual void cursorEntered(Panel* panel) {}
	virtual void cursorExited(Panel* panel) {}
	virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}
	virtual void mouseWheeled(int delta,Panel* panel) {}
	virtual void keyPressed(KeyCode code,Panel* panel) {}
	virtual void keyTyped(KeyCode code,Panel* panel) {}
	virtual void keyReleased(KeyCode code,Panel* panel) {}
	virtual void keyFocusTicked(Panel* panel) {}
};

// Pcjoe: Rotate Input Signal
class CRotateResetInputSignal : public InputSignal
{
public:
	// Mouse pressed
	virtual void mousePressed(MouseCode code,Panel* panel)
	{	gViewPort->m_pESFClassMenu->setCurrentlyRotating( false );
		gViewPort->m_pESFClassMenu->setMouseXPrev(-1);
		gViewPort->m_pESFClassMenu->setRotate(0);
	}

	virtual void cursorMoved(int x,int y,Panel* panel) {}
	virtual void cursorEntered(Panel* panel) {}
	virtual void cursorExited(Panel* panel) {}
	virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}
	virtual void mouseReleased(MouseCode code,Panel* panel) {}
	virtual void mouseWheeled(int delta,Panel* panel) {}
	virtual void keyPressed(KeyCode code,Panel* panel) {}
	virtual void keyTyped(KeyCode code,Panel* panel) {}
	virtual void keyReleased(KeyCode code,Panel* panel) {}
	virtual void keyFocusTicked(Panel* panel) {}
};

// Pcjoe: Stats Info (consist of label and bar
#define STAT_HEIGHT	20
class CStatInfo : public Panel
{
public:
	CStatInfo( char *pText, int x,int y,int wide,int tall, int iTextWide, float flValue, float flMax, int br, int bg, int bb, bool inverseBar=false ) : Panel(x,y,wide,tall)
	{	m_iTextWide = iTextWide;
		m_flBarValue = flValue;
		m_flBarMax = flMax;
		m_bInverseBar = inverseBar;

		// set bar colors
		m_barR = br;
		m_barG = bg;
		m_barB = bb;

		// make this panel transparent
		setBgColor( 0,0,0,255 );
		setFgColor( 0,0,0,255 );

		// Create text label
		Label *pTextLabel = new Label( pText, 0, 0, iTextWide, tall );
		pTextLabel->setContentAlignment(Label::a_east);
		pTextLabel->setFgColor( 255,255,255,0 );
		pTextLabel->setBgColor( 0,0,0,255 );
		pTextLabel->setParent(this);

		// Create label over bar
		int iBarPadding = 4;
		int iBarPaddingLeft = 10;
		int iBarStartX = m_iTextWide + iBarPadding + iBarPaddingLeft;
		int iBarWidthMax = wide-(m_iTextWide+iBarPaddingLeft+iBarPadding*2);

		// Convert with string stream
		std::stringstream s;
		s.precision(10);
		s << flValue; // Insert float
		
		// Create numerical label
		Label *pNumberLabel = new Label( s.str().c_str(), iBarStartX, 0, iBarWidthMax, tall );
		pNumberLabel->setContentAlignment( Label::a_center );
		pNumberLabel->setFgColor(255, 255, 255, 0);
		pNumberLabel->setBgColor( 0, 0, 0, 255 );
		pNumberLabel->setParent(this);

		// * Bar will be drawn dynamically
	}


	virtual void paintBackground( void )
	{	int wide,tall;
		getSize(wide,tall);
		int iBarPadding = 4;
		int iBarPaddingLeft = 10;
		int iBarStartX = m_iTextWide + iBarPadding + iBarPaddingLeft;
		int iBarStartY = iBarPadding;
		int iBarWidthMax = wide-(m_iTextWide+iBarPaddingLeft+iBarPadding*2);
		int iBarTall = tall-(iBarPadding*2);
		// calc percent
		float flPercent = m_flBarValue/m_flBarMax;
		if(flPercent > 1)
		{	flPercent = 1;
		}
		else if(flPercent < 0)
		{	flPercent = 0;
		}
		// Flip if needed
		if(m_bInverseBar)
		{	flPercent = 1-flPercent;
		}

		int iBarRealWidth = iBarWidthMax * flPercent;

		getPaintSize(wide,tall);

		drawSetColor(m_barR,m_barG,m_barB,0);
		drawFilledRect( iBarStartX,iBarStartY,iBarStartX+iBarRealWidth,iBarStartY+iBarTall );
		Panel::paintBackground();
	}

	void setMaxValue( float flValue ) { m_flBarMax = flValue; }
	float getMaxValue( void ) { return m_flBarMax; }

private:
	int m_iTextWide;
	float m_flBarValue;
	float m_flBarMax;
	bool m_bInverseBar;
	int m_barR, m_barG, m_barB;
};


// Pcjoe: Bullet button
#define BULLET_HEIGHT 20
class CBulletButton : public Panel
{
public:
	CBulletButton( char *pText, int x,int y,int wide,int tall, int iAlign=Label::a_west ) : Panel(x,y,wide,tall)
	{	// Default align
		setAlign(iAlign);
		// not armed by default
		m_bArmed = false;
		// Schemes
		CSchemeManager *pSchemes = gViewPort->GetSchemeManager();
		int r, g, b, a;
		SchemeHandle_t hBlueScheme = pSchemes->getSchemeHandle( "ESF Team Select Blue" );
		pSchemes->getFgColor( hBlueScheme, r, g, b, a );

		// clear fg and bg
		setFgColor(0,0,0,255);
		setBgColor(0,0,0,255);

		// Create two images
		int iMidY = tall/2-8-1;
		m_pBulletOnImg = new CImageLabel( "bulleton", 0, iMidY, 16, 16 );
		m_pBulletOnImg->setParent(this);
		m_pBulletOnImg->setVisible(false);
		m_pBulletOffImg = new CImageLabel( "bulletoff", 0, iMidY, 16, 16 );
		m_pBulletOffImg->setParent(this);
		m_pBulletOffImg->setVisible(true);
		// Create invis button
		m_pBullet = new CommandButtonNoDraw("",0,iMidY,16,16,false);
		m_pBullet->setParent(this);

		// Create text
		int iCurWide = wide-(16+4);
		m_pText = new ColorButton(pText, 16+4,0,iCurWide,tall, true, true);
		int wideT, tallT;
		m_pText->getTextSize(wideT,tallT);
		if(iCurWide > wideT)
		{	m_pText->setSize(wideT, tall);
			// Fix size
			setSize(16+4+wideT,tall);
		}
		m_pText->setUnArmedBorderColor(0,0,0,255);
		m_pText->setUnArmedColor(r,g,b,0);
		m_pText->setArmedBorderColor(0,0,0,255);
		m_pText->setArmedColor(255,255,255,0);
		m_pText->setButtonBorderEnabled(false);
		m_pText->setParent(this);

		// If aligned to east, flip text and button around
		if(getAlign() == Label::a_east)
		{	this->getSize(wide,tall);
			m_pText->setPos(0,0);
			m_pBullet->setPos(wide-16,iMidY);
			m_pBulletOnImg->setPos(wide-16-4,iMidY);
			m_pBulletOffImg->setPos(wide-16-4,iMidY);
		}
	}

	void setArmed()
	{	m_bArmed = true;
		m_pBulletOnImg->setVisible(true);
		m_pBulletOffImg->setVisible(false);
		m_pText->setArmed(m_bArmed);
	}

	void setUnArmed()
	{	m_bArmed = false;
		m_pBulletOnImg->setVisible(false);
		m_pBulletOffImg->setVisible(true);
		m_pText->setArmed(m_bArmed);
	}

	bool isArmed( void )
	{	return m_bArmed;
	}

	void flipArmed()
	{	if(isArmed())
		{	setUnArmed();
		}
		else
		{	setArmed();
		}
	}

	void setInputSignal(InputSignal *s)
	{	m_pBullet->addInputSignal(s);
		m_pText->addInputSignal(s);
	}
	
	// Accessor
	void setCallback( std::string strCallback ) { m_strCallback = strCallback; }
	std::string getCallback( void ) { return m_strCallback; }

	// Set Align
	void setAlign( int iAlign ) { m_iAlign = iAlign; }
	int getAlign( void ) { return m_iAlign; }
private:
	CImageLabel *m_pBulletOnImg;
	CImageLabel *m_pBulletOffImg;
	CommandButtonNoDraw *m_pBullet;
	ColorButton *m_pText;
	std::string m_strCallback;
	bool	m_bArmed;
	int		m_iAlign;
};

// Pcjoe: Bullet Input Signal
class CBulletedList;
class CBulletInputSignal : public InputSignal
{
public:
	// Constructors
	CBulletInputSignal(CBulletButton *pBtn, CBulletedList *pList)
	{	m_pButton = pBtn;
		m_pBulletedList = pList;
	}

	// Mouse pressed
	virtual void mousePressed(MouseCode code,Panel* panel);

	virtual void cursorMoved(int x,int y,Panel* panel) {}
	virtual void cursorEntered(Panel* panel) {}
	virtual void cursorExited(Panel* panel) {}
	virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}
	virtual void mouseReleased(MouseCode code,Panel* panel) {}
	virtual void mouseWheeled(int delta,Panel* panel) {}
	virtual void keyPressed(KeyCode code,Panel* panel) {}
	virtual void keyTyped(KeyCode code,Panel* panel) {}
	virtual void keyReleased(KeyCode code,Panel* panel) {}
	virtual void keyFocusTicked(Panel* panel) {}

private:
	CBulletButton *m_pButton;
	CBulletedList *m_pBulletedList;
};

// Pcjoe: Bulleted List
class CBulletedList
{
public:
	// Constructor
	CBulletedList(CESFClassMenuPanel *pMasterPanel, Panel *pParent, int iX, int iY, int width, int iAlign=Label::a_west)
	{	setParent(pParent);
		setMasterPanel(pMasterPanel);
		setAlign(iAlign);
		setUnselect(true);
		m_iStartX = iX;
		m_iStartY = iY;
		m_iWidth = width;
	}

	// Reset (armed status)
	void Reset( CBulletButton *pSkip=NULL )
	{	std::vector<CBulletButton*>::iterator iterBullet;
		ForEachIn(iterBullet, m_BulletList)
		{	if((*iterBullet) != pSkip)
			{	(*iterBullet)->setUnArmed();
			}
		}
	}

	// set visible
	void setVisible( bool state )
	{	std::vector<CBulletButton*>::iterator iterBullet;
		ForEachIn(iterBullet, m_BulletList)
		{	(*iterBullet)->setVisible(state);
		}
	}

	// Add Bullet
	void addBullet( std::string strName, std::string strCallback )
	{	CBulletButton *pNewBullet = new CBulletButton((char*)strName.c_str(), m_iStartX, m_iStartY+BULLET_HEIGHT*signed(m_BulletList.size()), m_iWidth, BULLET_HEIGHT, getAlign());
		pNewBullet->setParent(getParent());
		pNewBullet->setVisible(true);
		pNewBullet->setInputSignal(new CBulletInputSignal(pNewBullet, this));
		pNewBullet->setCallback(strCallback);
		int x,y;
		int wide,tall;
		// Realign bullet if not west
		switch(getAlign())
		{ 
		case Label::a_center:
			pNewBullet->getPos(x,y);
			pNewBullet->getSize(wide,tall);
			pNewBullet->setPos(m_iStartX+m_iWidth/2-wide/2, y);
			break;
		case Label::a_east:
			pNewBullet->getPos(x,y);
			pNewBullet->getSize(wide,tall);
			pNewBullet->setPos(m_iStartX+m_iWidth-wide, y);
			break;
		}
		m_BulletList.push_back(pNewBullet);
	}

	// Get Selected Callback
	std::string getSelectedCallback( void )
	{	std::vector<CBulletButton*>::iterator iterBullet;
		ForEachIn(iterBullet, m_BulletList)
		{	if((*iterBullet)->isArmed())
			{	return (*iterBullet)->getCallback();
			}
		}
		return "";
	}

	// Get num bullets
	int getNumBullets( void )
	{	return m_BulletList.size();
	}

	// Get height
	int getHeight( void )
	{	return m_iStartY+BULLET_HEIGHT*signed(m_BulletList.size());
	}

	// Get bullet at index
	CBulletButton *getBulletAtIndex( int n )
	{	if((n >= 0) && (n < signed(m_BulletList.size())))
		{	return  m_BulletList[n];
		}
		return NULL;
	}

	// Select first in list (arm first)
	void armFirst( void )
	{	Reset();
		if(signed(m_BulletList.size()) > 0)
		{	m_BulletList[0]->setArmed();
		}
	}

	void printCallback()
	{	std::string print = "Current Callback: ";
		print.append(getSelectedCallback());
		print.append("\n");
		ConsolePrint(print.c_str());
	}

	// Accessors
	void setParent(Panel *pParent) { m_pParent = pParent; }
	Panel *getParent( void ) { return m_pParent; }

	// Master Panel
	void setMasterPanel( CESFClassMenuPanel *pMaster ) { m_pMasterPanel = pMaster; }
	CESFClassMenuPanel *getMasterPanel( void ) { return m_pMasterPanel; }

	// Set Align
	void setAlign( int iAlign ) { m_iAlign = iAlign; }
	int getAlign( void ) { return m_iAlign; }

	// Unselect
	void setUnselect( bool unsel ) { m_bCanUnselect = unsel; }
	bool canUnselect( void ) { return m_bCanUnselect; }


private:
	std::vector<CBulletButton*> m_BulletList;
	CESFClassMenuPanel *m_pMasterPanel;
	Panel *m_pParent;
	bool	m_bCanUnselect;
	int m_iStartX;
	int m_iStartY;
	int m_iWidth;
	int m_iAlign;
};

// Custom drawn scroll bars
class CESFClassScrollButton : public CommandButton
{
private:
	BitmapTGA	*m_pTGA;

public:
	CESFClassScrollButton(std::string strArrow, const char* text,int x,int y,int wide,int tall);

	virtual void paint( void );
	virtual void paintBackground( void );
};

// Custom drawn slider bar
class CESFClassSlider : public Slider
{
public:
	CESFClassSlider(int x,int y,int wide,int tall,bool vertical) : Slider(x,y,wide,tall,vertical)
	{
	};

	virtual void paintBackground( void );
};

// Custom drawn scrollpanel
class CESFClassScrollPanel : public ScrollPanel
{
public:
	CESFClassScrollPanel(int x,int y,int wide,int tall);
	virtual void       validate();
};

// Color scroll panel
// Custom drawn scroll bars
class CESFColorScrollButton : public CommandButton
{
private:
	BitmapTGA	*m_pTGA;

public:
	CESFColorScrollButton(std::string strArrow, const char* text,int x,int y,int wide,int tall, Color fg);

	virtual void paint( void );
	virtual void paintBackground( void );
};

// Custom drawn slider bar
class CESFColorSlider : public Slider
{
public:
	CESFColorSlider(int x,int y,int wide,int tall,bool vertical, Color fg, Color bg) : Slider(x,y,wide,tall,vertical)
	{	setFgColor(fg);
		setBgColor(bg);
	};

	virtual void paintBackground( void );
};

// Custom drawn scrollpanel
class CESFColorScrollPanel : public ScrollPanel
{
public:
	CESFColorScrollPanel(int x,int y,int wide,int tall, Color fg, Color bg);

	virtual void setSize(int wide,int tall) { ScrollPanel::setSize(wide,tall); }
};

#endif