/*
===========================================================================
Copyright (C) 2015 the OpenMoHAA team

This file is part of OpenMoHAA source code.

OpenMoHAA source code 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.

OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/

#pragma once

#include "usignal.h"
#include "../qcommon/q_shared.h"
#include "../qcommon/str.h"
#include "ui_public.h"
#include "uirect2d.h"
#include "ucolor.h"
#include "uifont.h"

class UIFont;

class UIReggedMaterial {
	uihandle_t hMat;
	str name;
	bool isSet;
	bool isGot;

public:
	UIReggedMaterial();

	uihandle_t	GetMaterial( void );
	void		ReregisterMaterial( void );
	void		CleanupMaterial( void );
	void		SetMaterial( const str& name );
	void		RefreshMaterial( void );
	str			GetName( void );
};

// widget flags
#define WF_STRETCH_VERTICAL		(1<<0)
#define WF_STRETCH_HORIZONTAL	(1<<1)
#define WF_DIRECTED				(1<<2)
#define WF_TILESHADER			(1<<3)
#define WF_ALWAYS_BOTTOM		(1<<4)
#define WF_ALWAYS_TOP			(1<<5)
#define WF_NOPARENTADJUST		(1<<6)
#define WF_DONTLOCALIZE			(1<<7)

// widget alignment flags
#define WA_LEFT					(1<<0)
#define WA_RIGHT				(1<<1)
#define WA_TOP					(1<<3)
#define WA_BOTTOM				(1<<4)
#define WA_CENTERX				(1<<5)
#define WA_CENTERY				(1<<6)
#define WA_FULL					( WA_LEFT | WA_RIGHT | WA_TOP | WA_BOTTOM | WA_CENTERX | WA_CENTERY )

typedef class UIReggedMaterial UIReggedMaterial;
typedef enum {
	border_none,
	border_3D,
	border_indent,
	border_outline
} borderstyle_t;

typedef enum {
	D_NONE,
	D_FROM_LEFT,
	D_FROM_RIGHT,
	D_FROM_BOTTOM,
	D_FROM_TOP 
} direction_t;

typedef enum {
	MOTION_IN,
	MOTION_OUT
} motion_t;

typedef enum {
	SEQUENCE_NONE,
	SEQUENCE_STARTING,
	SEQUENCE_FADEIN,
	SEQUENCE_HOLD,
	SEQUENCE_FADEOUT
} fadesequence_t;

class UIWidget : public USignal {
	friend class Menu;
	friend class UILayout;
	friend class UIWindowManager;

protected:
	UIRect2D m_frame;
	vec2_t m_vVirtualScale;
	UIPoint2D m_startingpos;
	UIPoint2D m_origin;
	UIRect2D m_screenframe;
	UIPoint2D m_screenorigin;
	UIRect2D m_clippedframe;
	UIPoint2D m_clippedorigin;
	UColor m_background_color;
	UColor m_foreground_color;
	UBorderColor m_border_color;
	borderstyle_t m_borderStyle;
	bool m_visible;
	bool m_enabled;
	UIFont *m_font;
	class UIWidget *m_parent;
	Container<UIWidget *> m_children;
	str m_name;
	bool m_canactivate;
	str m_cvarname;
	str m_cvarvalue;
	str m_command;
	Container<str *> m_showcommands;
	Container<str *> m_hidecommands;
	str m_title;
	float m_indent;
	float m_bottomindent;
	UIReggedMaterial *m_material;
	UIReggedMaterial *m_hovermaterial;
	UIReggedMaterial *m_pressedmaterial;
	bool m_hovermaterial_active;
	bool m_pressedmaterial_active;
	direction_t m_direction;
	direction_t m_direction_orig;
	motion_t m_motiontype;
	float m_starttime;
	float m_fadetime;
	float m_alpha;
	float m_local_alpha;
	float m_motiontime;
    float m_fadeSequenceDelay;
    float m_fadeSequenceFadeIn;
    float m_fadeSequenceHold;
    float m_fadeSequenceFadeOut;
    float m_fadeSequenceRemainingTime;
    float m_fadeSequenceLastTime;
    int m_fadeSequenceState;
	str m_stopsound;
	str m_clicksound;
	int m_align;
	int m_flags;
	bool m_dying;
	int m_ordernum;
	int m_configstring_index;
	fonthorzjustify_t m_iFontAlignmentHorizontal;
	fontvertjustify_t m_iFontAlignmentVertical;
	qboolean m_bVirtual;
	str m_enabledCvar;
	//
	// New since 2.0
	//
	cvar_t* m_scaleCvar;

public:
	CLASS_PROTOTYPE( UIWidget );

	void( *m_commandhandler ) ( const char *, void * );

protected:
	bool			addChild( UIWidget *widget );
	bool			removeChild( UIWidget *widget );
	void			PropogateCoordinateSystem( void );
	void			set2D( void );
	virtual void	Draw( void );
	virtual void	FrameInitialized( void );
	void			DrawTitle( float x, float y );
	void			Motion( void );
	virtual void	AlignPosition( void );
	void			Hide( Event *ev );
	void			Activate( Event *ev );
	void			BringToFront( void );
	static void		SplitWidgets( Container<UIWidget*>& src, Container<UIWidget*>& bottom, Container<UIWidget*>& normal, Container<UIWidget*>& top );
	static void		CombineWidgets( Container<UIWidget*>& dst, Container<UIWidget*>& bottom, Container<UIWidget*>& normal, Container<UIWidget*>& top );
	static void		ArrangeWidgetList( Container<UIWidget*>& list );

public:

	UIWidget();
	virtual ~UIWidget();

	virtual void		Shutdown( void );
	virtual void		InitFrame( UIWidget *parentview, float x, float y, float width, float height, int border = -1, const char *fontname = "verdana-12" );
	void				InitFrame( UIWidget *parentview, const UIRect2D& r, int border, const char *fontname = "verdana-12" );
	void				LayoutSize( Event *ev );
	void				LayoutRect( Event *ev );
	void				LayoutName( Event *ev );
	void				LayoutTitle( Event *ev );
	void				LayoutFont( Event *ev );
	void				LayoutBgColor( Event *ev );
	void				LayoutFgColor( Event *ev );
	void				LayoutBorderStyle( Event *ev );
	void				LayoutBorderColor( Event *ev );
	void				LayoutShader( Event *ev );
	void				LayoutTileShader( Event *ev );
	void				LayoutHoverShader( Event *ev );
	void				LayoutPressedShader( Event *ev );
	void				LayoutFadeIn( Event *ev );
	void				LayoutStopSound( Event *ev );
	void				LayoutClickSound( Event *ev );
	void				LayoutStretch( Event *ev );
	void				LayoutVirtualRes( Event *ev );
	void				LayoutInitData( Event *ev );
	void				LayoutDirection( Event *ev );
	void				LayoutAlign( Event *ev );
	void				LayoutStuffCommand( Event *ev );
	void				LayoutLinkCvar( Event *ev );
	void				LayoutNoParentClipping( Event *ev );
	void				LayoutNoParentAdjustment( Event *ev );
	void				LayoutOrderNumber( Event *ev );
	void				TextAlignment( Event *ev );
	void				LayoutAliasCache( Event *ev );
	void				SetEnabledCvar( Event *ev );
	void				SetScaleCvar( Event *ev );

	// Added in 2.0
	//====
	void				SetDontLocalize( Event *ev );
	void				EventFadeSequence( Event *ev );
	//====

	void				SetVirtualScale(vec2_t out);
	void				SetDontLocalize();
	void				setParent( UIWidget *parent );
	class UIWidget		*getParent( void );
	class UIWidget		*getFirstChild( void );
	class UIWidget		*getNextSibling( void );
	class UIWidget		*getNextChild( UIWidget *child );
	class UIWidget		*getPrevChild( UIWidget *child );
	class UIWidget		*getPrevSibling( void );
	class UIWidget		*getPrevSibling( UIWidget *curr );
	class UIWidget		*getLastSibling( void );
	class UIWidget		*findSibling( str name );

	void				Enable( void );
	void				Disable( void );
	bool				isEnabled( void );
	bool				IsDying( void );
	class UIWidget		*FindResponder( const UIPoint2D& pos );
	void				setFont( const char *name );
	void				setFontHorizontalAlignment( fonthorzjustify_t alignment );
	void				setFontVerticalAlignment( fontvertjustify_t alignment );
	void				setShow( bool visible );
	bool				getShow( void );
	class UColor		getBackgroundColor( void );
	virtual void		setBackgroundColor( const UColor& color, bool setbordercolor );
	class UBorderColor	getBorderColor( void );
	void				setBorderColor( const UBorderColor& color );
	class UColor		getForegroundColor( void );
	virtual void		setForegroundColor( const UColor& color );
	borderstyle_t		getBorderStyle( void );
	void				setBorderStyle( borderstyle_t style );
	class UISize2D		getSize( void );
	void				setSize( const UISize2D& newsize );
	class UIRect2D		getFrame( void );
	void				setFrame( const UIRect2D& newframe );
	class UIPoint2D		getOrigin( void );
	void				setOrigin( const UIPoint2D& neworigin );
	void				setName( str name );
	const char			*getName( void );
	void				setTitle( str title );
	const char			*getTitle( void );
	void				setDirection( direction_t dir );
	direction_t			getDirection( void );
	void				setMotionType( motion_t type );
	motion_t			getMotionType( void );
	void				setMotionTime( float time );
	float				getMotionTime( void );
	void				setAlign( int align );
	int					getAlign( void );
	void				setMaterial( UIReggedMaterial *mat );
	void				setHoverMaterial( UIReggedMaterial *mat );
	void				setPressedMaterial( UIReggedMaterial *mat );
	class UIPoint2D		getLocalPoint( const UIPoint2D& pos );
	class UIPoint2D		getGlobalPoint( const UIPoint2D& pos );
	virtual void		setBackgroundAlpha( float f );
	float				getBackgroundAlpha( void );
	void				Display( const UIRect2D& drawframe, float parent_alpha );
	virtual qboolean	KeyEvent( int key, unsigned int time );
	virtual void		CharEvent( int ch );
	virtual void		UpdateData( void );
	virtual void		UpdateUIElement( void );
	float				getTitleWidth( void );
	float				getTitleHeight( void );
	bool				CanActivate( void );
	void				AllowActivate( bool canactivate );
	bool				IsActive( void );
	bool				IsVisible( void );
	virtual void		LinkCvar( str cvarname );
	void				LinkCommand( str cmd );
	void				ExecuteShowCommands( void );
	void				ExecuteHideCommands( void );
	void				InitializeCommandHandler( void( *fcn) ( const char *, void * ) );
	class UIWidget		*FindWidget( str name );
	void				ResetMotion( motion_t type );
	virtual void		Realign( void );
	void				BringToFrontPropogated( void );
	class UIWidget		*IsThisOrChildActive( void );
	class UIPoint2D		MouseEventToClientPoint( Event *ev );
	class UIRect2D		getClientFrame( void );
	void				setAlwaysOnBottom( bool b );
	void				setAlwaysOnTop( bool b );
	bool				getAlwaysOnBottom( void );
	bool				getAlwaysOnTop( void );
	bool				SendSignal( Event& event );
	void				ShowCommand( Event *ev );
	void				HideCommand( Event *ev );
	void				AddFlag( int flag );
	void				SetHovermaterialActive( bool a );
	void				SetPressedmaterialActive( bool a );
	int					getOrderNum( void );
	class str			getCommand( void );
	void				ActivateOrder( void );
	void				EnableEvent( Event *ev );
	void				DisableEvent( Event *ev );
	void				setConfigstringIndex( int cs );
	int					getConfigstringIndex( void );
	bool				PassEventToWidget( str name, Event *ev );
	// Added in OPM
	bool				isVirtual() const;
	const vec2_t&		getVirtualScale() const;
	const vec2_t&		getHighResScale() const;
};

class UIWidgetContainer : public UIWidget {
	UColor m_bgfill;
	qboolean m_fullscreen;
	int m_vidmode;
	int m_currentwidnum;
	int m_maxordernum;

public:
	class UILayout *m_layout;

	CLASS_PROTOTYPE( UIWidgetContainer );

private:
	void		AlignPosition( void ) override;
	void		Draw( void ) override;

public:
	UIWidgetContainer();

	void		Realign( void ) override;
	void		SetBGFill( Event *ev );
	void		SetFullscreen( Event *ev );
	void		SetVidMode( Event *ev );
	int			getVidMode( void );
	qboolean	isFullscreen( void );
	UIWidget	*GetNextWidgetInOrder( void );
	UIWidget	*GetPrevWidgetInOrder( void );
	void		SetActiveWidgetOrderNum( UIWidget *wid );
	void		SetActiveWidgetOrderNum( int num );
	void		SetLastActiveWidgetOrderNum( void );
};

extern Event W_Destroyed;
extern Event W_SizeChanged;
extern Event W_FrameChanged;
extern Event W_OriginChanged;
extern Event W_Activated;
extern Event EV_Widget_Activate;
extern Event W_Deactivated;
extern Event EV_Widget_Hide;
extern Event EV_Widget_Enable;
extern Event EV_Widget_Disable;
extern Event W_RealignWidget;
extern Event W_Draw;
extern Event EV_Layout_Size;
extern Event EV_Layout_Rect;
extern Event EV_Layout_Name;
extern Event EV_Layout_Title;
extern Event EV_Layout_Font;
extern Event EV_Layout_BGColor;
extern Event EV_Layout_FGColor;
extern Event EV_Layout_Borderstyle;
extern Event EV_Layout_BorderColor;
extern Event EV_Layout_Shader;
extern Event EV_Layout_TileShader;
extern Event EV_Layout_HoverShader;
extern Event EV_Layout_PressedShader;
extern Event EV_Layout_FadeIn;
extern Event EV_Layout_StopSound;
extern Event EV_Layout_ClickSound;
extern Event EV_Layout_Stretch;
extern Event EV_Layout_VirtualRes;
extern Event EV_Layout_InitData;
extern Event EV_Layout_Direction;
extern Event EV_Layout_Align;
extern Event EV_Layout_StuffCommand;
extern Event EV_Layout_LinkCvar;
extern Event EV_Layout_NoParentClipping;
extern Event EV_Layout_NoParentAdjustment;
extern Event EV_Widget_HideCommand;
extern Event EV_Widget_ShowCommand;
extern Event EV_Widget_OrderNumber;
extern Event EV_Widget_TextAlignment;
extern Event EV_Widget_EnabledCvar;
extern Event EV_Layout_AliasCache;
extern Event EV_Layout_BGFill;
extern Event EV_Layout_Fullscreen;
extern Event EV_Layout_VidMode;

void SetColor( const UColor& color, float alpha );
void DrawBox( const UIRect2D& rect, const UColor& color, float alpha );
void Draw3DBox( const UIRect2D& rect, bool indent, const UBorderColor& color, float alpha );
void DrawBox( float x, float y, float width, float height, const UColor &color, float alpha );
void Draw3DBox( float x, float y, float width, float height, bool indent, const UBorderColor& color, float alpha );
void DrawMac3DBox( const UIRect2D& rect, bool indent, const UBorderColor& color, int inset, float alpha );
void DrawBoxWithSolidBorder( const UIRect2D& rect, const UColor& inside, const UColor& outside, int size, int flags, float alpha );
