// ---------------------------------------------------------------------------
// 
//   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 "../console/console.h"
using namespace Console;

#include "GL/gl.h"

#include "widgettext.h"
#include "widgetbutton.h"
#include "widgetradiogroup.h"

WidgetButton::WidgetButton(void) {
	WidgetText *labelText = new WidgetText();
	labelText->setText("OK");
	label = labelText;
	toggleable = false;
	toggleValue = false;
	isRadio = false;
	padding = 16;
	labelHAlign = 0;
}

// TODO: XML Constructor.

WidgetButton::~WidgetButton(void) {
	if(label) {
        label->parent = NULL;
        autoGenLuaWrapper_Widget_safeDelete(label);
    }
}

void WidgetButton::setLabel(const std::string &text) {

	WidgetText *labelText = dynamic_cast<WidgetText*>(label);
	
	if(labelText) {
		labelText->setText(text);
	} else {
		out("error") << "Tried to call WidgetButton::setLabel, but the label is no longer a WidgetText." << endl;
	}
}

std::string WidgetButton::getLabel(void) {
	
	WidgetText *labelText = dynamic_cast<WidgetText*>(label);
	
	if(labelText) {
		return labelText->getText();
	} else {
		out("error") << "Tried to call WidgetButton::getLabel, but the label is no longer a WidgetText." << endl;
	}

	return "";
}

void WidgetButton::replaceLabelWidget(Widget *newLabel) {
	
	if(!newLabel->parent) {
		
		autoGenLuaWrapper_Widget_safeDelete(label);
		
		label = newLabel;
		newLabel->parent = this;
	
	} else {
	
		out("error") << "Can't set something as a button label when it already has a parent." << endl;
	}
	
}

void WidgetButton::draw(void) {
	
	// TODO: If inactive, but focused, set background to mouseover
	//   state, even if the mouse isn't over us.
	
	Widget::draw();
	
	// FIXME: This is all basically what the WidgetAlignBox does...
	
	// Make the text as small as possible...
	label->setWidth(0);
	label->setHeight(0);
	
	glPushMatrix();

	float myWidth = getWidth();
	float myHeight = getHeight();
	float textWidth = label->getWidth();
	float textHeight = label->getHeight();
	
	float centerX = myWidth / 2.0;
	float centerY = myHeight / 2.0;

	float textX;
	float textY = centerY - textHeight / 2.0;

	if(labelHAlign == -1) {
		textX = padding;
	} else if(labelHAlign == 1) {
		textX = myWidth - (textWidth + padding);
	} else {
		textX = centerX - textWidth / 2.0;
	}

#ifdef WIDGET_SNAP_TO_PIXELS
    textX = int(textX + 0.5);
    textY = int(textY + 0.5);
#endif

	glTranslatef(textX, textY, 0);
	
	//pushClipArea(0, 0, textWidth, textHeight);
	label->draw();
	//popClipArea();
	
	glPopMatrix();
}

bool WidgetButton::handleEvent(const WidgetEvent *event) {
	
	// Save this because the normal event handler will clear it.
	bool primaryMouseDownOnMe = mouseButtonsDownOnMe[0];
	
	bool ret = Widget::handleEvent(event);
	
	if(!ret) {
		
		// Multiple things can result in a click. Check each of them.
		bool doClickEvent = false;
		
		if(event->type == WIDGETEVENT_MOUSEUP) {
			
			if(primaryMouseDownOnMe && event->mouse.button == 0 && mouseWasOverMe) {
				
				// A button was pressed and released on this button.
				if(event->mouse.button == 0) {
					
					doClickEvent = true;
					
				}
			}
		}
		
		// Handle keyboard and joystick events when we have focus.
		if(hasFocus) {
			
			if(event->type == WIDGETEVENT_KEYDOWN) {
				
				// Space and return are equivalent to a mouse click.
				if(event->keyboard.keyCode == WIDGET_KEY_RETURN || event->keyboard.keyCode == WIDGET_KEY_SPACE) {
					
					doClickEvent = true;
					
				}
			}
		}
		
		if(doClickEvent) {
			
			// Handle toggle stuff.
			if(toggleable && !isRadio) {
			
				// Normal toggle button.
				setToggleValue(!getToggleValue());
			
			} else if(toggleable && isRadio) {
				
				// Radio toggle - doesn't get turned off by
				// selecting it again. So really we just want
				// to turn it on and never off (from here).
				setToggleValue(true);
			}
			
			// Send a pseudo event.
			ret |= handleLuaEvent("onClick", event);
			
			// Don't return immediately, because we still need
			// to adjust the background according to this.
		}
		
		if(event->type == WIDGETEVENT_FOCUSACCEPT || event->type == WIDGETEVENT_FOCUSACCEPT_BACK) {
			// Yes, we will accept focus.
			return true;
		}
		
	}
	
	// Set background according to mouse state.
	
	if(toggleable) {
		
		// Toggleable checkbox thinger.
		
		// We flip the shown toggled value if the mouse is held on this
		// button so we can give an immediate visual response to the
		// click.
		if((mouseButtonsDownOnMe[0] && mouseWasOverMe) ? !toggleValue : toggleValue) {
			
			if(backgroundActive.size()) {
				
				// Checked box = active BG
				setBackgroundImage(backgroundActive);
			}
			
		} else {
			
			if(mouseWasOverMe && !toggleValue && backgroundMouseOver.size()) {
				
				// Unchecked and mouse over.
				setBackgroundImage(backgroundMouseOver);
				
			} else if(backgroundDefault.size()) {
				
				// Unchecked box = default BG
				setBackgroundImage(backgroundDefault);
			}
			
		}
		
	} else {
		
		// Not toggleable. Normal button.
		
		if(mouseButtonsDownOnMe[0] && mouseWasOverMe) {
			
			// Mouse is held down over this.
			if(backgroundActive.size()) {
				setBackgroundImage(backgroundActive);
			}
			
		} else if((mouseWasOverMe || hasFocus) && backgroundMouseOver.size()) {
			
			// Simple mouse over thing (optional).
			setBackgroundImage(backgroundMouseOver);
			
		} else {
			
			// Just set it to normal.
			if(backgroundDefault.size()) {
				setBackgroundImage(backgroundDefault);
			}
		}
	}
	
	return ret;
}

