//
// Object_Struct
//

#include "ascript/Object_Struct.h"

namespace AScript {

//-----------------------------------------------------------------------------
// Object_Struct
//-----------------------------------------------------------------------------
Object_Struct::Object_Struct(const Object_Struct &obj) : Object(obj)
{
}

Object_Struct::~Object_Struct()
{
}

Object *Object_Struct::Clone() const
{
	return new Object_Struct(*this);
}

String Object_Struct::ToString(Signal sig, bool exprFlag)
{
	bool evaluatedFlag = false;
	Value value = EvalMethod(sig, AScript_Symbol(__str__),
											ValueList::Null, evaluatedFlag);
	if (evaluatedFlag) return value.ToString(sig, false);
	String str;
	str += _pClass->GetName();
	str += "(";
	const DeclarationList &declList = GetDeclList();
	foreach_const (DeclarationList, ppDecl, declList) {
		const Declaration *pDecl = *ppDecl;
		if (ppDecl != declList.begin()) str += ", ";
		str += pDecl->GetSymbol()->GetName();
		str += " => ";
		const Value *pValue = LookupValue(pDecl->GetSymbol(), false);
		if (pValue == NULL) {
			str += "nil";
		} else {
			str += pValue->ToString(sig, true);
		}
	}
	str += ")";
	return str;
}

const DeclarationList &Object_Struct::GetDeclList() const
{
	Class *pClass = _pClass;
	for ( ; pClass != NULL; pClass = pClass->GetClassSuper()) {
		if (pClass->GetConstructor()->IsStructPrototype()) break;
	}
	if (pClass == NULL) pClass = _pClass;
	return pClass->GetConstructor()->GetDeclOwner();
}

//-----------------------------------------------------------------------------
// AScript interfaces for Object_Struct
//-----------------------------------------------------------------------------
// struct#tolist()
AScript_DeclareMethod(Struct, tolist)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	SetHelp(
	"Returns a list of values extracted from the struct object in an order\n"
	"declared by struct() function.");
}

AScript_ImplementMethod(Struct, tolist)
{
	Object_Struct *pSelf = Object_Struct::GetSelfObj(args);
	Value result;
	ValueList &valList = result.InitAsList(env);
	const DeclarationList &declList = pSelf->GetDeclList();
	foreach_const (DeclarationList, ppDecl, declList) {
		const Value *pValue = pSelf->LookupValue((*ppDecl)->GetSymbol(), false);
		if (pValue == NULL) {
			valList.push_back(Value::Null);
		} else {
			valList.push_back(*pValue);
		}
	}
	return result;
}

// assignment
Class_Struct::Class_Struct(Environment *pEnvOuter) : Class(pEnvOuter)
{
	AScript_AssignMethod(Struct, tolist);
}

Object *Class_Struct::CreateDescendant(Environment &env, Signal sig, Class *pClass)
{
	return new Object_Struct((pClass == NULL)? this : pClass);
}

}
