// ---------------------------------------------------------------------------
// 
//   Lily Engine alpha
// 
//   Copyright (c) 2010 Clifford Jolly
//     http://cliffjolly.com
//     cliff@cliffjolly.com
// 
// ---------------------------------------------------------------------------
// 
//   This program 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.
//  
//   This program 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 this program; if not, write to the Free Software
//   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
//   USA
// -------------------------- END HEADER -------------------------------------

#include "../hacks/winhacks.h"

#include <iostream>
using namespace std;

#include <GL/gl.h>

#include "../console/console.h"
using namespace Console;

#include "widgetbutton.h"
#include "widgetslider.h"

WidgetSlider::WidgetSlider(void) {
	maxValue = 1;
	value = 0;
	vertical = true;
	thingy = NULL;
	intValuesOnly = false;
	
	thingy = new Widget();
	thingySize = 16;
	
	fixup();
	
	mouseDragStartX = 0;
	mouseDragStartY = 0;
	mouseDragStartValue = 0;
	draggingThingy = false;
	
	smallStep = 0.1;
	bigStep = 0.5;
	inverted = false;
}

WidgetSlider::~WidgetSlider(void) {
	if(thingy) delete thingy;
}

void WidgetSlider::draw(void) {
	Widget::draw();
	
	pushClipArea(0, 0, width, height);
	
	if(thingy) {
		glPushMatrix();
		
		// TODO: A way to flip these around.
		if(vertical) {
			glTranslatef(0, getThingyDrawOffset(), 0);
		} else {
			glTranslatef(getThingyDrawOffset(), 0, 0);
		}
		
		thingy->draw();
		
		glPopMatrix();
	}
	
	popClipArea();
}

bool WidgetSlider::handleEvent(const WidgetEvent *event) {
	
	if(Widget::handleEvent(event)) {
		return true;
	}
	
	// TODO: Make drag events only start when touching the thingy?
	if(event->type == WIDGETEVENT_MOUSEDOWN) {
		
		if(event->mouse.button == 0) {
			
			float thingyStart = getThingyDrawOffset();
			float thingyEnd = thingyStart + (vertical ? thingy->getHeight() : thingy->getWidth());
			float mousePos = vertical ? event->mouse.y : event->mouse.x;
			
			if(mousePos < thingyStart) {
				
				// Mouse before thingy. Big step back.
				setValue(value - getBigStep() * (inverted ? -1 : 1));
				
			} else if(mousePos > thingyEnd) {
				
				// Mouse before thingy. Big step forward.
				setValue(value + getBigStep() * (inverted ? -1 : 1));
				
			} else {
				
				// Mouse on thingy. Start dragging.
				mouseDragStartX = event->mouse.x;
				mouseDragStartY = event->mouse.y;
				mouseDragStartValue = value;
				draggingThingy = true;
			}
			
			return true;
		}
		
		
		// Mouse wheel stuff.
		if(event->mouse.button == 4) {
			setValue(value + getSmallStep() * (inverted ? -1 : 1));
			return true;
		}
		
		if(event->mouse.button == 3) {
			setValue(value - getSmallStep() * (inverted ? -1 : 1));
			return true;
		}
		
	}
	
	if(event->type == WIDGETEVENT_MOUSEUP) {
		
		if(event->mouse.button == 0) {
			// End dragging.
			draggingThingy = false;
		}
		
	}
	
	//if(event->type == WIDGETEVENT_MOUSEMOTION && mouseButtonsDownOnMe[0]) {
	if(event->type == WIDGETEVENT_MOUSEMOTION && draggingThingy) {

		// How much room we have total to move in...
		float movableRoom = vertical ? (height - thingy->getHeight()) : (width - thingy->getWidth());
		
		// How much was actually moved.
		float movement = vertical ? (mouseDragStartY - event->mouse.y) : (mouseDragStartX - event->mouse.x);
		
		// Flipped value if not inverted.
		if(!inverted) movement *= -1;
		
		// Get percentage change.
		float fractionOfMovableChanged = movement / movableRoom;
		
		// End value is starting value + that offset percentage out of the maxValue.
		setValue(mouseDragStartValue + fractionOfMovableChanged * maxValue);
		
		return true;
	}
	
	// Handle keyboard events (mainly probably going to come from a
	// WidgetScrollable.
	if(event->type == WIDGETEVENT_KEYDOWN) {
		switch(event->keyboard.keyCode) {
			case WIDGET_KEY_UP:
				setValue(getValue() - getSmallStep());
				return true;
			case WIDGET_KEY_DOWN:
				setValue(getValue() + getSmallStep());
				return true;
			case WIDGET_KEY_PAGEUP:
				setValue(getValue() - getBigStep());
				return true;
			case WIDGET_KEY_PAGEDOWN:
				setValue(getValue() + getBigStep());
				return true;
			case WIDGET_KEY_END:
				setValue(getMaxValue());
				return true;
			case WIDGET_KEY_HOME:
				setValue(0);
				return true;
		}
	}
	
	return false;
}

