#pragma once

#include <aplAggr.h>

#ifdef _MFC_VER
	#include <afxtempl.h>
#endif
#ifdef INHERIT_FROM_QOBJECT  // Это, если используется QML
	#include <QObject>
#endif

class CaplInstance;
class CaplValue;
class CaplAggr;
class CaplAttr;

typedef unsigned long apl_id; // тип для обозначений объектов

/** Возможные значения типов данных */
enum aplValueType{  aplNOTYPE=0,		/**< тип не задан*/
					aplINSTANCE=1,		/**< CaplInstance**/
					aplAGGR=2,			/**< CaplAggr*/
					aplINTEGER=3,		/**< int*/
					aplREAL=4,			/**< double*/
					aplSTRING=5,		/**< char**/
					aplBOOL=6,			/**< bool*/
					aplLOGICAL=7,		/**< long*/
					aplBINARY=8,		/**< char**/
					aplSELECT=9,		/**< char*/
					aplBLOB=10,			/**< любой*/
					aplENUMERATION=11,	/**< любой*/
					aplINTEGRATEDBIN=12	/**< CaplIntegrBINVal*/
};

class CaplIntegrBINVal{
public:
	int blobId;
	void Clear(){blobId=0;}
	void operator =(CaplIntegrBINVal &val){blobId=val.blobId;}
	bool operator ==(CaplIntegrBINVal &val){return blobId==val.blobId;}
};

/** способ кодирования русских букв в обменном файле*/
enum aplRusSaveMode{	aplWIN7BIT, /**< 7 bit но в кодировке WIN 1251*/
						aplWIN,     /**< 8 bit в кодировке WIN 1251*/
						aplISO      /**< как требует стандарт (7 bit в кодировке ISO)*/
	};



/** тип доступа (aplOWN < aplRW < aplRO < aplNO < aplNOT_DEFINED) */
enum aplAccessModeType{	aplOWN=0,	/**< владелец (можно все)  */
aplRW=1,	/**<  чтение и запись (нельзя удалять) */
aplRO=2,	/**<  только чтение */
aplNO=3,	/**<  нет доступа*/
aplNOT_DEFINED=4 /**<  доступ не определен*/
};


#define APL_TRUE 1
#define APL_FALSE 0
#define APL_UNKNOWN -1

/** Массив из Instance*/
typedef CaplTAggr <CaplInstance*, CaplInstance*, APLAGGR_UNIQUE | APLAGGR_LIST> aplExtent;

bool AFX_EXT_API aplExtentIsEqual(aplExtent &ext1, aplExtent &ext2); // Возвращает true, если все элементы ext1 и ext2 совпадают. Порядок не важен. Используется тупой перебор.


/** Массив из CaplValue*/
typedef CaplTAggr <CaplValue*,CaplValue*,APLAGGR_LIST|APLAGGR_AUTOKILLREF> TAKListPCaplValue;
/** Указатель на  Instance*/
typedef  CaplInstance* pCaplInstance;

#define APL_CAPLVALUE_CONSTR(TYPE_PAR) CaplValue(TYPE_PAR val):type(aplNOTYPE), m_bUseExternalString(false){Set((TYPE_PAR)val);}

//************************************************************************
//************************************************************************
//************************************************************************
/** Класс представляющий значение любого тиа (аналог VARIANT)*/
class AFX_EXT_CLASS CaplValue
{
public:

	// Attributes
	aplValueType type; /**< Текущий тип*/

protected:
	bool m_bUseExternalString; // строчки внешние - не удаляет. При задании значения только устанавливает ссылку.
public:

	/// значение
	union
	{
		INT32 ival;
		double rval;
		bool bval;
		char lval;
		CaplInstance *instval;
		TCHAR *sval;
		CaplAggr *aggrval;
		CaplDataBuf *binval;
		CaplIntegrBINVal *intbinval;
	};

