#ifndef __OBJECT_MATRIX_H__
#define __OBJECT_MATRIX_H__

#include "Object_List.h"

namespace AScript {

//-----------------------------------------------------------------------------
// Class_Matrix
//-----------------------------------------------------------------------------
class DLLDECLARE Class_Matrix : public Class {
public:
	Class_Matrix(Environment *pEnvOuter);
	virtual Object *CreateDescendant(Environment &env, Signal sig, Class *pClass);
};

//-----------------------------------------------------------------------------
// Object_Matrix
//-----------------------------------------------------------------------------
class DLLDECLARE Object_Matrix : public Object {
public:
	class IteratorEach : public Iterator {
	private:
		Object_Matrix *_pObj;
		size_t _iRow, _iCol;
		bool _transposeFlag;
	public:
		inline IteratorEach(Object_Matrix *pObj, bool transposeFlag) :
							Iterator(false), _pObj(pObj),
							_iRow(0), _iCol(0), _transposeFlag(transposeFlag) {}
		virtual ~IteratorEach();
		virtual bool DoNext(Environment &env, Signal sig, Value &value);
		virtual String ToString(Signal sig) const;
	};
	class IteratorEachRow : public Iterator {
	private:
		Object_Matrix *_pObj;
		size_t _iRow;
	public:
		inline IteratorEachRow(Object_Matrix *pObj) :
							Iterator(false), _pObj(pObj), _iRow(0) {}
		virtual ~IteratorEachRow();
		virtual bool DoNext(Environment &env, Signal sig, Value &value);
		virtual String ToString(Signal sig) const;
	};
	class IteratorEachCol : public Iterator {
	private:
		Object_Matrix *_pObj;
		size_t _iCol;
	public:
		inline IteratorEachCol(Object_Matrix *pObj) :
							Iterator(false), _pObj(pObj), _iCol(0) {}
		virtual ~IteratorEachCol();
		virtual bool DoNext(Environment &env, Signal sig, Value &value);
		virtual String ToString(Signal sig) const;
	};
private:
	Object_List *_pObjList;
	size_t _iRowOff, _iColOff;
	size_t _nRows, _nCols;
	size_t _nFold;
	bool _indexForColFlag;
public:
	AScript_DeclareObjectAccessor(Matrix)
public:
	Object_Matrix(Environment &env, size_t nRows, size_t nCols);
	Object_Matrix(Environment &env, size_t nRows, size_t nCols, const Value &valueElem);
	Object_Matrix(Environment &env, Object_List *pObjList,
				size_t iRowOff, size_t iColOff, size_t nRows, size_t nCols,
				size_t nFold, bool indexForColFlag);
	Object_Matrix(const Object_Matrix &obj);
	virtual ~Object_Matrix();
	//virtual bool IsMatrix() const;
	virtual Object *Clone() const;
	virtual Value EmptyIndexGet(Signal sig);
	virtual Value IndexGet(Signal sig, const Value &valueIdx);
	virtual void IndexSet(Signal sig, const Value &valueIdx, const Value &value);
	virtual String ToString(Signal sig, bool exprFlag);
	void ToList(ValueList &valList, bool transposeFlag, bool flattenFlag);
	inline size_t RowSize() const { return _nRows; }
	inline size_t ColSize() const { return _nCols; }
	inline size_t FoldSize() const { return _nFold; }
	inline ValueList &GetList() { return _pObjList->GetList(); }
	inline const ValueList &GetList() const { return _pObjList->GetList(); }
	inline ValueList::iterator GetPointer(size_t iRow, size_t iCol) {
		return GetList().begin() + _iColOff + iCol + (_iRowOff + iRow) * _nFold;
	}
	inline ValueList::const_iterator GetPointer(size_t iRow, size_t iCol) const {
		return GetList().begin() + _iColOff + iCol + (_iRowOff + iRow) * _nFold;
	}
	inline const Value &GetElement(size_t iRow, size_t iCol) {
		return *GetPointer(iRow, iCol);
	}
	inline void SetElement(size_t iRow, size_t iCol, const Value &value) {
		*GetPointer(iRow, iCol) = value;
	}
	Value GetSub(size_t iRow, size_t iCol, size_t nRows, size_t nCols);
	bool Set(Environment &env, Signal sig, Iterator *pIterator);
	bool SetRow(Environment &env, Signal sig, size_t iRow, Iterator *pIterator);
	bool SetCol(Environment &env, Signal sig, size_t iCol, Iterator *pIterator);
	Value GetRow(Environment &env, Signal sig, size_t iRow) const;
	Value GetCol(Environment &env, Signal sig, size_t iCol) const;
	Value Transpose(Environment &env, Signal sig);
	Value Inverse(Environment &env, Signal sig);
	static Value OperatorNeg(Environment &env, Signal sig,
										const Object_Matrix *pObjMat);
	static Value OperatorPlusMinus(Environment &env, Signal sig, const Function &func,
				const Object_Matrix *pObjMat1, const Object_Matrix *pObjMat2);
	static Value OperatorMultiply(Environment &env, Signal sig,
				const Object_Matrix *pObjMat1, const Object_Matrix *pObjMat2);
	static Value OperatorMultiply(Environment &env, Signal sig,
				const Object_Matrix *pObjMat, const Value &value);
	static Value OperatorMultiply(Environment &env, Signal sig,
				const Value &value, const Object_Matrix *pObjMat);
	static Value OperatorDivide(Environment &env, Signal sig,
				const Object_Matrix *pObjMat, const Value &value);
	static void SetError_IndexOutOfRange(Signal sig);
private:
	ValueType CheckValueType() const;
	static bool GetElemIndex(Environment &env, Signal sig,
		const Expr *pExprIdx, size_t nElemsSrc, size_t &iElem, size_t &nElems);
};

}

#endif
