#include "ascript/Value.h"
#include "ascript/Expr.h"
#include "ascript/Environment.h"
#include "ascript/Object.h"
#include "ascript/Module.h"
#include "ascript/Iterator.h"
#include "ascript/Object_Function.h"
#include "ascript/Object_String.h"
#include "ascript/Object_Binary.h"
#include "ascript/Object_List.h"
#include "ascript/Object_Matrix.h"
#include "ascript/Object_Dict.h"
#include "ascript/Object_DateTime.h"
#include "ascript/Object_TimeDelta.h"
#include "ascript/Object_Iterator.h"
#include "ascript/Object_Stream.h"
#include "ascript/Object_Expr.h"
#include "ascript/Object_Environment.h"
#include "ascript/Object_Error.h"
#include "ascript/Object_URI.h"
#include "ascript/Object_Semaphore.h"
#include "ascript/Object_Struct.h"
#include "ascript/Object_Image.h"
#include "ascript/Object_Color.h"
#include "ascript/Object_Palette.h"
#include "ascript/Object_Audio.h"
#include "ascript/Object_Codec.h"

namespace AScript {

//-----------------------------------------------------------------------------
// static variables
//-----------------------------------------------------------------------------
ValueTypePool *ValueTypePool::_pInst = NULL;

const Complex	Value::_compZero;
const Value		Value::Null;
const Value		Value::Undefined(VTYPE_Undefined, true);
const ValueList	ValueList::Null;
const ValueMap	ValueMap::Null;
const ValueDict	ValueDict::Null;

//-----------------------------------------------------------------------------
// ValueTypeInfo
//-----------------------------------------------------------------------------
ValueTypeInfo::~ValueTypeInfo()
{
	Class::Delete(_pClass);
}

void ValueTypeInfo::SetClass(Class *pClass)
{
	_pClass = pClass;
	pClass->SetSymbol(_pSymbol);
	pClass->SetValueType(_valType);
}

//-----------------------------------------------------------------------------
// ValueTypePool
//-----------------------------------------------------------------------------
ValueTypePool::~ValueTypePool()
{
	foreach (ValueTypeList, ppValueTypeInfo, _valueTypeList) {
		ValueTypeInfo::Delete(*ppValueTypeInfo);
	}
}

void ValueTypePool::Initialize(Environment &env)
{
	if (_pInst == NULL) {
		_pInst = new ValueTypePool();
		_pInst->_Initialize(env);
	}
}

void ValueTypePool::_Initialize(Environment &env)
{
	// primitive types (this order is significant for IsPrimitive())
	AScript_RealizeVTYPE(Nil,			"nil");			// must be at first
	AScript_RealizeVTYPE(Undefined,		"undefined");	// must be at second
	AScript_RealizeVTYPE(Symbol,		"symbol");
	AScript_RealizeVTYPE(Boolean,		"boolean");
	AScript_RealizeVTYPE(Number,		"number");
	AScript_RealizeVTYPE(Complex,		"complex");
	// for declaration
	AScript_RealizeVTYPE(Quote,			"quote");
	AScript_RealizeVTYPE(Any,			"any");
	// container types
	AScript_RealizeVTYPE(Module,		"module");
	AScript_RealizeVTYPE(Class,			"class");
	// object types
	AScript_RealizeVTYPE(Object,		"object");
	AScript_RealizeVTYPE(Function,		"function");
	AScript_RealizeVTYPE(String,		"string");
	AScript_RealizeVTYPE(StringEmb,		"string_emb");
	AScript_RealizeVTYPE(Binary,		"binary");
	AScript_RealizeVTYPE(BinaryEmb,		"binary_emb");
	AScript_RealizeVTYPE(BinaryPtr,		"binaryptr");
	AScript_RealizeVTYPE(List,			"list");
	AScript_RealizeVTYPE(Matrix,		"matrix");
	AScript_RealizeVTYPE(Dict,			"dict");
	AScript_RealizeVTYPE(Stream,		"stream");
	AScript_RealizeVTYPE(DateTime,		"datetime");
	AScript_RealizeVTYPE(TimeDelta,		"timedelta");
	AScript_RealizeVTYPE(Iterator,		"iterator");
	AScript_RealizeVTYPE(Expr,			"expr");
	AScript_RealizeVTYPE(Environment,	"environment");
	AScript_RealizeVTYPE(Error,			"error");
	AScript_RealizeVTYPE(URI,			"uri");
	AScript_RealizeVTYPE(Semaphore,		"semaphore");
	AScript_RealizeVTYPE(Struct,		"struct");
	AScript_RealizeVTYPE(Image,			"image");
	AScript_RealizeVTYPE(Color,			"color");
	AScript_RealizeVTYPE(Palette,		"palette");
	AScript_RealizeVTYPE(Audio,			"audio");
	AScript_RealizeVTYPE(Codec,			"codec");
	// Class must be initialized at 1st
	Class *pClass = new Class(&env);
	AScript_VTYPEInfo(Object	)->SetClass(pClass);
	// Class_Function must be initialized at 2nd
	Class_Function *pClass_Function = new Class_Function(pClass);
	AScript_VTYPEInfo(Function	)->SetClass(pClass_Function);
	pClass_Function->Prepare();	// methods of Function can only be initialized here
	pClass->Prepare();			// methods of Object can only be initialized here
	// classes for primitive types
	AScript_VTYPEInfo(Nil		)->SetClass(new Class_Nil(pClass));
	AScript_VTYPEInfo(Undefined	)->SetClass(new Class(pClass));
	AScript_VTYPEInfo(Symbol	)->SetClass(new Class_Symbol(pClass));
	AScript_VTYPEInfo(Boolean	)->SetClass(new Class_Boolean(pClass));
	AScript_VTYPEInfo(Number	)->SetClass(new Class_Number(pClass));
	AScript_VTYPEInfo(Complex	)->SetClass(new Class_Complex(pClass));
	// for declaration
	AScript_VTYPEInfo(Quote		)->SetClass(new Class(pClass));
	AScript_VTYPEInfo(Any		)->SetClass(new Class(pClass));
	// other built-in object classes
	AScript_VTYPEInfo(String	)->SetClass(new Class_String(pClass));
	AScript_VTYPEInfo(Binary	)->SetClass(new Class_Binary(pClass));
	AScript_VTYPEInfo(BinaryPtr	)->SetClass(new Class_BinaryPtr(pClass));
	AScript_VTYPEInfo(List		)->SetClass(new Class_List(pClass));
	AScript_VTYPEInfo(Matrix	)->SetClass(new Class_Matrix(pClass));
	AScript_VTYPEInfo(Dict		)->SetClass(new Class_Dict(pClass));
	Class *pClassStream = new Class_Stream(pClass);
	AScript_VTYPEInfo(Stream	)->SetClass(pClassStream);
	AScript_VTYPEInfo(DateTime	)->SetClass(new Class_DateTime(pClass));
	AScript_VTYPEInfo(TimeDelta	)->SetClass(new Class_TimeDelta(pClass));
	AScript_VTYPEInfo(Iterator	)->SetClass(new Class_Iterator(pClass));
	AScript_VTYPEInfo(Expr		)->SetClass(new Class_Expr(pClass));
	AScript_VTYPEInfo(Environment)->SetClass(new Class_Environment(pClass));
	AScript_VTYPEInfo(Error		)->SetClass(new Class_Error(pClass));
	AScript_VTYPEInfo(URI		)->SetClass(new Class_URI(pClass));
	AScript_VTYPEInfo(Semaphore	)->SetClass(new Class_Semaphore(pClass));
	AScript_VTYPEInfo(Struct	)->SetClass(new Class_Struct(pClass));
	AScript_VTYPEInfo(Image		)->SetClass(new Class_Image(pClass));
	AScript_VTYPEInfo(Color		)->SetClass(new Class_Color(pClass));
	AScript_VTYPEInfo(Palette	)->SetClass(new Class_Palette(pClass));
	AScript_VTYPEInfo(Audio		)->SetClass(new Class_Audio(pClass));
	AScript_VTYPEInfo(Codec		)->SetClass(new Class_Codec(pClass));
}

ValueTypeInfo *ValueTypePool::Add(const Symbol *pSymbol)
{
	ValueType valType = static_cast<ValueType>(_valueTypeList.size());
	ValueTypeInfo *pValTypeInfo = new ValueTypeInfo(valType, pSymbol, NULL);
	_valueTypeList.push_back(pValTypeInfo);
	return pValTypeInfo;
}

ValueTypeInfo *ValueTypePool::Lookup(ValueType valType)
{
	return _valueTypeList[valType];
}

ValueTypePool *ValueTypePool::GetInstance()
{
	return _pInst;
}

//-----------------------------------------------------------------------------
// Value
//-----------------------------------------------------------------------------
Value::Value(const Value &value) : _valType(value._valType), _ownFlag(value._ownFlag)
{
	if (value.IsNumber()) {
		_u.num = value._u.num;
	} else if (value.IsBoolean()) {
		_u.flag = value._u.flag;
	} else if (value.IsSymbol()) {
		_u.pSymbol = value._u.pSymbol;
	} else if (value.IsComplex()) {
		_u.pComp = new Complex(*value._u.pComp);
	} else if (value.IsModule()) {
		_u.pModule = value._u.pModule->IncRef();
	} else if (value.IsClass()) {
		_u.pClass = value._u.pClass->IncRef();
	} else if (value.IsObject()) {
		_u.pObj = Object::Reference(value._u.pObj);
	} else {
		// nothing to do
	}
}

Value::Value(Object *pObj, bool ownFlag) :
							_valType(pObj->GetValueType()), _ownFlag(ownFlag)
{
	_u.pObj = pObj;
}

Value::~Value()
{
	if (IsInvalid()) return;
	// when the application teminates, it calls a destructor for statically
	// defined values such as Value::Null. until that timing, it's likely
	// that VTYPE_xxxx referenced in FreeResource() are not initialized and
	// it causes application error. to avoid such a case, the above line is
	// necessary.
	FreeResource();
}

// VTYPE_String, VTYPE_Binary, VTYPE_StringEmb, VTYPE_BinaryEmb
Value::Value(Environment &env, const char *str) : _valType(VTYPE_String), _ownFlag(true)
{
	_u.pObj = new Object_String(env, str);
}

Value::Value(Environment &env, const char *str, size_t len) : _valType(VTYPE_String), _ownFlag(true)
{
	_u.pObj = new Object_String(env, str, len);
}

Value::Value(Environment &env, ValueType valType, const char *str) : _valType(valType), _ownFlag(true)
{
	_u.pObj = new Object_String(env, str);
}

Value::Value(Environment &env, ValueType valType, const char *str, size_t len) : _valType(valType), _ownFlag(true)
{
	_u.pObj = new Object_String(env, str, len);
}

// VTYPE_Iterator
Value::Value(Environment &env, Iterator *pIterator) : _valType(VTYPE_Iterator), _ownFlag(true)
{
	_u.pObj = new Object_Iterator(env, pIterator);
}

// VTYPE_Stream
Value::Value(Environment &env, Stream *pStream) : _valType(VTYPE_Stream), _ownFlag(true)
{
	_u.pObj = new Object_Stream(env, pStream);
}

// VTYPE_Function
Value::Value(Environment &env, Function *pFunc, const Value &valueSelf) :
									_valType(VTYPE_Function), _ownFlag(true)
{
	_u.pObj = new Object_Function(env, pFunc, valueSelf);
}

// VTYPE_Expr
Value::Value(Environment &env, Expr *pExpr) : _valType(VTYPE_Expr), _ownFlag(true)
{
	_u.pObj = new Object_Expr(env, pExpr);
}

// VTYPE_DateTime
Value::Value(Environment &env, const DateTime &dateTime) : _valType(VTYPE_DateTime), _ownFlag(true)
{
	_u.pObj = new Object_DateTime(env, dateTime);
}

// VTYPE_TimeDelta
Value::Value(Environment &env, const TimeDelta &timeDelta) : _valType(VTYPE_TimeDelta), _ownFlag(true)
{
	_u.pObj = new Object_TimeDelta(env, timeDelta);
}

void Value::FreeResource()
{
	if (IsComplex()) {
		delete _u.pComp;
		_u.pComp = NULL;
	} else if (IsModule()) {
		if (_ownFlag) Module::Delete(_u.pModule);
		_u.pModule = NULL;
	} else if (IsClass()) {
		if (_ownFlag) Class::Delete(_u.pClass);
		_u.pClass = NULL;
	} else if (IsObject()) {
		if (_ownFlag) Object::Delete(_u.pObj);
		_u.pObj = NULL;
	} else { // Number, Boolean
		// nothing to do
	}
	_valType = VTYPE_Nil;
}

Value &Value::operator=(const Value &value)
{
	FreeResource();
	_valType = value._valType;
	_ownFlag = value._ownFlag;
	if (value.IsNumber()) {
		_u.num = value._u.num;
	} else if (value.IsBoolean()) {
		_u.flag = value._u.flag;
	} else if (value.IsSymbol()) {
		_u.pSymbol = value._u.pSymbol;
	} else if (value.IsComplex()) {
		_u.pComp = new Complex(*value._u.pComp);
	} else if (value.IsModule()) {
		_u.pModule = value._u.pModule->IncRef();
	} else if (value.IsClass()) {
		_u.pClass = value._u.pClass->IncRef();
	} else if (value.IsObject()) {
		_u.pObj = Object::Reference(value._u.pObj);
	} else {
		// nothing to do
		//_valType = VTYPE_Nil;
	}
	return *this;
}

const char *Value::GetTypeName() const
{
	return GetValueTypeSymbol(GetType())->GetName();
}

ObjectBase *Value::ExtractObject(Signal sig)
{
	ObjectBase *pObjBase = NULL;
	if (IsModule()) {
		pObjBase = GetModule();
	} else if (IsClass()) {
		pObjBase = GetClass();
	} else if (IsObject()) {
		pObjBase = GetObject();
		if (pObjBase->IsFunction()) {
			const Object_Function *pObjFunc =
								dynamic_cast<const Object_Function *>(pObjBase);
			Class *pClass = pObjFunc->GetFunction()->GetClassToConstruct();
			if (pClass != NULL) {
				InitAsClass(pClass->IncRef());
				pObjBase = pClass;
			}
		}
	} else {
		sig.SetError(ERR_ValueError,
			"%s can not be specified as l-value of field", GetTypeName());
		return NULL;
	}
	return pObjBase;
}

bool Value::IsFlatList() const
{
	return IsList() && GetList().IsFlat();
}

bool Value::IsInstanceOf(ValueType valType)
{
	if (_valType == valType) return true;
	const ValueTypeInfo *pValueTypeInfo =
							ValueTypePool::GetInstance()->Lookup(_valType);
	if (pValueTypeInfo == NULL) return false;
	for (Class *pClass = pValueTypeInfo->GetClass(); pClass != NULL;
										pClass = pClass->GetClassSuper()) {
		if (pClass->GetValueType() == valType) return true;
	}
	return false;
}

Object_String *Value::GetStringObj()
{
	return dynamic_cast<Object_String *>(_u.pObj);
}

Object_String *Value::GetStringObj() const
{
	return dynamic_cast<Object_String *>(_u.pObj);
}

Object_Stream *Value::GetStreamObj() const
{
	return dynamic_cast<Object_Stream *>(_u.pObj);
}

const char *Value::GetString() const
{
	return dynamic_cast<Object_String *>(_u.pObj)->GetString();
}

const String &Value::GetStringSTL() const
{
	return dynamic_cast<Object_String *>(_u.pObj)->GetStringSTL();
}

const Binary &Value::GetBinary() const
{
	return dynamic_cast<Object_Binary *>(_u.pObj)->GetBinary();
}

Object_BinaryPtr *Value::GetBinaryPtr() const
{
	return dynamic_cast<Object_BinaryPtr *>(_u.pObj);
}

const DateTime &Value::GetDateTime() const
{
	return dynamic_cast<Object_DateTime *>(_u.pObj)->GetDateTime();
}

const TimeDelta &Value::GetTimeDelta() const
{
	return dynamic_cast<Object_TimeDelta *>(_u.pObj)->GetTimeDelta();
}

bool Value::PropDir(Environment &env, Signal sig, SymbolSet &symbols)
{
	if (IsModule()) {
		return GetModule()->PropDir(sig, symbols);
	} else if (IsClass()) {
		return GetClass()->PropDir(sig, symbols);
	} else if (IsObject()) {
		return GetObject()->PropDir(sig, symbols);
	} else {
		return env.LookupClass(_valType)->PropDir(sig, symbols);
	}
}

ErrorType Value::GetErrorType() const
{
	return dynamic_cast<Object_Error *>(_u.pObj)->GetErrorType();
}

Object_List *Value::GetListObj()
{
	return dynamic_cast<Object_List *>(_u.pObj);
}

Object_List *Value::GetListObj() const
{
	return dynamic_cast<Object_List *>(_u.pObj);
}

Object_Matrix *Value::GetMatrixObj()
{
	return dynamic_cast<Object_Matrix *>(_u.pObj);
}

Object_Matrix *Value::GetMatrixObj() const
{
	return dynamic_cast<Object_Matrix *>(_u.pObj);
}

Object_Image *Value::GetImageObj()
{
	return dynamic_cast<Object_Image *>(_u.pObj);
}

Object_Image *Value::GetImageObj() const
{
	return dynamic_cast<Object_Image *>(_u.pObj);
}

Object_Color *Value::GetColorObj()
{
	return dynamic_cast<Object_Color *>(_u.pObj);
}

Object_Color *Value::GetColorObj() const
{
	return dynamic_cast<Object_Color *>(_u.pObj);
}

Object_Palette *Value::GetPaletteObj()
{
	return dynamic_cast<Object_Palette *>(_u.pObj);
}

Object_Palette *Value::GetPaletteObj() const
{
	return dynamic_cast<Object_Palette *>(_u.pObj);
}

ValueList &Value::GetList()
{
	return dynamic_cast<Object_List *>(_u.pObj)->GetList();
}

const ValueList &Value::GetList() const
{
	return dynamic_cast<const Object_List *>(_u.pObj)->GetList();
}

ValueDict &Value::GetDict()
{
	return dynamic_cast<Object_Dict *>(_u.pObj)->GetDict();
}

const ValueDict &Value::GetDict() const
{
	return IsDict()?
		dynamic_cast<const Object_Dict *>(_u.pObj)->GetDict() : ValueDict::Null;
}

Iterator *Value::GetIterator() const
{
	return IsIterator()?
		dynamic_cast<const Object_Iterator *>(_u.pObj)->GetIterator() : NULL;
}

Stream &Value::GetStream() const
{
	return dynamic_cast<Object_Stream *>(_u.pObj)->GetStream();
}

const Expr *Value::GetExpr() const
{
	return IsExpr()? dynamic_cast<Object_Expr *>(_u.pObj)->GetExpr() : NULL;
}

Function *Value::GetFunction()
{
	return IsFunction()? dynamic_cast<Object_Function *>(_u.pObj)->GetFunction() : NULL;
}

Object_Function *Value::GetFunctionObj()
{
	return IsFunction()? dynamic_cast<Object_Function *>(_u.pObj) : NULL;
}

Expr *Value::CloneExpr() const
{
	return IsExpr()? dynamic_cast<Object_Expr *>(_u.pObj)->GetExpr()->IncRef() :
			IsSymbol()? new Expr_Symbol(_u.pSymbol) : NULL;
}

ObjectBase *Value::GetObjectBase()
{
	if (IsObject()) {
		return _u.pObj;
	} else if (IsClass()) {
		return _u.pClass;
	} else if (IsModule()) {
		return _u.pModule;
	} else {
		return NULL;
	}
}

Iterator *Value::CreateIterator(Signal sig) const
{
	if (IsObject()) {
		return _u.pObj->CreateIterator(sig);
	}
	sig.SetError(ERR_ValueError, "value of %s cannot generate iterator", GetTypeName());
	return NULL;
}

String Value::ToString(Signal sig, bool exprFlag) const
{
	if (IsNumber()) {
		return NumberToString(_u.num);
	} else if (IsBoolean()) {
		return String(_u.flag?
			AScript_Symbol(true_)->GetName() : AScript_Symbol(false_)->GetName());
	} else if (IsSymbol()) {
		String str;
		if (exprFlag) str += '`';
		str += _u.pSymbol->GetName();
		return str;
	} else if (IsComplex()) {
		const Complex &comp = *_u.pComp;
		String str;
		char buff[32];
		if (comp.real() == 0. && comp.imag() == 0.) {
			::sprintf(buff, GetNumberFormat(), 0.);
			str += buff;
		} else if (comp.real() == 0.) {
			if (_u.pComp->imag() < 0.) str += "-";
			::sprintf(buff, GetNumberFormat(), ::fabs(_u.pComp->imag()));
			str += buff;
			str += AScript_Symbol(j)->GetName();
		} else if (comp.imag() == 0.) {
			::sprintf(buff, GetNumberFormat(), _u.pComp->real());
			str += buff;
		} else {
			::sprintf(buff, GetNumberFormat(), _u.pComp->real());
			str += buff;
			str += (_u.pComp->imag() >= 0.)? "+" : "-";
			::sprintf(buff, GetNumberFormat(), ::fabs(_u.pComp->imag()));
			str += buff;
			str += AScript_Symbol(j)->GetName();
		}
		return str;
	} else if (IsModule()) {
		return _u.pModule->ToString(sig, exprFlag);
	} else if (IsClass()) {
		return _u.pClass->ToString(sig, exprFlag);
	} else if (IsObject()) {
		return _u.pObj->ToString(sig, exprFlag);
	}
	return String(exprFlag? "nil" : "");
}

Number Value::ToNumber(bool allowPartFlag, bool &successFlag) const
{
	successFlag = true;
	if (IsNumber()) {
		return _u.num;
	} else if (IsBoolean()) {
		return _u.flag? 1. : 0.;
	} else if (IsString()) {
		const char *str = GetString();
		Number num = 0.;
		char *p = const_cast<char *>(str);
		if (str[0] == '0' &&
				(str[1] == 'x' || str[1] == 'X' || IsOctDigit(str[1]))) {
			num = static_cast<Number>(::strtoul(str, &p, 0));
		} else {
			num = ::strtod(str, &p);
		}
		successFlag = (p > str && (allowPartFlag || *p == '\0'));
		return num;
	} else {
		successFlag = false;
		return 0.;
	}
}

int Value::Compare(const Value &value1, const Value &value2)
{
	int rtn = -1;
	if (value1.GetType() != value2.GetType()) {
		rtn = static_cast<int>(value1.GetType()) -
								static_cast<int>(value2.GetType());
	} else if (value1.IsNumber()) {
		rtn = (value1.GetNumber() == value2.GetNumber())? 0 :
				(value1.GetNumber() < value2.GetNumber())? -1 : +1;
	} else if (value1.IsBoolean()) {
		rtn = static_cast<int>(value1.GetBoolean()) -
								static_cast<int>(value2.GetBoolean());
	} else if (value1.IsSymbol()) {
		rtn = static_cast<int>(value1.GetSymbol()->GetUniqNum()) -
										value2.GetSymbol()->GetUniqNum();
	} else if (value1.IsString()) {
		rtn = ::strcmp(value1.GetString(), value2.GetString());
	} else if (value1.IsDateTime()) {
		const DateTime &dt1 = value1.GetDateTime();
		const DateTime &dt2 = value2.GetDateTime();
		rtn = DateTime::Compare(dt1, dt2);
	} else if (value1.IsTimeDelta()) {
		rtn = TimeDelta::Compare(value1.GetTimeDelta(), value2.GetTimeDelta());
	} else if (value1.IsList()) {
		bool emptyFlag1 = value1.GetList().empty();
		bool emptyFlag2 = value2.GetList().empty();
		if (emptyFlag1 || emptyFlag2) {
			rtn = -(static_cast<int>(emptyFlag1) - static_cast<int>(emptyFlag2));
		} else {
			rtn = Value::Compare(value1.GetList().front(), value2.GetList().front());
		}
	} else if (value1.IsObject()) {
		rtn = value1.GetObject()->Compare(value2.GetObject());
	} else if (value1.IsInvalid() && value2.IsInvalid()) {
		rtn = 0;
	}
	return rtn;
}

void Value::Accept(Signal sig, ValueVisitor &visitor) const
{
	if (IsList()) {
		GetList().Accept(sig, visitor);
	} else {
		visitor.Visit(sig, *this);
	}
}

void Value::InitAsModule(Module *pModule)
{
	FreeResource();
	_valType = VTYPE_Module, _u.pModule = pModule;
}

void Value::InitAsClass(Class *pClass)
{
	FreeResource();
	_valType = VTYPE_Class, _u.pClass = pClass;
}

void Value::InitAsObject(Object *pObj)
{
	FreeResource();
	_valType = pObj->GetValueType(), _u.pObj = pObj;
	_ownFlag = true; //ownFlag;
}

void Value::InitAsIterator(Environment &env, Iterator *pIterator)
{
	Object_Iterator *pObj = new Object_Iterator(env, pIterator);
	InitAsObject(pObj);
}

ValueList &Value::InitAsList(Environment &env)
{
	Object_List *pObj = new Object_List(env);
	InitAsObject(pObj);
	return pObj->GetList();
}

Object_Matrix *Value::InitAsMatrix(Environment &env,
								int nRows, int nCols, const Value &valueElem)
{
	Object_Matrix *pObj = new Object_Matrix(env, nRows, nCols, valueElem);
	InitAsObject(pObj);
	return pObj;
}

Object_Matrix *Value::InitAsMatrix(Environment &env, Signal sig, const ValueList &valList)
{
	size_t nRows, nCols;
	if (!valList.CheckMatrix(&nRows, &nCols)) {
		sig.SetError(ERR_ValueError, "invalid matrix initialization");
		return NULL;
	}
	Object_List *pObjList = new Object_List(env);
	ValueList &valListDst = pObjList->GetList();
	valListDst.reserve(nRows * nCols);
	foreach_const (ValueList, pValue, valList) {
		if (pValue->IsList()) {
			foreach_const (ValueList, pValueElem, pValue->GetList()) {
				valListDst.push_back(*pValueElem);
			}
		} else {
			valListDst.push_back(*pValue);
		}
	}
	Object_Matrix *pObj =
			new Object_Matrix(env, pObjList, 0, 0, nRows, nCols, nCols, false);
	InitAsObject(pObj);
	return pObj;
}

ValueList &Value::InitAsList(Environment &env, size_t n, const Value &value)
{
	Object_List *pObj =
			(n == 0)? new Object_List(env) : new Object_List(env, n, value);
	InitAsObject(pObj);
	return pObj->GetList();
}

ValueDict &Value::InitAsDict(Environment &env)
{
	Object_Dict *pObj = new Object_Dict(env);
	InitAsObject(pObj);
	return pObj->GetDict();
}

Object_Binary *Value::InitAsBinary(Environment &env)
{
	Object_Binary *pObj = new Object_Binary(env);
	InitAsObject(pObj);
	return pObj;
}

Object_Binary *Value::InitAsBinary(Environment &env, const Binary &binary)
{
	Object_Binary *pObj = new Object_Binary(env, binary);
	InitAsObject(pObj);
	return pObj;
}

Object_Binary *Value::InitAsBinary(Environment &env, const char *buff, size_t size)
{
	Object_Binary *pObj = new Object_Binary(env, buff, size);
	InitAsObject(pObj);
	return pObj;
}

Object_BinaryPtr *Value::InitAsBinaryPtr(Environment &env,
									Object_Binary *pObjBinary, size_t offset)
{
	Object_BinaryPtr *pObj = new Object_BinaryPtr(env, pObjBinary, offset);
	InitAsObject(pObj);
	return pObj;
}

void Value::InitAsExpr(Environment &env, Expr *pExpr)
{
	Object_Expr *pObj = new Object_Expr(env, pExpr);
	InitAsObject(pObj);
}

void Value::InitAsEnvironment(Environment &env)
{
	Object_Environment *pObj = new Object_Environment(env);
	InitAsObject(pObj);
}

//-----------------------------------------------------------------------------
// ValueList
//-----------------------------------------------------------------------------
ValueList::ValueList(const ValueList &valList)
{
	reserve(valList.size());
	foreach_const (ValueList, pValue, valList) {
		push_back(*pValue);
	}
}

bool ValueList::IsFlat() const
{
	foreach_const (ValueList, pValue, *this) {
		if (pValue->IsList()) return false;
	}
	return true;
}

bool ValueList::IsContain(const Value &value) const
{
	foreach_const (ValueList, pValue, *this) {
		if (Value::Compare(*pValue, value) == 0) return true;
	}
	return false;
}

bool ValueList::IsContainIterator() const
{
	foreach_const (ValueList, pValue, *this) {
		if (pValue->IsIterator()) return true;
	}
	return false;
}

bool ValueList::CheckMatrix(size_t *pnRow, size_t *pnCol) const
{
	if (empty()) return false;
	size_t nRow = size();
	size_t nCol = 1;
	if (front().IsList()) {
		nCol = front().GetList().size();
		foreach_const (ValueList, pValueRow, *this) {
			if (!pValueRow->IsList()) {
				return false;
			} else if (pValueRow->GetList().size() != nCol) {
				return false;
			}
		}
	} else {
		foreach_const (ValueList, pValueCol, *this) {
			if (pValueCol->IsList()) return false;
		}
	}
	if (pnRow != NULL) *pnRow = nRow;
	if (pnCol != NULL) *pnCol = nCol;
	return true;
}

bool ValueList::AssumeSameLength(Signal sig,
						const ValueList &valList1, const ValueList &valList2)
{
	if (valList1.size() == valList2.size()) return true;
	sig.SetError(ERR_ValueError, "lists are different in length");
	return false;
}

void ValueList::ExtractFlat(ValueList &valList) const
{
	foreach_const (ValueList, pValue, *this) {
		if (pValue->IsList()) {
			pValue->GetList().ExtractFlat(valList);
		} else {
			valList.push_back(*pValue);
		}
	}
}

void ValueList::Accept(Signal sig, ValueVisitor &visitor) const
{
	foreach_const (ValueList, pValue, *this) {
		pValue->Accept(sig, visitor);
		if (sig.IsSignalled()) break;
	}
}

void ValueList::Append(const ValueList &valList)
{
	foreach_const (ValueList, pValue, valList) {
		push_back(*pValue);
	}
}

void ValueList::Print(Signal sig, int indentLevel) const
{
	foreach_const (ValueList, pValue, *this) {
		if (pValue->IsList()) {
			pValue->GetList().Print(sig, indentLevel + 1);
		} else {
			::printf("%*s%s\n",
					indentLevel * 2, "", pValue->ToString(sig).c_str());
		}
	}
}

bool ValueList::ToStringList(Signal sig, StringList &strList) const
{
	foreach_const (ValueList, pValue, *this) {
		String str = pValue->ToString(sig, false);
		if (sig.IsSignalled()) return false;
		strList.push_back(str);
	}
	return true;
}

//-----------------------------------------------------------------------------
// ValueMap
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// ValueDict
//-----------------------------------------------------------------------------
bool ValueDict::Store(Signal sig, const ValueList &valList, bool allowDupFlag)
{
	enum { FIELD_Key, FIELD_Value } field = FIELD_Key;
	Value valueIdx;
	const ValueList *pValList = &valList;
	if (valList.size() == 1 && valList[0].IsList()) {
		pValList = &valList[0].GetList();
	}
	foreach_const (ValueList, pValue, *pValList) {
		if (field == FIELD_Key) {
			Value value;
			valueIdx = *pValue;
			if (valueIdx.IsList()) {
				const ValueList &valListElem = valueIdx.GetList();
				if (valListElem.size() != 2) {
					sig.SetError(ERR_KeyError, "invalid key-value format");
					return false;
				}
				valueIdx = valListElem[0];
				value = valListElem[1];
			}
			if (!ValueDict::IsValidKey(valueIdx)) {
				sig.SetError(ERR_KeyError, "invalid value type for key");
				return false;
			}
			if (value.IsValid()) {
				ValueDict::iterator iterDst = find(valueIdx);
				if (iterDst == end()) {
					insert(ValueDict::value_type(valueIdx, value));
				} else if (allowDupFlag) {
					iterDst->second = value;
				} else {
					sig.SetError(ERR_KeyError, "duplicated key '%s'", valueIdx.ToString(sig).c_str());
					return false;
				}
			} else {
				field = FIELD_Value;
			}
		} else { // FIELD_Value
			ValueDict::iterator iterDst = find(valueIdx);
			if (iterDst == end()) {
				insert(ValueDict::value_type(valueIdx, *pValue));
			} else if (allowDupFlag) {
				iterDst->second = *pValue;
			} else {
				sig.SetError(ERR_KeyError, "duplicated key '%s'", valueIdx.ToString(sig).c_str());
				return false;
			}
			field = FIELD_Key;
		}
	}
	if (field == FIELD_Value) {
		sig.SetError(ERR_KeyError, "unmatching key-value pair");
		return false;
	}
	return true;
}

bool ValueDict::Store(Signal sig, const ValueDict &valDict, bool allowDupFlag)
{
	foreach_const (ValueDict, iterSrc, valDict) {
		const Value &valueIdx = iterSrc->first;
		ValueDict::iterator iterDst = find(valueIdx);
		if (iterDst == end()) {
			insert(*iterSrc);
		} else if (allowDupFlag) {
			iterDst->second = iterSrc->second;
		} else {
			sig.SetError(ERR_KeyError, "duplicated key '%s'", valueIdx.ToString(sig).c_str());
			return false;
		}
	}
	return true;
}

bool ValueDict::Store(Signal sig, const Value &valueIdx, const Value &value, bool allowDupFlag)
{
	if (!ValueDict::IsValidKey(valueIdx)) {
		sig.SetError(ERR_KeyError, "invalid value type for key");
		return false;
	} else if (!allowDupFlag && find(valueIdx) != end()) {
		sig.SetError(ERR_KeyError, "duplicated key '%s'", valueIdx.ToString(sig).c_str());
		return false;
	}
	insert(ValueDict::value_type(valueIdx, value));
	return true;
}

}