	// Methods
public:
	CaplValue(){type=aplNOTYPE; m_bUseExternalString=false;} /**< Конструктор */
	/**< Конструкторы копирования >*/
	APL_CAPLVALUE_CONSTR(const CaplValue& )
	APL_CAPLVALUE_CONSTR(int)
	APL_CAPLVALUE_CONSTR(double)
	APL_CAPLVALUE_CONSTR(bool)
	APL_CAPLVALUE_CONSTR(char)
	APL_CAPLVALUE_CONSTR(CaplInstance*)
	APL_CAPLVALUE_CONSTR(const CString &)
	APL_CAPLVALUE_CONSTR(const CaplAggr&)
	APL_CAPLVALUE_CONSTR(const aplExtent&)
	APL_CAPLVALUE_CONSTR(CaplDataBuf&)
	APL_CAPLVALUE_CONSTR(CaplIntegrBINVal &)
 	APL_CAPLVALUE_CONSTR(LPCTSTR)
#ifdef _UNICODE
	CaplValue(const char* str);
#endif
#ifdef QSTRING_H
	CaplValue(const QString &str);
#endif

	virtual ~CaplValue(){Clear();}

	void Clear();				/**< Очиска данных  */

	/**@name Функции работы со строками */
	//@{
	/** Печать значения в строку*/
	void Print(CString &str, pCaplInstance *instmap=0, int instmapsize=0, aplRusSaveMode mode = aplWIN, CaplAttr *attr=0, bool bSaveRealId=false);
    CString Print(){CString cstr; Print(cstr); return cstr;}
	/** Чтение значения из строки*/
	bool ReadFromString(LPCTSTR str, int &pos, pCaplInstance *instmap, int instmapsize);
	/** Чтение значения из строи в формате обменного файла */
	bool ReadFromP21String(CString &input_string, int &pos, pCaplInstance *instmap, int instmapsize);
	//@}

	void PrintDebugInfo(CString &str); // Печатает значение с отладочной информацией


	/**@name Функции установки значения */
	//@{
	void Set(int val){Clear(); type=aplINTEGER; ival=val;};	/**< Установка значения типа aplINTEGER*/
	void Set(double val);									/**< Установка значения типа aplREAL*/
	void Set(bool val){Clear(); type=aplBOOL; bval=val;};	/**< Установка значения типа aplBOOL*/
	void Set(char val){Clear(); type=aplLOGICAL; lval=val;};/**< Установка значения типа aplLOGICAL*/
	void Set(CaplInstance *val);							/**< Установка значения типа aplINSTANCE*/
	void Set(const CString &val);							/**< Установка значения типа aplSTRING*/
	void Set(LPCTSTR val);								/**< Установка значения типа aplSTRING*/
	void Set(const CaplAggr &val);							/**< Установка значения типа aplAGGR*/
	void Set(const aplExtent &val);							/**< Установка значения типа aplAGGR из aplExtent*/
	void Set(CaplDataBuf &val);								/**< Установка значения типа aplBINARY*/
	void Set(CaplIntegrBINVal &val);						/**< Установка значения типа aplINTEGRATEDBIN*/
	void Set(const CaplValue &val);							/**< Установка значения из другого CaplValue*/
	void operator =(const CaplValue &val){Set(val);};				/**< Установка значения  из другого CaplValue*/

	void SetExternalString(LPCTSTR str);
	//@}

	/**@name Функции чтения значения */
	//@{

	/** Чтение значения типа aplINTEGER*/
	bool Get(int &rez) const	{ rez=0; if(type==aplINTEGER) {rez=ival; return true;} else return false;}
	/** Чтение значения типа aplREAL*/
	bool Get(double &rez) const	{ rez=0; if(type==aplREAL){rez=(double)rval; return true;}else if(type==aplINTEGER){rez=(double)ival; return true;} else return false;}
	/** Чтение значения типа aplBOOL*/
	bool Get(bool &rez) const;
	/** Чтение значения типа aplLOGICAL*/
	bool Get(char &rez) const;
	/** Чтение значения типа aplSTRING*/
	bool Get(CString &rez) const	{ rez=_T(""); if(type==aplSTRING) {rez=sval; return true;} else return false;}
	bool Get(_std_string &rez) const	{ rez=_T(""); if(type==aplSTRING) {rez=sval; return true;} else return false;}
	/** Чтение значения типа aplINSTANCE*/
	bool Get(pCaplInstance &rez) const		{rez=0; if(type==aplINSTANCE) {rez=instval;return true;} else return false;}
	/** Чтение значения типа aplAGGR*/
	bool Get(CaplAggr &rez) const; 
	/** Чтение значения типа aplAGGR из Instance*/
	bool Get(aplExtent &rez) const; 
	/** Чтение значения типа aplBINARY*/
	bool Get(CaplDataBuf **rez) const			{if(rez==0) return false; *rez=0; if(type==aplBINARY) {*rez=binval;return true;} else return false;}
	/** Чтение значения типа aplINTEGRATEDBIN*/
	bool Get(CaplIntegrBINVal &rez) const;

