/*
 * SenchaObject.cpp
 *
 *  Created on: Dec 5, 2012
 *      Author: attero
 */

#include "SenchaObject.h"

SenchaObject::SenchaObject() {
	set_null_value();
}

SenchaObject::~SenchaObject() {
	// Do nothing
}

bool SenchaObject::is_true()
{
	if(type == invalid || type == null)
	{
		return false;
	}
	if(type == boolean) return truthy;
	else return true;

}

void SenchaObject::set_value(std::string text)
{
	if(text[0] == '\"' && text[text.size()-1] == '\"')
	{
		this->text = text.substr(1, text.size()-2);
		type = string_literal;
	}
	else {
		this->text = text;
		type = string_literal;
	}
}

void SenchaObject::set_new_string(std::string text)
{
	this->text = text;
	type = string_literal;
}

void SenchaObject::set_null_value()
{
	this->type = null;
	this->integer = 0;
	this->number = 0;
	this->text = "";
}

void SenchaObject::set_value(int integer)
{
	this->integer = integer;
	type = integer_number;
}

void SenchaObject::set_value(double number)
{
	this->number = number;
	type = float_number;
}

void SenchaObject::set_value(bool logic)
{
	this->truthy = logic;
	type = boolean;
}

std::string SenchaObject::repr()
{
	std::string representation = "";
	switch(type){
	case string_literal:
		representation = "type: string\n";
		representation += this->text;
		break;
	case integer_number:
		representation = "type: integer\n";
		representation += to_string(this->integer);
		break;
	case float_number:
		representation = "type: float\n";
		representation += to_string(this->number);
		break;
	case null:
		representation = "type: null\n";
		representation += "null";
		break;
	case invalid:
		representation = "type: invalid\n";
		representation += "some crap";
		break;
	case boolean:
		representation = "type: boolean\n";
		representation += to_string(this->truthy);
		break;
	}
	return representation;
}
std::string SenchaObject::str()
{
	std::string representation = "";
	switch(type){
	case string_literal:
		representation += this->text;
		break;
	case integer_number:
		representation += to_string(this->integer);
		break;
	case float_number:
		representation += to_string(this->number);
		break;
	case null:
		representation += "null";
		break;
	case invalid:
		representation += "some crap";
		break;
	case boolean:
		representation += to_string(this->truthy);
		break;
	}
	return representation;
}

SenchaObject SenchaObject::operator+(const SenchaObject& right)const
{
	SenchaObject result;
	if(type == right.type)
	{
		switch(type){
		case string_literal:
			result.set_new_string(this->text + right.text);
			break;
		case integer_number:
			result.set_value(this->integer + right.integer);
			break;
		case float_number:
			result.set_value(this->number + right.number);
			break;
		case boolean:
			result.type = invalid;
			break;
		case invalid:
			result.type = invalid;
			break;
		case null:
			result.type = invalid;
			break;
		}
	}
	else if(type == float_number && right.type == integer_number )
	{
		result.set_value(this->number + right.integer);
	}
	else if(type == integer_number && right.type == float_number)
	{
		result.set_value(this->integer + right.number);
	}
	else
	{
		result.type = invalid;
	}

	return result;

}

SenchaObject SenchaObject::operator-(const SenchaObject& right)const
{
	SenchaObject result;
	if(type == right.type)
	{
		switch(type){
		case string_literal:
			result.type = invalid;
			break;
		case integer_number:
			result.set_value(this->integer - right.integer);
			break;
		case float_number:
			result.set_value(this->number - right.number);
			break;
		case boolean:
			result.type = invalid;
			break;
		case invalid:
			result.type = invalid;
			break;
		case null:
			result.type = invalid;
			break;
		}
	}
	else if(type == float_number && right.type == integer_number )
	{
		result.set_value(this->number - right.integer);
	}
	else if(type == integer_number && right.type == float_number)
	{
		result.set_value(this->integer - right.number);
	}
	else
	{
		result.type = invalid;
	}

	return result;
}

SenchaObject SenchaObject::operator*(const SenchaObject& right)const
{
	SenchaObject result;
	if(type == right.type)
	{
		switch(type){
		case string_literal:
			result.type = invalid;
			break;
		case integer_number:
			result.set_value(this->integer * right.integer);
			break;
		case float_number:
			result.set_value(this->number * right.number);
			break;
		case boolean:
			result.type = invalid;
			break;
		case invalid:
			result.type = invalid;
			break;
		case null:
			result.type = invalid;
			break;
		}
	}
	else if(type == float_number && right.type == integer_number )
	{
		result.set_value(this->number * right.integer);
	}
	else if(type == integer_number && right.type == float_number)
	{
		result.set_value(this->integer * right.number);
	}
	else
	{
		result.type = invalid;
	}

	return result;
}