float WidgetButton::getMinWidth(void) {
	float ret1 = Widget::getMinWidth();
	float ret2 = 0;
	if(label) ret2 = label->getMinWidth() + padding;
	
	return ret1 > ret2 ? ret1 : ret2;
}

float WidgetButton::getMinHeight(void) {
	float ret1 = Widget::getMinHeight();
	float ret2 = 0;
	if(label) ret2 = label->getMinHeight() + padding;

	return ret1 > ret2 ? ret1 : ret2;
}

void WidgetButton::setBackgroundDefault(const std::string &fileName) {
	backgroundDefault = fileName;
}

void WidgetButton::setBackgroundActive(const std::string &fileName) {
	backgroundActive = fileName;
}

void WidgetButton::setBackgroundMouseOver(const std::string &fileName) {
	backgroundMouseOver = fileName;
}

std::string WidgetButton::getBackgroundDefault(void) {
	return backgroundDefault;
}

std::string WidgetButton::getBackgroundActive(void) {
	return backgroundActive;
}

std::string WidgetButton::getBackgroundMouseOver(void) {
	return backgroundMouseOver;
}

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

void WidgetButton::setToggleable(bool toggleable) {
	this->toggleable = toggleable;
}

bool WidgetButton::getToggleable(void) {
	return toggleable;
}

void WidgetButton::setToggleValue(bool toggleValue) {

	if(toggleValue && isRadio) {
		
		bool foundGroup = false;
		
		// Need to go up and let the radio group widget know.
		Widget *currentParent = parent;
		while(currentParent) {
			
			WidgetRadioGroup *group = dynamic_cast<WidgetRadioGroup*>(currentParent);
			if(group) {
				group->setSelectedOption(this);
				foundGroup = true;
				break;
			}
			
			currentParent = currentParent->getParent();
		}
		
		if(!foundGroup) {
			
			// If we let this go, then the radio button won't send the
			// message to the radio group to let it know that this is
			// now selected. This is bad.
			out("error") << "Setting a radio button's value to true without it being a child to a WidgetRadioGroup! Add it as a child first!" << endl;
			
		}
	}
	
	// TODO: Umm... send click event?
	this->toggleValue = toggleValue;
	
	
	// Update display...
	if(toggleValue) {
		
		if(backgroundActive.size()) {
			
			// Checked box = active BG
			setBackgroundImage(backgroundActive);
		}
		
	} else {
		
		if(backgroundDefault.size()) {
			
			// Unchecked box = default BG
			setBackgroundImage(backgroundDefault);
		}
	}
}

bool WidgetButton::getToggleValue(void) {
	return toggleValue;
}

void WidgetButton::setIsRadio(bool isRadio) {
	this->isRadio = isRadio;
}

bool WidgetButton::getIsRadio(void) {
	return isRadio;
}

void WidgetButton::setLabelPadding(float padding) {
	this->padding = padding;
}

float WidgetButton::getLabelPadding(void) {
	return padding;
}

void WidgetButton::setLabelHAlign(int align) {
	labelHAlign = align;
}

