#include "ScrollbarWidget.h"
#include "WidgetManager.h"
#include "ScrollListener.h"
#include "ScrollbuttonWidget.h"

using namespace Sexy;

ScrollbarWidget::ScrollbarWidget(int theId, ScrollListener* theScrollListener) 
{
	mId = theId;
	mScrollListener = theScrollListener;		
		
	SetDisabled(true);
						
	mUpButton = new ScrollbuttonWidget(0, this);
	mUpButton->SetDisabled(true);
				
	mDownButton = new ScrollbuttonWidget(1, this);		
	mDownButton->SetDisabled(true);
		
	mInvisIfNoScroll = false;
	mPressedOnThumb = false;
	mValue = 0;
	mMaxValue = 0;
	mPageSize = 0;
	mUpdateAcc = 0;
	mButtonAcc = 0;
	mUpdateMode = 0;
	mHorizontal = false;

	AddWidget(mUpButton);
	AddWidget(mDownButton);
}

ScrollbarWidget::~ScrollbarWidget()
{
	RemoveAllWidgets(true);
}

void ScrollbarWidget::SetInvisIfNoScroll(bool invisIfNoScroll)
{
	mInvisIfNoScroll = invisIfNoScroll;

	if (mInvisIfNoScroll) 
	{
		SetVisible(false);
		mDownButton->SetVisible(false);
		mUpButton->SetVisible(false);
	}
}

void ScrollbarWidget::SetHorizontal(bool isHorizontal)
{
	mHorizontal = isHorizontal;
	mDownButton->mHorizontal = mHorizontal;
	mUpButton->mHorizontal = mHorizontal;
}


void ScrollbarWidget::ResizeScrollbar(int theX, int theY, int theWidth, int theHeight) 
{
	Resize(theX, theY, theWidth, theHeight);
	if (mHorizontal)
	{
		theX = theY = 0; // Use New Container Stuff
		mUpButton->Resize(theX, theY, theHeight, theHeight);
		mDownButton->Resize(theX + theWidth - theHeight, theY, theHeight, theHeight);
	}
	else
	{
		theX = theY = 0; // Use New Container Stuff
		mUpButton->Resize(theX, theY, theWidth, theWidth);
		mDownButton->Resize(theX, theY + theHeight - theWidth, theWidth, theWidth);
	}
}

void ScrollbarWidget::SetMaxValue(double theNewMaxValue) 
{
	mMaxValue = theNewMaxValue;
	ClampValue();
	MarkDirty();
}
	
void ScrollbarWidget::SetPageSize(double theNewPageSize) 
{
	mPageSize = theNewPageSize;
	ClampValue();
	MarkDirty();
}
	
void ScrollbarWidget::SetValue(double theNewValue) 
{
	mValue = theNewValue;		
	ClampValue();
	mScrollListener->ScrollPosition(mId, mValue);
	MarkDirty();
}
	
bool ScrollbarWidget::AtBottom() 
{
	return mMaxValue - mPageSize - mValue <= 1.0;
}
	
void ScrollbarWidget::GoToBottom() 
{
	mValue = mMaxValue - mPageSize;
	ClampValue();
	SetValue(mValue);
}
	
void ScrollbarWidget::DrawThumb(Graphics *g, int theX, int theY, int theWidth, int theHeight) 
{
	g->SetColor(Color(212, 212, 212));
	g->FillRect(theX, theY, theWidth, theHeight);
		
	g->SetColor(Color(255, 255, 255));
	g->FillRect(theX + 1, theY + 1, theWidth-2, 1);
	g->FillRect(theX + 1, theY + 1, 1, theHeight-2);
			
	g->SetColor(Color::Black);
	g->FillRect(theX, theY + theHeight - 1, theWidth, 1);
	g->FillRect(theX + theWidth - 1, theY, 1, theHeight);						
		
	g->SetColor(Color(132, 132, 132));
	g->FillRect(theX + 1, theY + theHeight - 2, theWidth - 2, 1);
	g->FillRect(theX + theWidth - 2, theY + 1, 1, theHeight - 2);					
}
	
int ScrollbarWidget::GetTrackSize() 
{
	if (mHorizontal)
		return mWidth-2*mUpButton->mWidth;
	else
		return mHeight-2*mUpButton->mWidth;
}
	
int ScrollbarWidget::GetThumbSize() 
{
	if (mPageSize > mMaxValue)
		return 0;
		
	int aThumbSize = (int) ((double) ((GetTrackSize() * mPageSize / mMaxValue)) + 0.5);
	return std::max(8, aThumbSize);
}
	
int ScrollbarWidget::GetThumbPosition() 
{
	if (mPageSize > mMaxValue) return mUpButton->mWidth;
	return (int) ((double) (((mValue * (GetTrackSize() - GetThumbSize())) / (mMaxValue - mPageSize))) + 0.5) + mUpButton->mWidth;
}

