/** SGX

The   sss    gggg x   x   
     s      g      x x    Engine
      sss   g  gg   x
         s  g   g  x x          Copyright 1995-2009.
     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: sgx/src/utils/guidesign/guidesign.cpp

*/

#include "sgx/core/core.hpp"
#include "sgx/graphics/graphics.hpp"
#include "sgx/filesystem/filesystem.hpp"
#include "sgx/gui/gui.hpp"
#include "utils/guidesign/guidesign.hpp"

//
//
//
CGUIDesign::CGUIDesign(tUINT32 numAssets) {
	m_pAssetList = new CGUIDesignAsset *[numAssets];
	m_iNumTextures = numAssets;
}

CGUIDesign::~CGUIDesign() {
	for(tUINT32 ia=0;ia<m_iNumTextures;++ia) {
		//delete m_pAssetList[ia];
	}
	for(tUINT32 is=0;is<m_iNumScreens;++is) {
		delete m_pScreenList[is];
	}
}

//
//
//
CGUIDesignScreen::CGUIDesignScreen(const tUINT32 id) :
m_pFrame(NULL),
m_ID(id) {
}

CGUIDesignScreen::~CGUIDesignScreen() {

	sgxVector<const sgxWidget *>::const_iterator cit = m_WidgetList.begin();

	for(;cit!=m_WidgetList.end();++cit) {
		delete *cit;
	}
	m_WidgetList.clear();
}

sgxWidget * 
CGUIDesignScreen::addWidget(sgxWidget *pWidget) {
	m_WidgetList.push_back(pWidget);
	return pWidget;
}



/**
This adds GUI elements into the current screen, based around
the descriptions present in the data file.
*/
sgxWidget *
CGUIDesignScreen::applyScreen() {
	if (!m_pFrame) {
		sgxVector<const sgxWidget *>::const_iterator cit = m_WidgetList.begin();

		m_pFrame = new sgxGUIFrame(0,0);	// don't create, because that adds it to the engine manager
		for(;cit!=m_WidgetList.end();++cit) {
			m_pFrame->addChildWidget(SGX_CONST_CAST(sgxWidget *, *cit));
		}
	}

	return m_pFrame;
}

void
CGUIDesignScreen::releaseScreenWidgets() {
	if (m_pFrame) {
		//m_pFrame->releaseChildWidgets();	// this isn't called, because we own the widgets in DesignScreen
		delete m_pFrame;
		m_pFrame = NULL;
	}
}

void 
CGUIDesign::adjustPosition(tINT32 &x, tINT32 &y, const tUINT32 w, const tUINT32 h, const tJustify fx, const tJustify fy) {
//	SGX_ASSERT(w && h && "
	switch(fx) {
		case fmtLeftJustify:
			break;
		case fmtCentreJustify:
			x -= w/2;
			break;
		case fmtRightJustify:
			x -= w;
			break;
	}
	//
	switch(fy) {
		case fmtTopAlignment:
			break;
		case fmtMiddleAlignment:
			y -= h/2;
			break;
		case fmtBottomAlignment:
			y -= h;
			break;
	}
}

CGUIDesignAsset *CGUIDesignAssetTextureData::load(const sgxString &str, const tUINT32 id) {
	CGUIDesignAsset *pAsset = new CGUIDesignAsset();
	pAsset->m_ID = id;
	pAsset->m_pData = SGX_STATIC_CAST(CGUIDesignAssetTextureData *, CSGXTextureManager::get()->loadTexture(str));
	return pAsset;
}

CGUIDesignAsset *CGUIDesignAssetAnimationData::load(const sgxString &str, const tUINT32 id) {
	CGUIDesignAsset *pAsset = new CGUIDesignAsset();
	pAsset->m_ID = id;
	CSGXTextureAnimationData *pAnim = CSGXTextureAnimationManager::get()->loadData(str);
	pAsset->m_pData = SGX_STATIC_CAST(CGUIDesignAssetAnimationData *, pAnim);
	return pAsset;
}

//
// The manager
//
CGUIDesign *
CSGXGUIDesignManager::loadDesign(const sgxString &filename) {
	CSGXFile file(filename+".dat");

	return loadDesign(file);
}

