//
// Tools_Cutscene_Dialog.cpp
//
// Created by Richard Rice - 12/04/2002
// 
// Copyright (C) 2001 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"
#include "Debugging/Asura_Assert.h"
#include "Rendering/Asura_Viewport.h"
#include "Rendering/Asura_Text_Output.h"
#include "Interface/Asura_Overlay.h"
#include "Interface/Asura_Overlay_System.h"
#include "Core/Asura_UserInput.h"

#include "Cutscene/Tools_Mode_Cutscene.h"
#include "Cutscene/Tools_Cutscene_Dialog.h"
#include "Cutscene/Tools_Cutscene_Timeline.h"



/////////////////////////////////////////////////////////////////////////////////////////////////
/*-------------------------------**
** Tools_CutsceneTimeline_Dialog **
**-------------------------------*/
Tools_CutsceneTimeline_Dialog::Tools_CutsceneTimeline_Dialog( const Asura_Vector_2& xOffset )
:Asura_Dialog(0,xOffset)
,m_fPreResizeHeight(0.0f)
{
	float fScreenWidth = Asura_Viewport::GetWidth()/10.0f;
	float fScrollbarWidth = Asura_Scrollbar_Gadget::GetDefaultThickness(false);
	float fTimelineWidth = fScreenWidth - fScrollbarWidth;

	Asura_Vector_2 xGadgetOffset = xOffset;
	m_pxTimelineGadget = new Tools_CutsceneTimeline_Gadget( xGadgetOffset, fTimelineWidth );
	AddGadget(m_pxTimelineGadget);

	
	xGadgetOffset.x += fTimelineWidth;
	m_pxVerticalScroll = new Asura_Scrollbar_Gadget(xGadgetOffset, &Tools_Cutscene_Timeline::s_fTimelineBarActorYOffset,0.0f,100.0f,false,2.0f,NULL,NULL);
	AddGadget(m_pxVerticalScroll);

	m_xMaxCoord.x = m_xOffset.x + fScreenWidth;
	m_xMaxCoord.y = m_xOffset.y + m_pxTimelineGadget->m_fHeight;
}

void Tools_CutsceneTimeline_Dialog::UpdateFromCutsceneMode(float fBottomY)
{
	//do the main update of things that aren't safe to be done during the overlay update
	m_pxTimelineGadget->UpdateFromCutsceneMode((m_pxOverlay->m_xPosition.y + m_xMaxCoord.y) * 14.0f);

	//Adjust the overlay position and dialog height to match the current timeline height
	float fPixelHeight = Tools_Cutscene_Timeline::GetTimelineBarHeight();
	float fPrintHeight = fPixelHeight/ASURA_TEXT_OUTPUT_FONT_HEIGHT;

	float fOverlayPosY = fBottomY - fPrintHeight - m_xOffset.y;
	if(fOverlayPosY < 3.0f)
	{
		//The overlay isgetting too close to the top of the screen , so force the timeline height
		//to be reduced.
		//(Otherwise it becomes impossible to drag it down again).
		fPrintHeight -= 3.5f - fOverlayPosY;
		fPixelHeight = (float)Asura_Maths::FloatToInt_Near(fPrintHeight * ASURA_TEXT_OUTPUT_FONT_HEIGHT);
		fPrintHeight = fPixelHeight/ASURA_TEXT_OUTPUT_FONT_HEIGHT;
		fOverlayPosY = fBottomY - fPrintHeight - m_xOffset.y;

		Tools_Cutscene_Timeline::SetTimelineBarHeight(fPixelHeight);
	}

	m_pxOverlay->m_xPosition.y = fOverlayPosY;
	m_pxOverlay->m_xOrigin.y = fOverlayPosY;

	if(m_pxTimelineGadget->m_fHeight != fPrintHeight)
	{
		m_pxTimelineGadget->m_fHeight = fPrintHeight;
		m_pxVerticalScroll->SetBarLength(fPrintHeight);
		m_xMaxCoord.y = m_xOffset.y+fPrintHeight;

		//hide the scrollbar if it gets too small
		m_pxVerticalScroll->SetHidden(fPrintHeight<=m_pxVerticalScroll->GetSliderLength());

		m_pxOverlay->FlagForResize();
	}

	//update the range covered by the scrollbar
	//The +42 accounts for the extra space required by the numbers at the top , and the 2 lines of status text at the bottom
	m_pxVerticalScroll->SetMax(Asura_Maths::Max(Tools_Cutscene_Timeline::GetMaxTimelineDataY()+42.0f-fPixelHeight,1.0f));
}