void ScrollbarWidget::Draw(Graphics *g) 
{
	int aThumbSize = GetThumbSize();
	int aThumbPosition = GetThumbPosition();
	
	if (mHorizontal)
	{
		if (mUpdateMode == UPDATE_MODE_PGUP) 
			g->SetColor(Color(48, 48, 48));
		else 
			g->SetColor(Color(232, 232, 232));				
		g->FillRect(0, 0, aThumbPosition, mHeight);
			
		if (aThumbSize > 0)	
			DrawThumb(g, aThumbPosition, 0, aThumbSize, mHeight);
			
		if (mUpdateMode == UPDATE_MODE_PGDN) 
			g->SetColor(Color(48, 48, 48));
		else 
			g->SetColor(Color(232, 232, 232));
		g->FillRect(aThumbPosition + aThumbSize, 0, mWidth - aThumbPosition - aThumbSize, mHeight);
	}
	else
	{
		if (mUpdateMode == UPDATE_MODE_PGUP) 
			g->SetColor(Color(48, 48, 48));
		else 
			g->SetColor(Color(232, 232, 232));				
		g->FillRect(0, 0, mWidth, aThumbPosition);
			
		if (aThumbSize > 0)	
			DrawThumb(g, 0, aThumbPosition, mWidth, aThumbSize);
			
		if (mUpdateMode == UPDATE_MODE_PGDN) 
			g->SetColor(Color(48, 48, 48));
		else 
			g->SetColor(Color(232, 232, 232));
		g->FillRect(0, aThumbPosition + aThumbSize, mWidth, mHeight - aThumbPosition - aThumbSize);
	}
}
	
void ScrollbarWidget::ClampValue() 
{
	double anOldValue = mValue;
		
	if (mValue > mMaxValue - mPageSize)
		mValue = mMaxValue - mPageSize;
	if (mValue < 0.0)
		mValue = 0.0;
		
	bool canScroll = mPageSize < mMaxValue;
		
	SetDisabled(!canScroll);
	mUpButton->SetDisabled(!canScroll);
	mDownButton->SetDisabled(!canScroll);
				
	if (mInvisIfNoScroll) 
	{
		SetVisible(canScroll);
		mDownButton->SetVisible(canScroll);
		mUpButton->SetVisible(canScroll);
	}
		
	if (mValue != anOldValue) mScrollListener->ScrollPosition(mId, mValue);
}		
	
void ScrollbarWidget::SetThumbPosition(int thePosition) 
{
	SetValue(((thePosition-mUpButton->mWidth) * (mMaxValue - mPageSize)) / (GetTrackSize() - GetThumbSize()));				
}
	
void ScrollbarWidget::ButtonPress(int theId) 
{
	mButtonAcc = 0;
		
	if (theId == 0) 
		SetValue(mValue-1);
	else 
		SetValue(mValue+1);
}

void ScrollbarWidget::ButtonDepress(int){}

void ScrollbarWidget::ButtonDownTick(int theId)
{
	if (theId == 0) 
	{
		if (++mButtonAcc >= 25)	
		{
			SetValue(mValue-1);
			mButtonAcc = 24;	
		}
	}
	else 
	{
		if (++mButtonAcc >= 25)	
		{
			SetValue(mValue+1);
			mButtonAcc = 24;
		}
	}
}
	
void ScrollbarWidget::Update()
{
	Widget::Update();

	switch (mUpdateMode)
	{
	case UPDATE_MODE_PGUP:
		if (ThumbCompare(mLastMouseX, mLastMouseY) != -1) 
		{
			mUpdateMode = UPDATE_MODE_IDLE;
			MarkDirty();
		}
		else if (++mUpdateAcc >= 25)
		{
			SetValue(mValue - mPageSize);
			mUpdateAcc = 20;
		}
		break;
	case UPDATE_MODE_PGDN:
		if (ThumbCompare(mLastMouseX, mLastMouseY) != 1) 
		{
			mUpdateMode = UPDATE_MODE_IDLE;
			MarkDirty();
		}
		else if (++mUpdateAcc >= 25) 
		{
			SetValue(mValue + mPageSize);
			mUpdateAcc = 20;
		}
		break;
	}
}
	
int ScrollbarWidget::ThumbCompare(int x, int y) 
{
	int aTrackPosition; 

	if (mHorizontal)
		aTrackPosition = x;
	else
		aTrackPosition = y;
		
	if (aTrackPosition < GetThumbPosition()) 
		return -1;

	if (aTrackPosition >= GetThumbPosition() + GetThumbSize()) 
		return 1;

	return 0;
}
	
void ScrollbarWidget::MouseDown(int x, int y, int theBtnNum, int theClickCount)
{
	Widget::MouseDown(x, y, theBtnNum, theClickCount);
		
	if (!mDisabled)
	{
		switch (ThumbCompare(x, y))	
		{
		case -1:
			SetValue(mValue - mPageSize);
			mUpdateMode = UPDATE_MODE_PGUP;
			mUpdateAcc = 0;
			break;
		case 0:
			mPressedOnThumb = true;
			mMouseDownThumbPos = GetThumbPosition();
			mMouseDownX = x;
			mMouseDownY = y;
			break;
		case 1:
			SetValue(mValue + mPageSize);
			mUpdateMode = UPDATE_MODE_PGDN;
			mUpdateAcc = 0;
			break;
		}
	}
		
	mLastMouseX = x;
	mLastMouseY = y;
}		
	
void ScrollbarWidget::MouseUp(int x, int y, int theBtnNum, int theClickCount) 
{
	Widget::MouseUp(x, y, theBtnNum, theClickCount);

	mUpdateMode = 0;
	mPressedOnThumb = false;
	MarkDirty();
}
	
void ScrollbarWidget::MouseDrag(int x, int y) 
{
	Widget::MouseDrag(x, y);
		
	if (mPressedOnThumb) 
	{
		if (mHorizontal)
			SetThumbPosition(mMouseDownThumbPos + x - mMouseDownX);
		else
			SetThumbPosition(mMouseDownThumbPos + y - mMouseDownY);
	}
		
	mLastMouseX = x;
	mLastMouseY = y;
}
