////////////////////////////////////////////////////////////////////////////////
//    Scorched3D (c) 2000-2003
//
//    This file is part of Scorched3D.
//
//    Scorched3D 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.
//
//    Scorched3D 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 Scorched3D; if not, write to the Free Software
//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
////////////////////////////////////////////////////////////////////////////////

#include <GLEXT/GLState.h>
#include <GLEXT/GLViewPort.h>
#include <GLW/GLWToolTip.h>
#include <GLW/GLWidget.h>
#include <GLW/GLWFont.h>
#include <client/ScorchedClient.h>
#include <common/OptionsDisplay.h>
#include <common/Defines.h>
#include <string.h>

static Vector color(0.1f, 0.1f, 0.4f);
static Vector selectedColor(0.9f, 0.9f, 1.0f);

GLWToolTip *GLWToolTip::instance_ = 0;

GLWToolTip *GLWToolTip::instance()
{
	if (!instance_)
	{
		instance_ = new GLWToolTip;
	}
	return instance_;
}

GLWToolTip::GLWToolTip() : 
	GameStateI("GLWToolTip"),
	lastTip_(0), currentTip_(0),
	timeDrawn_(0.0f), timeSeen_(0.0),
	refreshTime_(100.0f)
{
}

GLWToolTip::~GLWToolTip()
{
}

bool GLWToolTip::addToolTip(const char *title, const char *text,
	float x, float y, float w, float h)
{
	if (!OptionsDisplay::instance()->getShowContextHelp()) return false;

	int mouseX = ScorchedClient::instance()->getGameState().getMouseX();
	int mouseY = ScorchedClient::instance()->getGameState().getMouseY();
	
	bool result = false;
	if (x < mouseX && mouseX < x + w &&
		y < mouseY && mouseY < y + h)
	{
		static GLWTip singleTip;
		singleTip.setText(title, text);

		currentX_ = x;
		currentY_ = y;
		currentW_ = w;
		currentH_ = h;
		currentTip_ = &singleTip;

		result = true;
	}
	return result;
}

bool GLWToolTip::addToolTip(GLWTip *tip, float x, float y, float w, float h)
{
	if (!OptionsDisplay::instance()->getShowContextHelp()) return false;

	int mouseX = ScorchedClient::instance()->getGameState().getMouseX();
	int mouseY = ScorchedClient::instance()->getGameState().getMouseY();
	
	bool result = false;
	if (x < mouseX && mouseX < x + w &&
		y < mouseY && mouseY < y + h)
	{
		currentX_ = x;
		currentY_ = y;
		currentW_ = w;
		currentH_ = h;
		currentTip_ = tip;

		result = true;
	}
	return result;
}

void GLWToolTip::setupTip(GLWTip *tip)
{
	currentTip_ = tip;
	tipTextWidth_ = 0.0f;
	tipTextHeight_ = 0.0f;
	tipTitle_ = tip->getTitle();
	tipText_ = tip->getText();
	tipTexts_.clear();
}

void GLWToolTip::calculateTip(GLWTip *tip)
{
	if (tipTextWidth_ != 0.0f) return;

	tipTextHeight_ = 24.0f;
	char *token = strtok((char *) tipText_.c_str(), "\n");
	while(token != NULL)
	{
		tipTexts_.push_back(token);
		tipTextHeight_ += 10.0f;
		token = strtok(NULL, "\n");
	}

	std::list<char *>::iterator itor;
	std::list<char *>::iterator enditor = tipTexts_.end();
	for (itor = tipTexts_.begin(); itor != enditor; itor++)
	{
		float width = float(GLWFont::instance()->getSmallPtFont()->
			getWidth(9,(*itor))) + 10.0f;
		if (width > tipTextWidth_) tipTextWidth_ = width;
	}

	float width = float(GLWFont::instance()->getSmallPtFont()->
		getWidth(11, tipTitle_.c_str())) + 10.0f; 
	if (width > tipTextWidth_) tipTextWidth_ = width;
}