void Tools_CutsceneTimeline_Dialog::StartResize(u_int uResizeFlags)
{
	m_fPreResizeHeight = m_xMaxCoord.y - m_xOffset.y;
}

void Tools_CutsceneTimeline_Dialog::UpdateResize(u_int uResizeFlags, const Asura_Vector_2& xDelta)
{
	float fNewHeight;
	if(uResizeFlags & ASURA_OVERLAY_RESIZE_INITIAL)
	{
		return;
	}
	else
	{
		fNewHeight = m_fPreResizeHeight + xDelta.y;
		if(fNewHeight < 0.0f) fNewHeight = 0.0f;
	}
	//make sure the height is an integer number of pixels
	float fPixelHeight = fNewHeight * ASURA_TEXT_OUTPUT_FONT_HEIGHT;
	fPixelHeight = (float)Asura_Maths::FloatToInt_Near(fPixelHeight);
	fNewHeight = fPixelHeight / ASURA_TEXT_OUTPUT_FONT_HEIGHT;

	//update the height in the dialog and gagets
	m_xMaxCoord.y = m_xOffset.y + fNewHeight;
	Tools_CutsceneTimeline_Gadget* pxTimelineGadget = (Tools_CutsceneTimeline_Gadget*) m_pxGadgetList;
	pxTimelineGadget->m_fHeight = fNewHeight;

	//update the height in Tools_Cutscene_Timeline
	Tools_Cutscene_Timeline::SetTimelineBarHeight(fPixelHeight);


}



/////////////////////////////////////////////////////////////////////////////////////////////////
/*-------------------------------**
** Tools_CutsceneTimeline_Gadget **
**-------------------------------*/


Tools_CutsceneTimeline_Gadget::Tools_CutsceneTimeline_Gadget( const Asura_Vector_2& xOffset, float fWidth )
{
	m_xOffset = xOffset;
	m_fWidth = fWidth;
	m_fHeight = 2.0f;

}


void Tools_CutsceneTimeline_Gadget::Render( const Asura_Vector_2& xOrigin )
{
	Tools_Cutscene_Timeline::RenderForOverlay((m_xOffset.y + xOrigin.y + m_fHeight) * 14.0f,m_fWidth*ASURA_TEXT_OUTPUT_FONT_WIDTH);
    
    // We won't necessarily call Handle() each frame so we need to reset this
    // after rendering in case the user has moved the mouse off the overlay
    // before the next update.
    m_bClickedThisFrame = false;
    m_bIsMouseOver      = false;
}

void Tools_CutsceneTimeline_Gadget::Update( const Asura_Vector_2& xOrigin )
{
	if( m_bIsMouseOver )
	{
//		if(Tools_Cutscene_Timeline::ActorObject)
		{
			//see which gadget currently has focus
			//if a different gadget has focus , don't try to take it
			Asura_Gadget* focusGadget = Asura_Overlay_System::GetFocusGadget();
			if(focusGadget==0 || focusGadget==this)
			{ 
				//take keyboard focus
				if(!(m_iFocusFlags & OverlayFocusType_Keyboard))
				{
					Asura_Overlay_System::TakeFocus(this,OverlayFocusType_Keyboard);
				}

				//if the mouse is being pressed on this gadget , get mouse focus
				if(!(m_iFocusFlags & OverlayFocusType_Mouse))
				{
                    if( m_bIsClickable )
                    {
					    if( Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_MOUSEBUTTON1) || 
						    Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_MOUSEBUTTON2) ||
						    Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_MOUSEBUTTON3))
					    {
						    Asura_Overlay_System::TakeFocus(this,OverlayFocusType_Mouse);
                            m_bClickedThisFrame = true;
					    }
                    }
			 	}
			}

		}
	}
	else if(m_iFocusFlags & OverlayFocusType_Keyboard)
	{
		//mouse is no longer over the gadget , so lose keyboard focus
		Asura_Overlay_System::ReleaseFocus(OverlayFocusType_Keyboard);
	}
}