	//@}
    
	/**@name Функции сравнения */
	//@{

	/** Сравнивает два значения 
	@return true эквивалентности и false в различия */
	bool IsEqu(const CaplValue &val) const;
	
  	/** Сравнивает  текущее значение с val
	@return true эквивалентности и false в различия */
	bool operator ==(const CaplValue &val) const { return IsEqu(val); };

	/** Сравнивает  текущее значение с val
	@return false эквивалентности и true в различия */
    bool operator !=(const CaplValue &val) const {return !IsEqu(val);};
	//@}
	/** Сравнивает  текущее значение с val
	@return false эквивалентности и true в различия */
    bool operator>(const CaplValue &rVal) const;
    bool operator<(const CaplValue &rVal) const {return (!((*this)>rVal) && !IsEqu(rVal));};
	//@}

	/** Нестрогое сравнение двух значений. В случае если текущий тип AGGR, 
		возвращает true если в AGGR есть хоть один элемент совпадающий со значением в val
		И наоборот - если тип val AGGR, то возвращает true если в нем есть хоть один элемент совпадающий с текущим значением
		В остальном эквивалентно IsEqu
	@return true эквивалентности и false в различия */
	bool IsEquWithAggr(const CaplValue &val) const;


};

//////////////////////////////////////////////////////////////////////////
template<class value_type>
inline CaplValue aplMakeValue(value_type val)
{
	CaplValue value;
	value.Set(val);

	return value;
}

template<>
inline CaplValue aplMakeValue(const CString& val)
{
	CaplValue value;
	value.Set(val);

	return value;
}

template<>
inline CaplValue aplMakeValue(aplExtent& val)
{
	CaplValue value;
	value.Set(val);

	return value;
}

template<>
inline CaplValue aplMakeValue(CaplAggr& val)
{
	CaplValue value;
	value.Set(val);

	return value;
}

template<>
inline CaplValue aplMakeValue(CaplDataBuf& val)
{
	CaplValue value;
	value.Set(val);

	return value;
}

template<>
inline CaplValue aplMakeValue(CaplIntegrBINVal& val)
{
	CaplValue value;
	value.Set(val);

	return value;
}

template<>
inline CaplValue aplMakeValue(CaplValue& val)
{
	CaplValue value;
	value.Set(val);

	return value;
}
//////////////////////////////////////////////////////////////////////////

/** Описывает значение типа aplAGGR*/
class AFX_EXT_CLASS CaplAggr 
{
public:
	
	aplValueType type;		/**< Тип элементов*/
	TAKListPCaplValue aggr; /**< Массив элементов*/
	
	// Methods
	CaplAggr(aplValueType def_type=aplNOTYPE); /**< Конструктор*/
	virtual ~CaplAggr();

	void Clear(); /**< Очистка*/

	int GetSize() const;				/**< Возвращает количество элементов*/
	
	bool Append(const CaplAggr &aggr);	/**< Дополняет данными из другого CaplAggr*/

	bool Add(const CaplValue &value);	/**< Дополняет значением*/
	bool Add(int value);				/**< Дополняет значением*/
	bool Add(double value);				/**< Дополняет значением*/
	bool Add(bool value);				/**< Дополняет значением*/
	bool Add(pCaplInstance value);		/**< Дополняет значением*/
	bool Add(LPCTSTR value);		/**< Дополняет значением*/
	bool Add(const CString &value);		/**< Дополняет значением*/
	bool Add(const CaplAggr &value);	/**< Дополняет значением*/


