/** SGX

The   sss    gggg x   x   
     s      g      x x    Engine
      sss   g  gg   x
         s  g   g  x x          Copyright 1995-2008.
     ssss    gggg x   x         Steven Goodwin. All Rights Reserved.
    
This version has been released under the GNU Public License v2.0.

Please see the license files for details.

File: src/sgx/gui/sgxwidget.cpp

*/

#include "sgx/core/core.hpp"
#include "sgx/graphics/graphics.hpp"
#include "sgx/gui/gui.hpp"

sgxWidget::sgxWidget(const tINT32 x, const tINT32 y, const CGUIDesignScreen::tWidgetType type):
	m_Type(type),

	m_pParent(NULL),
	m_bEnabled(TRUE),
	m_bVisible(TRUE),
	m_isOver(FALSE),
	m_pSelectCallback(NULL),
	m_State(FALSE),
	m_DirectedState(FALSE),
	m_pGroup(NULL),
	m_X(x), m_Y(y),
	m_KeyboardShortcut(0),
	m_KeyboardShortcutExt(0)
{
}

CGUIDesignScreen::tWidgetType	
sgxWidget::getType() {
	return m_Type;
}

void sgxWidget::update(const tREAL32 telaps) {
	sgxVector<sgxWidget *>::iterator it = m_Children.begin();
	for(;it!=m_Children.end();++it) {
		(*it)->update(telaps);
	}
}

tBOOL sgxWidget::draw(const tINT32 offsetX, const tINT32 offsetY) const {
	tBOOL rt = TRUE;

	if (!m_bVisible) {
		return FALSE;
	}

	sgxVector<sgxWidget *>::const_iterator cit = m_Children.begin();
	for(;cit!=m_Children.end();++cit) {
		if ((*cit)->m_bVisible) {
			rt &= (*cit)->draw(offsetX, offsetY);
		}
	}

	return rt;
}


tBOOL	sgxWidget::enable() {
	tBOOL prev = m_bEnabled;
	m_bEnabled = TRUE;
	return prev;
}

tBOOL	sgxWidget::disable() {
	tBOOL prev = m_bEnabled;
	m_bEnabled = FALSE;
	return prev;
}

tBOOL	sgxWidget::show() {
	tBOOL prev = m_bVisible;
	m_bVisible = TRUE;
	return prev;
}

tBOOL	sgxWidget::hide() {
	tBOOL prev = m_bVisible;
	m_bVisible = FALSE;
	return prev;
}

tBOOL sgxWidget::isVisible() const {
	return m_bVisible;
}

void	sgxWidget::setCallback(CSGXCallback *pCallback) {
	m_pSelectCallback = pCallback;
}


CSGXCallback *sgxWidget::getCallback() const {
	return m_pSelectCallback;
}

void 
sgxWidget::setText(const sgxString &s) {
	SGX_UNUSED(s);
}

void 
sgxWidget::getPosition(sgxPoint2i &pt) {
	pt.x = m_X;
	pt.y = m_Y;
}

void 
sgxWidget::setPosition(const sgxPoint2i &pt) {
	m_X = pt.x;
	m_Y = pt.y;
}

void 
sgxWidget::setPosition(const tINT32 x, const tINT32 y) {
	m_X = x;
	m_Y = y;
}

void 			
sgxWidget::setSize(const tINT32 w, const tINT32 h) {
SGX_UNUSED(w);
SGX_UNUSED(h);
}

tBOOL	sgxWidget::onPressed(const sgxVector2 &position) {
	SGX_UNUSED(position);
	m_DirectedState = TRUE;
	return TRUE;
}


tBOOL	sgxWidget::onRelease(const sgxVector2 &position) {
	if (m_DirectedState) {
		onSelect(position);
	}
	m_DirectedState = FALSE;
	return TRUE;
}


tBOOL	sgxWidget::onLeaveArea(const sgxVector2 &position) {
	SGX_UNUSED(position);
	m_DirectedState = FALSE;
	return TRUE;
}


tBOOL	sgxWidget::onReenterArea(const sgxVector2 &position) {
	SGX_UNUSED(position);
	m_DirectedState = TRUE;
	return TRUE;
}


tBOOL	sgxWidget::onKeyDown(const tUINT32 key) {
	SGX_UNUSED(key);
	return TRUE;
}


tBOOL	sgxWidget::onKeyUp(const tUINT32 key) {
	SGX_UNUSED(key);
	return TRUE;
}


tBOOL	sgxWidget::onHoverEnter(const sgxVector2 &position) {
	SGX_UNUSED(position);
	m_isOver = TRUE;
	return TRUE;
}


tBOOL	sgxWidget::onHoverLeave(const sgxVector2 &position) {
	SGX_UNUSED(position);
	m_isOver = FALSE;
	return TRUE;
}


tBOOL	sgxWidget::onFocusGain() {
	return TRUE;
}


tBOOL	sgxWidget::onFocusLose() {
	m_isOver = FALSE;
	return TRUE;
}


tBOOL	sgxWidget::onActiveGain() {
	return TRUE;
}


tBOOL	sgxWidget::onActiveLose() {
	m_isOver = FALSE;
	return TRUE;
}