void Tools_CutsceneTimeline_Gadget::FocusLost(int focusType)
{
	Asura_Gadget::FocusLost(focusType);
	if(!(m_iFocusFlags & OverlayFocusType_Mouse))
	{
		Tools_Cutscene_Timeline::FocusLost();
	}
}


void Tools_CutsceneTimeline_Gadget::UpdateFromCutsceneMode(float fBottomY)
{

	//The main update of the timeline bar can't be done during the overlay update , since there is a chance that it will
	//need to create and destroy overlays.
	//So it is done here , from a funciton called within the cutscene mode update.
	//RAR 27/07/2007
	if( m_bIsMouseOver || m_iFocusFlags )
	{
		Tools_Cutscene_Timeline::UpdateForOverlay(fBottomY,m_fWidth*ASURA_TEXT_OUTPUT_FONT_WIDTH,m_iFocusFlags);
	}

	//lose mouse focus when the mouse is released
	if(!Asura_UserInput::KeyPressed(ASURA_KEYID_MOUSEBUTTON1) &&
	   !Asura_UserInput::KeyPressed(ASURA_KEYID_MOUSEBUTTON2) &&
	   !Asura_UserInput::KeyPressed(ASURA_KEYID_MOUSEBUTTON3))
	{
		if(m_iFocusFlags & OverlayFocusType_Mouse)
		{
			Asura_Overlay_System::ReleaseFocus(OverlayFocusType_Mouse);
		}
	}

}


/////////////////////////////////////////////////////////////////////////////////////////////////
/*---------------------------**
** Tools_CutsceneTime_Dialog **
**---------------------------*/

Tools_CutsceneTime_Dialog::Tools_CutsceneTime_Dialog(const char* pszName,const Asura_Vector_2& xOffset,float* pfTime,float fMin,float fMax,float fDelta,bool* pbChangedFlag)
:Asura_Dialog(pszName,xOffset)
{
	m_pbChangedFlag = pbChangedFlag;
	m_pfTime = pfTime;
	m_fTimeBackup = *m_pfTime;
	m_fMin = fMin;
	m_fMax = fMax;
	m_fDelta = fDelta;
	m_xGadgetOffset = xOffset;

	m_iTimerMode = Tools_Mode_Cutscene::GetTimerMode();

	CreateGadgets();
}