	bool Insert(int index, const CaplValue &value);	/**< Вставляет значение value по индексу index со сдвигом последующих элементов*/
	bool Remove(int index);							/**< Удаляет значение индексу index со сдвигом последующих элементов*/

	/** Возвращает по индексу ссылку на значение - элемент массива (не копию)*/
	CaplValue *GetByIndex(int index) const {return aggr[index];}

	bool GetByIndex(int index,CaplValue &value) const;		/**< Возвращает по индексу значение (копирует значение)*/
	bool GetByIndex(int index,int &value) const;			/**< Возвращает по индексу значение*/
	bool GetByIndex(int index,double &value) const;			/**< Возвращает по индексу значение*/
	bool GetByIndex(int index,bool &value) const;			/**< Возвращает по индексу значение*/
	bool GetByIndex(int index,pCaplInstance &value) const;	/**< Возвращает по индексу значение*/
	bool GetByIndex(int index,CString &value) const;		/**< Возвращает по индексу значение*/
	bool GetByIndex(int index,CaplAggr &value) const;		/**< Возвращает по индексу значение*/

	bool IsEqual(CaplAggr &aggr2); // Возвращает true, если все элементы текущего и aggr2 совпадают. Порядок не важен. Используется тупой перебор.

};

//***********************************************************
//***********************************************************
//***********************************************************

/** Карта четырехбайтовое число-аггр*/
class AFX_EXT_CLASS CaplAggrMap 
{
private:
	CaplAggrMap(const CaplAggrMap& ){}
	CaplAggrMap& operator=(CaplAggrMap& ){return *this;}
public:	
	/** Элемент карты четырехбайтовое число-аггр*/
	class CaplAggrMapItem
	{
	public:
		CaplAggrMapItem(){in=-1;}
		virtual ~CaplAggrMapItem(){}
		long in;	  ///<Входной ключ
		CaplAggr out; ///<Выходной ключ
		CaplAggrMapItem & operator = (CaplAggrMapItem &item)
		{   
			if(&item==this)return *this;
			in=item.in;
			out.Clear();
			out.Append(item.out);
			return *this;
		}
	};

public:

	CaplAggrMap();
	CaplAggrMap(int max_size);	//Резервирует память под max_size элементов

	virtual ~CaplAggrMap();

	// Attributes
public:
	CaplAggrMapItem *Data;		/**< Данные*/
	long Size;					/**< Текущий размер*/
protected:
	long MaxSize;
	bool m_sorted;
		
	// Metods
public:
	bool SetSize(int max_size);			/**< Резервирование памяти для max_size элементов*/
	long GetSize(){return Size;};

	int Add(long in, CaplAggr &out);	/**< Добавление комбинации  in -  ключ, out - добавляемые элементы*/
	int Add(long in, long out);			/**< Добавление комбинации  in -  ключ, out - добавляемый элемент*/
	int Add(long in, CaplInstance *out);/**< Добавление комбинации  in -  ключ, out - добавляемый элемент*/
	
	bool Remove(int index);				/**< Удаление комбинации по индексу*/
	
	CaplAggrMapItem operator [](int index) const { return Data[index]; }	/**< Возврат комбинации по индексу*/
	
	void Clear();						/**< Очистка */
	void SortIn();						/**< Сортировка входных значений*/
	int QFindByIn(long data);			/**< Быстрый поиск индекса по входному значению*/
	CaplAggr* QGetByIn(long data);		/**< Быстрый поиск выходного значения по входному */
//	void *QGetPointerByIn(long data);	/**< Быстрый поиск выходного значения по входному */
};


#ifndef APL_NO_INSET_IN_DOC

