// ---------------------------------------------------------------------------
// 
//   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 <iostream>
#include <sstream>
#include <cstdlib>
using namespace std;

#include "luavalue.h"

LuaValue::LuaValue(double n) {
	type = LUA_TNUMBER;
	numberValue = n;
}

LuaValue::LuaValue(const std::string &str) {
	type = LUA_TSTRING;
	stringValue = str;
}

LuaValue::LuaValue(bool b) {
	type = LUA_TBOOLEAN;
	boolValue = b;
}

LuaValue::LuaValue(void) {
	type = LUA_TNIL;
}

LuaValue::LuaValue(lua_State *L, int index) {
	int type = lua_type(L, index);
	switch(type) {
		case LUA_TBOOLEAN:
			*this = LuaValue(bool(lua_toboolean(L, index)));
			break;
		case LUA_TSTRING:
			*this = LuaValue(string(lua_tostring(L, index)));
			break;
		case LUA_TNUMBER:
			*this = LuaValue(lua_tonumber(L, index));
			break;
		case LUA_TNIL:
			*this = LuaValue();
			break;
		default:
			cout << "Error: Lua type " << lua_typename(L, type) << " is not supported by LuaValue." << endl;
			cout << "  (I'm going to treat this as a nil because I'm nice, but I'm still going to spew this ugly error at you.)" << endl;
			*this = LuaValue();
			break;
	}
}

LuaValue::LuaValue(TiXmlElement *xml) {
	
	if(xml->Attribute("type")) {
		
		string typeStr(xml->Attribute("type"));
		
		if(typeStr == "string") {
			
			type = LUA_TSTRING;
			if(xml->Attribute("value")) {
				stringValue = xml->Attribute("value");
			}
			
		} else if(typeStr == "number") {
			
			type = LUA_TNUMBER;
			numberValue = 0;
			xml->QueryDoubleAttribute("value", &numberValue);
			
		} else if(typeStr == "boolean") {
			
			type = LUA_TBOOLEAN;
			int v = 0;
			xml->QueryIntAttribute("value", &v);
			boolValue = (bool)v;
			
		} else {
			
			type = LUA_TNIL;
			
		}
		
	} else {
		
		type = LUA_TNIL;
	}
}

std::string LuaValue::toString(void) {
	ostringstream ostr;
	
	switch(type) {
		case LUA_TBOOLEAN:
			ostr << (boolValue ? "true" : "false");
			break;
		case LUA_TSTRING:
			return stringValue;
			break;
		case LUA_TNUMBER:
			ostr << numberValue;
			break;
		case LUA_TNIL:
			ostr << "nil"; // FIXME: Should I just have this be ""?
			break;
	}
	
	return ostr.str();
}

double LuaValue::toNumber(void) {
	switch(type) {
		case LUA_TBOOLEAN:
			return (boolValue ? 1 : 0);
			break;
		case LUA_TSTRING:
			return atoi(stringValue.c_str());
			break;
		case LUA_TNUMBER:
			return numberValue;
			break;
		case LUA_TNIL:
			return 0;
			break;
	}
	
	// If it gets here, something is wrong.
	// Whatever.
	return false;
}

bool LuaValue::toBool(void) {
	switch(type) {
		case LUA_TBOOLEAN:
			return boolValue;
			break;
		case LUA_TSTRING:
			if(stringValue == "0" || stringValue == "false" || stringValue == "" || stringValue == "FALSE") {
				return false;
			}
			return true;
			break;
		case LUA_TNUMBER:
			return !(numberValue == 0);
			break;
		case LUA_TNIL:
			return false;
			break;
	}
	
	// If it gets here, something is wrong.
	// Whatever.
	return false;
}

int LuaValue::getType(void) {
	return type;
}

std::string LuaValue::getTypeString(lua_State *L) {
	return string(lua_typename(L, type));
}

void LuaValue::push(lua_State *L) {
	switch(type) {
		case LUA_TBOOLEAN:
			lua_pushboolean(L, int(boolValue));
			break;
		case LUA_TSTRING:
			lua_pushstring(L, stringValue.c_str());
			break;
		case LUA_TNUMBER:
			lua_pushnumber(L, numberValue);
			break;
		case LUA_TNIL:
			lua_pushnil(L);
			break;
	}

}