void Tools_CutsceneTime_Dialog::CreateGadgets()
{

	//get values to use for the current timer mode
	m_fDisplayedTime = Tools_Mode_Cutscene::ConvertSecondsToDisplayedTime(*m_pfTime,m_iTimerMode);
	float fMin = Tools_Mode_Cutscene::ConvertSecondsToDisplayedTime(m_fMin,m_iTimerMode);
	float fMax = Tools_Mode_Cutscene::ConvertSecondsToDisplayedTime(m_fMax,m_iTimerMode);
	float fDelta = (m_iTimerMode == CUTSCENETIMER_SECONDS) ? m_fDelta : 1.0f;
	m_bGadgetChanged = false;

	Asura_Gadget* pxGadget;

	//delete old gadgets
	if(m_pxGadgetList)
	{
		//make sure the number gadget doesn't have focus first
		pxGadget = m_pxGadgetList;
		while(pxGadget)
		{
			if(pxGadget == Asura_Overlay_System::GetFocusGadget())
			{
				Asura_Overlay_System::ReleaseFocus();
			}
			pxGadget = pxGadget->m_pxNextGadget;
		}

		delete m_pxGadgetList;
		m_pxGadgetList = 0;
	}


	//and create new ones
	Asura_Vector_2 xPos = m_xGadgetOffset;


	pxGadget  = new Asura_IncrementorFloat_Gadget(xPos,&m_fDisplayedTime,fMin,fMax,-fDelta,&m_bGadgetChanged);
	AddGadget(pxGadget);
	
	xPos.x += pxGadget->m_fWidth*2;
	
	const char* pszPrintFormat = (m_iTimerMode == CUTSCENETIMER_SECONDS) ? "%.3f" : "%.0f";

	pxGadget  = new Asura_Float_Gadget(xPos,&m_fDisplayedTime,fMin,fMax,pszPrintFormat,&m_bGadgetChanged);
	AddGadget(pxGadget);

	xPos.x += pxGadget->m_fWidth;

	pxGadget  = new Asura_IncrementorFloat_Gadget(xPos,&m_fDisplayedTime,fMin,fMax,fDelta,&m_bGadgetChanged);
	AddGadget(pxGadget);

	xPos.x += pxGadget->m_fWidth*2;
	
	m_xOffset.x = xPos.x;

	m_xMaxCoord.x = m_xOffset.x + Asura_Text_Output::WidthOfString(m_xName.GetString(),ASURA_TEXT_FORMAT_SMALLFONT);
	m_xMaxCoord.y = m_xOffset.y + 1.0f;
}