float WidgetSlider::getMinWidth(void) {
	float mySize = Widget::getMinWidth();
	float childSize = thingy ? thingy->getMinWidth() : 0;
	return mySize > childSize ? mySize : childSize;
}

float WidgetSlider::getMinHeight(void) {
	float mySize = Widget::getMinHeight();
	float childSize = thingy ? thingy->getMinHeight() : 0;
	return mySize > childSize ? mySize : childSize;
}

void WidgetSlider::setWidth(float newWidth) {
	Widget::setWidth(newWidth);
	fixup();
}

void WidgetSlider::setHeight(float newHeight) {
	Widget::setHeight(newHeight);
	fixup();
}

void WidgetSlider::fixup(void) {
	if(thingy) {
		if(vertical) {
			thingy->setMinHeight(thingySize);
			thingy->setMinWidth(0);
			thingy->setWidth(width);
			thingy->setHeight(0);
		} else {
			thingy->setMinHeight(0);
			thingy->setMinWidth(thingySize);
			thingy->setWidth(0);
			thingy->setHeight(height);
		}
	}
	
	if(value > maxValue) value = maxValue;
	if(value < 0) value = 0;
	
	if(intValuesOnly) value = (int)value;
}

float WidgetSlider::getThingyDrawOffset(void) {
	if(!thingy) return 0;
	
	float movableRoom = vertical ? (height - thingy->getHeight()) : (width - thingy->getWidth());
	float percentage = (value / maxValue);
	
	// Flip it if we're in inverted mode.
	if(inverted) percentage = 1.0 - percentage;
	
	float offset = movableRoom * percentage;
	
	return offset;
}

float WidgetSlider::getMaxValue(void) {
	return maxValue;
}

void WidgetSlider::setMaxValue(float maxValue) {
	if(maxValue < 0.0001) maxValue = 0.0001;
	this->maxValue = maxValue;
	fixup();
}

float WidgetSlider::getValue(void) {
	return value;
}

void WidgetSlider::setValue(float value) {
	float startValue = this->value;
	
	this->value = value;
	fixup();

	if(startValue != value) {
		handleLuaEvent("onValueChanged", NULL);
	}
}

void WidgetSlider::setVertical(bool vertical) {
	if(this->vertical != vertical) {
		this->vertical = vertical;
		fixup();
	}
}

bool WidgetSlider::getVertical(void) {
	return vertical;
}

void WidgetSlider::setSmallStep(float step) {
	smallStep = step;
}

float WidgetSlider::getSmallStep(void) {
	return smallStep;
}

void WidgetSlider::setBigStep(float step) {
	bigStep = step;
}

float WidgetSlider::getBigStep(void) {
	return bigStep;
}

void WidgetSlider::setInverted(bool inverted) {
	this->inverted = inverted;
}

bool WidgetSlider::getInverted(void) {
	return inverted;
}

void WidgetSlider::setThingyImage(const std::string &image) {
	if(thingy) {
		thingy->setBackgroundImage(image);
	}
}

void WidgetSlider::setThingySize(float thingySize) {
	this->thingySize = thingySize;
}

bool WidgetSlider::isSizeDirty(void) {
	bool ret = Widget::isSizeDirty();
	if(thingy) {
		ret |= thingy->isSizeDirty();
	}
	return ret;
}

void WidgetSlider::overrideDragStart(float mousex, float mousey) {
	mouseDragStartX = mousex;
	mouseDragStartY = mousey;
	mouseDragStartValue = value;
	draggingThingy = true;
}

void WidgetSlider::overrideDragEnd() {
	draggingThingy = false;
}