CGUIDesign *
CSGXGUIDesignManager::loadDesign(CSGXFile &file) {
	if (!file.open()) {
		return NULL;
	}

	tUINT32 numAssets;

	file >> numAssets;
	CGUIDesign *pDesign = new CGUIDesign(numAssets);
	for(tUINT32 i=0;i<numAssets;++i) {
		tUINT32 id;
		tBYTE assetType;
		sgxString str;
		file >> id >> assetType >> str;
		switch(assetType) {
			case CGUIDesign::assetAnimation:
				pDesign->m_pAssetList[i] = CGUIDesignAssetAnimationData::load(str, id);
				break;
			case CGUIDesign::assetTexture:
				pDesign->m_pAssetList[i] = CGUIDesignAssetTextureData::load(str, id);
				break;
			default:
				sgxError("No such asset type.");
				pDesign->m_pAssetList[i] = NULL;
		}
	}

	// Screens
	file >> pDesign->m_iNumScreens;
	pDesign->m_pScreenList = new CGUIDesignScreen *[pDesign->m_iNumScreens];
	for(tUINT32 i=0;i<pDesign->m_iNumScreens;++i) {
		tUINT32 items, id;
		file >> items >> id;
		CGUIDesignScreen *pCurrScreen = pDesign->m_pScreenList[i] = new CGUIDesignScreen(id);
		for(tUINT32 i=0;i<items;++i) {
			tBYTE type;
			file >> type;
			//
			tINT32 x,y,visible, enabled, fx, fy, userdata, keyShortcut, flags;
			
			sgxWidget *pWidget = NULL;
			file >> x >> y >> visible >> enabled >> keyShortcut >> flags >> fx >> fy >> userdata;
			switch(type) {
				case CGUIDesignScreen::widgetHotspot:
					{
						tUINT32  w, h;
						file >> w >> h;
						
						CGUIDesign::adjustPosition(x,y,w,h,(CGUIDesign::tJustify)fx,(CGUIDesign::tJustify)fy);
						pWidget = pCurrScreen->addWidget(CSGXGUI::get()->createHotSpot(x, y, sgxGUIHotSpotParams(w, h), /*cb*/NULL, /*ud*/0, FALSE));
					}
					break;
				case CGUIDesignScreen::widgetImage:
					{
						tUINT32 textureIndex, region, w, h, style, intColor;
						sgxColorRGBA col;
						file >> textureIndex >> region >> w >> h >> style >> intColor;

						col.fromInt(intColor);

						CGUIDesignAssetTextureData *pTexture = SGX_STATIC_CAST(CGUIDesignAssetTextureData *, pDesign->getAssetData(textureIndex));
						//
						if (w == 0) {
							w = pTexture->getRegionWidth(region);
						}
						if (h == 0) {
							h = pTexture->getRegionHeight(region);
						}
						// TODO: move this common code for vary offset. x-= xf{w}?
						CGUIDesign::adjustPosition(x,y,w,h,(CGUIDesign::tJustify)fx,(CGUIDesign::tJustify)fy);
						pWidget = pCurrScreen->addWidget(CSGXGUI::get()->createStaticImage(x, y, sgxGUIStaticImageParams(pTexture, region, (sgxGUIStaticImageParams::tStyle)style, col, w, h), FALSE));
					}
					break;

				case CGUIDesignScreen::widgetAnimatedImage:
					{
						tUINT32 textureIndex, w, h, intColor;
						tUINT32	animationAsset, animationSequence;
						sgxColorRGBA col;
						file >> textureIndex >> w >> h >> intColor >> animationAsset >> animationSequence;

						col.fromInt(intColor);

						CGUIDesignAssetTextureData *pTexture = SGX_STATIC_CAST(CGUIDesignAssetTextureData *, pDesign->getAssetData(textureIndex));
						CGUIDesignAssetAnimationData *pAnimation = SGX_STATIC_CAST(CGUIDesignAssetAnimationData *, pDesign->getAssetData(animationAsset));

						pWidget = pCurrScreen->addWidget(CSGXGUI::get()->createDynamicImage(x, y, sgxGUIDynamicImageParams(pTexture, pAnimation, animationSequence, w, h, (CGUIDesign::tJustify)fx, (CGUIDesign::tJustify)fy), FALSE));
					}
					break;

					
				case CGUIDesignScreen::widgetText:
					{
						sgxString str;
						tUINT32 color;
						sgxColorRGBA col;

						file >> str;
						file >> color;

						col.fromInt(color);

						pWidget = pCurrScreen->addWidget(CSGXGUI::get()->createStaticText(x, y, (CGUIDesign::tJustify)fx,(CGUIDesign::tJustify)fy, sgxGUIStaticTextParams(str, col), FALSE));
					}
					break;
				case CGUIDesignScreen::widgetButton:
					{
						tUINT32 w, h=0;
						sgxString txt;

						file >> w >> txt;
						
						if (w == 0) {
							w = CSGXGUI::get()->getCurrentSkin()->getDefaultButtonWidth();
						}
						if (h == 0) {
							h = CSGXGUI::get()->getCurrentSkin()->getDefaultButtonHeight();
						}

						CGUIDesign::adjustPosition(x,y,w,h,(CGUIDesign::tJustify)fx,(CGUIDesign::tJustify)fy);
						pWidget = pCurrScreen->addWidget(CSGXGUI::get()->createGUIButton(x, y, sgxGUIButtonParams(txt, (tINT32)w), FALSE));
					}
					break;
				case CGUIDesignScreen::widgetImageButton:
					{
						tUINT32 type;
						tUINT32 textureIndex, region;
						file >> type >> textureIndex >> region;

						tUINT32 w = CSGXGUI::get()->getCurrentSkin()->getDefaultImageButtonWidth();
						tUINT32 h = CSGXGUI::get()->getCurrentSkin()->getDefaultImageButtonHeight();

						if (textureIndex != -1) {
							CGUIDesignAssetTextureData *pTexture = SGX_STATIC_CAST(CGUIDesignAssetTextureData *, pDesign->getAssetData(textureIndex));
							w = pTexture->getRegionWidth(region);
							h = pTexture->getRegionHeight(region);
							CGUIDesign::adjustPosition(x,y,w,h,(CGUIDesign::tJustify)fx,(CGUIDesign::tJustify)fy);
							pWidget = pCurrScreen->addWidget(CSGXGUI::get()->createGUIImageButton(x, y, sgxGUIImageButtonParams(pTexture, region), FALSE));
						} else {
							CGUIDesign::adjustPosition(x,y,w,h,(CGUIDesign::tJustify)fx,(CGUIDesign::tJustify)fy);
							pWidget = pCurrScreen->addWidget(CSGXGUI::get()->createImageButton(x, y, sgxGUIImageButtonParams((sgxGUISkinnedImageButton::tButtonType)type), NULL, 0, FALSE));
						}
					}
					break;

				default:
					sgxTrace("WARNING: Unknown widget type: %d", type);
			}
			//
			if (pWidget) {
				pWidget->setFlags(flags);
				pWidget->setUserData(userdata);
				pWidget->setKeyShortcut(keyShortcut);

				if (!visible) {
					pWidget->hide();
				}
				if (!enabled) {
					pWidget->disable();
				}
			}
		}
	}

	return pDesign;
}