void GLWToolTip::clearToolTip(float x, float y, float w, float h)
{
	if (!OptionsDisplay::instance()->getShowContextHelp()) return;

	int mouseX = ScorchedClient::instance()->getGameState().getMouseX();
	int mouseY = ScorchedClient::instance()->getGameState().getMouseY();
	
	if (x < mouseX && mouseX < x + w &&
		y < mouseY && mouseY < y + h)
	{
		currentTip_ = 0;
	}
}

void GLWToolTip::simulate(const unsigned state, float frameTime)
{
	timeDrawn_ += frameTime;
}

void GLWToolTip::draw(const unsigned state)
{
	if (currentTip_ != lastTip_) refreshTime_ = 100.0f;
	lastTip_ = currentTip_;
	currentTip_ = 0;

	if (lastTip_) timeSeen_ += timeDrawn_;
	else timeSeen_ -= timeDrawn_;
	refreshTime_ += timeDrawn_;
	timeDrawn_ = 0.0f;

	float showTime = 
		float(OptionsDisplay::instance()->getToolTipTime()) / 1000.0f;
	if (timeSeen_ <= -showTime)
	{
		timeSeen_ = -showTime;
		return;
	}

	if ((refreshTime_ > 1.0f || 
		tipX_ != currentX_ || 
		tipY_ != currentY_) && lastTip_)
	{
		tipX_ = currentX_;
		tipY_ = currentY_;
		tipW_ = currentW_;
		tipH_ = currentH_;

		lastTip_->populate();
		setupTip(lastTip_);
		refreshTime_ = 0.0f;
	}
	if (lastTip_) calculateTip(lastTip_);

	float alpha = timeSeen_ * 
		float(OptionsDisplay::instance()->getToolTipSpeed());
	if (alpha > 1.0f)
	{
		alpha = 1.0f;
		timeSeen_ = 1.0f / 
			float(OptionsDisplay::instance()->getToolTipSpeed());
	}

	GLState currentState(GLState::TEXTURE_OFF | GLState::DEPTH_OFF);

	float posX = tipX_;
	float posY = tipY_;
	float posW = tipTextWidth_;
	float posH = tipTextHeight_;

	int camWidth = GLViewPort::getWidth();
	if (posX > camWidth / 2)
	{
		posX -= posW + 5.0f;
	}
	else
	{
		posX += tipW_ + 5.0f;
	}
	int camHeight = GLViewPort::getHeight();
	if (posY > camHeight / 2)
	{
		posY -= posH;
	}
	else
	{
		posY += 5.0f;
	}

	if (posX < 0) posX = 0;
	else if (posX + posW > camWidth) posX -= posX + posW - camWidth;

	{
		if (OptionsDisplay::instance()->getSmoothLines())
		{
			glEnable(GL_LINE_SMOOTH);
		}

		GLState currentStateBlend(GLState::BLEND_ON);
		glColor4f(0.5f, 0.5f, 1.0f, 0.8f * alpha);	
		glBegin(GL_TRIANGLE_FAN);
			glVertex2f(posX + 10.0f, posY + 2.0f);
			glVertex2f(posX + 10.0f, posY);
			GLWidget::drawRoundBox(
				posX, posY,
				posW, posH, 10.0f);
			glVertex2f(posX + 10.0f, posY);
		glEnd();
		glColor4f(0.9f, 0.9f, 1.0f, 0.5f * alpha);
		glLineWidth(2.0f);
		glBegin(GL_LINE_LOOP);
			GLWidget::drawRoundBox(
				posX, posY,
				posW, posH, 10.0f);
		glEnd();
		glLineWidth(1.0f);

		if (OptionsDisplay::instance()->getSmoothLines())
		{
			glDisable(GL_LINE_SMOOTH);
		}
	}

	float pos = posY + posH - 16.0f;
	GLWFont::instance()->getSmallPtFont()->drawA(selectedColor, alpha, 11, posX + 3.0f, 
		pos, 0.0f, tipTitle_.c_str());
	pos -= 2.0f;

	std::list<char *>::iterator itor;
	std::list<char *>::iterator enditor = tipTexts_.end();
	for (itor = tipTexts_.begin(); itor != enditor; itor++)
	{
		pos -= 10.0f;

		GLWFont::instance()->getSmallPtFont()->drawA(
			color, alpha, 9, posX + 6.0f, 
			pos, 0.0f, (*itor));
	}
}