int AFX_EXT_API aplQuickFind(int *array, int count, int value);
int AFX_EXT_API aplQuickFindP(void **array, int count, void *value);
int AFX_EXT_API aplQFindInstIdInExtent(aplExtent &ext, apl_id id, int max_size=-1, bool full_cycle=true, CaplInstance **founded_inst=0);
int AFX_EXT_API aplQFindInstInExtent(aplExtent &ext, CaplInstance *inst, bool full_cycle=true);
bool AFX_EXT_API aplGetWord(LPCTSTR str, int &pos, CString &word, bool make_lower=true);
bool AFX_EXT_API SkipBrackets(CString &input_string, int &pos);
void AFX_EXT_API ConvertP21String(CString &string, aplRusSaveMode initmode, aplRusSaveMode resultmode);
CString AFX_EXT_API GetOnlyFileName(CString &full_path);
CString AFX_EXT_API GetOnlyDirName(CString &file_name);


/////////////////////////////////////////////////////////////////////////////
// Класс- контейнер перечня инстанс - ее доступ к кому-то
class AFX_EXT_CLASS aplAccessEl{
public:
	aplAccessEl();

	void Set(aplAccessEl* old_el);
	bool compare(aplAccessEl* el);

	CaplInstance* inst;
	BOOL is_individual;
	aplAccessModeType access;
	CaplInstance* pattern;  
};
// Массив данных о доступе юзера к группе инстансов
//class aplAccessList: public CaplTAggr <aplAccessEl*,aplAccessEl*,APLAGGR_LIST|APLAGGR_AUTOKILLREF>
class AFX_EXT_CLASS aplAccessList: public CArray <aplAccessEl*,aplAccessEl*>
{
public:
	aplAccessList();
	virtual ~aplAccessList();

	void Clear();
	aplAccessEl* Find(CaplInstance* inst);
	void Set(aplAccessList* old_list);
	bool IsSetAccess();
	CString GetText(bool for_dialog=false);

	CaplInstance *user;
	bool	changed;
	bool multy;
};

class aplListAccess2Inst;
// Контейнер для структур юзеров
class AFX_EXT_CLASS aplUsers:public CArray <aplAccessList*,aplAccessList*> 
{
public:
	aplUsers(){m_auto_add=false;code1=0;code2=0;};
	virtual ~aplUsers();

	aplAccessList* Find(CaplInstance* user);
	void Clear();
	void RemoveAtWithDel(int indx);
	void Set(aplUsers &table);
	void Set(aplListAccess2Inst *table);
	void Sort();

	bool m_auto_add;
	int code1;
	int code2;
};

// Структура описывает доступе к инстансу 1) по умолчанию 2) по шаблону 3)группы юзеров
class AFX_EXT_CLASS aplAccess2Inst 
{
public:
	CaplInstance* inst;
	BOOL is_individual;
	BYTE access_def; // Эта переменная несет значение aplAccessModeType, но определена как BYTE так как напрямую пишется/читается в/из буфера
	CaplInstance* pattern;  
	bool	changed;

	aplAccess2Inst(){inst=0;pattern=0;is_individual=false;access_def=4;changed=false;multy=false;user_access.bAutoSort=true;};

	void Add(CaplInstance* user, aplAccessModeType access);
	BYTE Find(CaplInstance* user);
	int GetSize(){return user_access.Size;}
	bool Get(int indx,CaplInstance** user, aplAccessModeType &access);
	
	void ResetAccess();

	void Set(aplAccess2Inst* old_access);
	//bool IsSetAccess();
	CString GetText();
	bool multy;
private:
	//Карта доступа юзеров. В in - (CaplInstance* )user, в out - aplAccessModeType access;
	CaplMap user_access;

};

// Массив данных о доступе к инстансам
// в in - инстанс, в out - aplAccess2Inst*
class AFX_EXT_CLASS aplListAccess2Inst: public CaplMap
{
public:
	aplListAccess2Inst(){Clear();};
	aplAccess2Inst* Find(CaplInstance* inst);
	virtual ~aplListAccess2Inst();

	int Add(aplAccess2Inst* el);
	aplAccess2Inst* GetAt(int indx);
	void Clear();
	//void RemoveAtWithDel(int indx);
	void Set(aplListAccess2Inst &table);
	void Set(aplUsers* old_access,bool clear=true);
	void Sort();
	bool m_auto_add;
	bool identical_access4all;
	bool clear_old_ind_access;
	int code1;
	int code2;
	bool changed;
};


#endif // #ifndef APL_NO_INSET_IN_DOC