SenchaObject SenchaObject::operator/(const SenchaObject& right)const
{
	SenchaObject result;
	if(type == right.type)
	{
		switch(type){
		case string_literal:
			result.type = invalid;
			break;
		case integer_number:
			result.set_value(this->integer / right.integer);
			break;
		case float_number:
			result.set_value(this->number / right.number);
			break;
		case boolean:
			result.type = invalid;
			break;
		case invalid:
			result.type = invalid;
			break;
		case null:
			result.type = invalid;
			break;
		}
	}
	else if(type == float_number && right.type == integer_number )
	{
		result.set_value(this->number / right.integer);
	}
	else if(type == integer_number && right.type == float_number)
	{
		result.set_value(this->integer / right.number);
	}
	else
	{
		result.type = invalid;
	}

	return result;
}

SenchaObject SenchaObject::operator==(const SenchaObject& right)const
														{
	SenchaObject result;
	bool value = false;
	result.type = boolean;

	if(type == right.type)
	{
		switch(type){
		case string_literal:
			if(this->text == right.text)
			{
				value = true;
			}
			break;
		case integer_number:
			if(this->integer == right.integer)
			{
				value = true;
			}
			break;
		case float_number:
			if(this->number == right.number)
			{
				value = true;
			}
			break;
		case boolean:
			if(this->truthy == right.truthy)
			{
				value = true;
			}
			break;
		case invalid:
			result.type = invalid;
			break;
		case null:
			result.type = invalid;
			break;
		}
	}

	result.truthy = value;
	return result;
														}

SenchaObject SenchaObject::operator!=(const SenchaObject& right) const
						{
	SenchaObject result;
	result.type = boolean;

	result = (*this == right);
	if(result.truthy)
		result.truthy = false;
	else result.truthy = true;

	return result;
						}


SenchaObject SenchaObject::operator>(const SenchaObject& right) const
{
	SenchaObject result;
	bool value = false;
	result.type = boolean;

	if(type == right.type)
	{
		switch(type){
		case string_literal:
			if(this->text > right.text)
			{
				value = true;
			}
			break;
		case integer_number:
			if(this->integer > right.integer)
			{
				value = true;
			}
			break;
		case float_number:
			if(this->number > right.number)
			{
				value = true;
			}
			break;
		case invalid:
			result.type = invalid;
			break;
		case boolean:
			result.type = invalid;
			break;
		case null:
			result.type = invalid;
			break;
		}
	}
	else if(type == float_number && right.type == integer_number )
	{
		value = (this->number > right.integer);
	}
	else if(type == integer_number && right.type == float_number)
	{
		value = (this->integer > right.number);
	}

	result.truthy = value;
	return result;
}

SenchaObject SenchaObject::operator>= (const SenchaObject& right) const
						{
	SenchaObject result;
	bool value = false;
	result.type = boolean;

	if((*this == right).truthy || ((*this) > right).truthy)
	{
		value = true;
	}
	result.truthy = value;
	return result;
						}

SenchaObject SenchaObject::operator< (const SenchaObject& right) const
{
	SenchaObject result;
	bool value = false;
	result.type = boolean;

	if(!((*this) >= right).truthy)
	{
		value = true;
	}
	result.truthy = value;
	return result;
}

SenchaObject SenchaObject::operator<= (const SenchaObject& right) const
{
	SenchaObject result;
	bool value = false;
	result.type = boolean;

	if(!((*this) > right).truthy)
	{
		value = true;
	}
	result.truthy = value;
	return result;
}

SenchaObject SenchaObject::operator-() const
{
	SenchaObject result = *this;
	if(this->type == integer_number) result.integer = - result.integer;
	else if(this->type == float_number) result.number = - result.number;
	else result.type = invalid;
	return result;
}
SenchaObject SenchaObject::operator!() const
{
	SenchaObject result = *this;
	if(this->type == boolean) result.truthy = ! result.truthy;
	else result.type = invalid;
	return result;
}
//TODO change code above to something more generic