tBOOL	sgxWidget::onSelect(const sgxVector2 &position) {
	SGX_UNUSED(position);
	if (m_pSelectCallback) {
		m_pSelectCallback->call((tMEM_SIZE)this);
	}
	CSGXGUI::get()->clearFocus();
	CSGXGUI::get()->clearActive();
	return TRUE;
}



tBOOL	sgxWidget::isFocused() const {
	return CSGXGUI::get()->getFocusWidget() == this;
}

tBOOL	sgxWidget::isActive() const {
	return CSGXGUI::get()->getActiveWidget() == this;
}

tBOOL	sgxWidget::isEnabled() const {
	return m_bEnabled;
}


tBOOL	sgxWidget::isPointInside(const sgxPoint2i &position) const {
	sgxRect2i rc;
	getArea(rc);
	return rc.isInside(position);
}

void	sgxWidget::getArea(sgxRect2i &rc) const {
	rc.left = m_X;
	rc.top = m_Y;
}


const sgxWidget *sgxWidget::getWidgetAt(const sgxPoint2i &position) const {
	return getWidgetAt(position);
}

sgxWidget *sgxWidget::getWidgetAt(const sgxPoint2i &position, const tSelectionSet fromSet) {
	if (!m_bEnabled) {
		return NULL;
	}
	//
	switch(fromSet) {
		case eFunctioningWidgets:
			switch(m_Type) {
				case CGUIDesignScreen::widgetImage:
				case CGUIDesignScreen::widgetText:
				case CGUIDesignScreen::widgetAnimatedImage:
					return NULL;
			}
			break;
	}
	//
	if (isPointInside(position)) {
		return this;
	}
	
	sgxPoint2i pos(position.x, position.y);
	pos.x -= m_X;
	pos.y -= m_Y;
	sgxVector<sgxWidget *>::iterator it = m_Children.begin();
	for(;it!=m_Children.end();++it) {
		if ((*it)->getWidgetAt(pos, fromSet)) {
			return *it;
		}
	}
	
	return NULL;
}

tUINT32			
sgxWidget::getWidgetListWithin(const sgxRect2i &rc, sgxVector<sgxWidget *> &widgetList) {
	tUINT32 count = widgetList.size();

	if (m_bEnabled) {
		sgxRect2i checkArea;
		sgxRect2i targetArea(rc);

		getArea(checkArea);
		if (targetArea.intersects(checkArea)) {
			widgetList.push_back(this);
		}
		//
		targetArea.left -= m_X;
		targetArea.top -= m_Y;
		targetArea.right -= m_X;
		targetArea.bottom -= m_Y;
		sgxVector<sgxWidget *>::iterator it = m_Children.begin();
		for(;it!=m_Children.end();++it) {
			(*it)->getWidgetListWithin(targetArea, widgetList);
		}
	}

	return widgetList.size() - count;
}

sgxWidget *sgxWidget::getWidget(const tUINT32 idx) {
	if (idx >= m_Children.size()) {
		return NULL;
	}
	return m_Children[idx];
}
	
sgxWidget *sgxWidget::addChildWidget(sgxWidget *pWidget) {
	m_Children.push_back(pWidget);
	pWidget->m_pParent = this;
	return pWidget;
}

sgxWidget *		
sgxWidget::getChildWidget(const tUINT32 idx) {
	if (idx < m_Children.size()) {
		return m_Children[idx];
	}
	return NULL;
}

/**
Returns the idx'th child widget of the given type. 
*/
sgxWidget *		
sgxWidget::getChildWidget(const tUINT32 idx, CGUIDesignScreen::tWidgetType type) {
	tUINT32 mx = m_Children.size();
	tUINT32 count = idx;
	for(tUINT32 i=0;i<mx;++i) {
		if (m_Children[i]->m_Type == type) {
			if (count == 0) {
				return m_Children[i];
			}
			--count;
		}
	}
	return NULL;
}


tBOOL 			
sgxWidget::reorderWidget(sgxWidget *pTargetWidget, const tDepthPosition pos, sgxWidget *pMarkerWidget) {
	sgxWidget *pParent = pTargetWidget->m_pParent;
	sgxVector<sgxWidget *>::iterator it = find(pParent->m_Children.begin(), pParent->m_Children.end(), pMarkerWidget);

	if (it != pParent->m_Children.end()) {
		if (pos == eInFrontOf) {
			if (++it == pParent->m_Children.end()) {
				pParent->m_Children.push_back(pTargetWidget);
			} else {
				pParent->m_Children.insert(it, pTargetWidget);
			}
		} else {
			pParent->m_Children.insert(it, pTargetWidget);
		}

		it = find(pParent->m_Children.begin(), pParent->m_Children.end(), pTargetWidget);
		pParent->m_Children.erase(it);
		//
		return TRUE;
	}

	return FALSE;
}

void sgxWidget::clearChildWidgets() {
	m_Children.clear();
}

void sgxWidget::releaseChildWidgets() {
	sgxVector<sgxWidget *>::iterator it = m_Children.begin();
	for(;it!=m_Children.end();++it) {
		delete (*it);
	}
	
	clearChildWidgets();
}