void Tools_CutsceneTime_Dialog::PerFrameUpdate()
{
	Asura_Dialog::PerFrameUpdate();

	//has timer been modified by gadget?
	if(m_bGadgetChanged)
	{
		*m_pfTime = Tools_Mode_Cutscene::ConvertDisplayedTimeToSeconds(m_fDisplayedTime,m_iTimerMode);
		m_fTimeBackup = *m_pfTime;

		//make sure time is in range
		//(if it gets altered here , the gadget will get updated correctly the backup time will differ)
		if(*m_pfTime<m_fMin)
		{
			*m_pfTime = m_fMin;
		}
		else if(*m_pfTime>m_fMax)
		{
			*m_pfTime = m_fMax;
		}
		if(m_pbChangedFlag) *m_pbChangedFlag = true;
		m_bGadgetChanged = false;

	}

	//has the time been modified outside of the gadget?
	if(*m_pfTime != m_fTimeBackup)
	{
		m_fTimeBackup = *m_pfTime;
		m_fDisplayedTime = Tools_Mode_Cutscene::ConvertSecondsToDisplayedTime(m_fTimeBackup,m_iTimerMode);
	}

	//has the timer mode been changed?
	if(m_iTimerMode != Tools_Mode_Cutscene::GetTimerMode())
	{
		m_iTimerMode = Tools_Mode_Cutscene::GetTimerMode();

		//need to re-create the gadgets then
		CreateGadgets();
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////
/*---------------------------------**
** Tools_CutsceneTimeSlider_Dialog **
**---------------------------------*/

Tools_CutsceneTimeSlider_Dialog::Tools_CutsceneTimeSlider_Dialog(const Asura_Vector_2& xOffset,float* pfTime,float* pfMin,float* pfMax,float fSlideWidth,bool* pbChangedFlag)
:Asura_Dialog(0,xOffset)
{
	m_pbChangedFlag = pbChangedFlag;
	m_pfTime = pfTime;
	m_pfMin = pfMin;
	m_pfMax = pfMax;

	m_fTimeBackup = *m_pfTime;
	m_fMinBackup = *m_pfMin;
	m_fMaxBackup = *m_pfMax;

	m_xOffset = xOffset;
	m_fSlideWidth = fSlideWidth;

	CreateGadgets();

}

void Tools_CutsceneTimeSlider_Dialog::CreateGadgets()
{

	//get values to use for the current timer mode
	m_iTimerMode = Tools_Mode_Cutscene::GetTimerMode();
	m_fDisplayedTime = Tools_Mode_Cutscene::ConvertSecondsToDisplayedTime(*m_pfTime,m_iTimerMode);
	m_fDisplayedMin = Tools_Mode_Cutscene::ConvertSecondsToDisplayedTime(*m_pfMin,m_iTimerMode);
	m_fDisplayedMax = Tools_Mode_Cutscene::ConvertSecondsToDisplayedTime(*m_pfMax,m_iTimerMode);
	m_bGadgetChanged = false;

	Asura_Gadget* pxGadget;

	//delete old gadgets
	if(m_pxGadgetList)
	{
		//make sure the number gadget doesn't have focus first
		pxGadget = m_pxGadgetList;
		while(pxGadget)
		{
			if(pxGadget == Asura_Overlay_System::GetFocusGadget())
			{
				Asura_Overlay_System::ReleaseFocus();
			}
			pxGadget = pxGadget->m_pxNextGadget;
		}

		delete m_pxGadgetList;
		m_pxGadgetList = 0;
	}


	//and create new ones
	Asura_Vector_2 xPos = m_xOffset;

	char* pszPrintFormat = (m_iTimerMode == CUTSCENETIMER_SECONDS) ? "%.3f" : "%.0f";
	pxGadget = new Asura_NumberSlider_Gadget(m_xOffset,&m_fDisplayedTime,&m_fDisplayedMin,&m_fDisplayedMax,m_fSlideWidth,pszPrintFormat,&m_bGadgetChanged);
	AddGadget(pxGadget);

	m_xMaxCoord.x = m_xOffset.x + m_fSlideWidth;
	m_xMaxCoord.y = m_xOffset.y + 1.0f;
}

void Tools_CutsceneTimeSlider_Dialog::PerFrameUpdate()
{
	Asura_Dialog::PerFrameUpdate();

	//has timer been modified by gadget?
	if(m_bGadgetChanged)
	{
		*m_pfTime = Tools_Mode_Cutscene::ConvertDisplayedTimeToSeconds(m_fDisplayedTime,m_iTimerMode);
		m_fTimeBackup = *m_pfTime;

		//make sure time is in range
		//(if it gets altered here , the gadget will get updated correctly the backup time will differ)
		if(*m_pfTime<*m_pfMin)
		{
			*m_pfTime = *m_pfMin;
		}
		else if(*m_pfTime>*m_pfMax)
		{
			*m_pfTime = *m_pfMax;
		}
		if(m_pbChangedFlag) *m_pbChangedFlag = true;
		m_bGadgetChanged = false;

	}

	//has the time been modified outside of the gadget?
	if(*m_pfTime != m_fTimeBackup)
	{
		m_fTimeBackup = *m_pfTime;
		m_fDisplayedTime = Tools_Mode_Cutscene::ConvertSecondsToDisplayedTime(m_fTimeBackup,m_iTimerMode);
	}

	//or min or max?
	if(*m_pfMin != m_fMinBackup)
	{
		m_fMinBackup = *m_pfMin;
		m_fDisplayedMin = Tools_Mode_Cutscene::ConvertSecondsToDisplayedTime(m_fMinBackup,m_iTimerMode);
	}
	if(*m_pfMax != m_fMaxBackup)
	{
		m_fMaxBackup = *m_pfMax;
		m_fDisplayedMax = Tools_Mode_Cutscene::ConvertSecondsToDisplayedTime(m_fMaxBackup,m_iTimerMode);
	}

	//has the timer mode been changed?
	if(m_iTimerMode != Tools_Mode_Cutscene::GetTimerMode())
	{
		m_iTimerMode = Tools_Mode_Cutscene::GetTimerMode();

		//need to re-create the gadgets then
		CreateGadgets();
	}
}
