//this file is part of NeoMule
//Copyright (C)2006-2007 David Xanatos ( XanatosDavid@googlemail.com / http://neomule.sourceforge.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#pragma once
// NEO: FCFG - [FileConfiguration] -- Xanatos -->

///////////////////////////////////////////////////////////////////////
// Neo File Preferences
//

#define FCFG_BASE	2000000000	// lets take somethink easy to remember 2 eight 0's and a number // INT_MAX = 2147483647
#define FCFG_DEF	FCFG_BASE+1	// use default settings of the previuse level
#define FCFG_GLB	FCFG_BASE+2	// use default global setting
#define FCFG_AUT	FCFG_BASE+3	// use automatic value (only one valid for the base)
#define FCFG_STD	FCFG_BASE+4	// use standard value
#define FCFG_UNK	FCFG_BASE+5	// state unknown different files have different falues

#define FCFG_INI_DEF	_T("def")
#define FCFG_INI_GLB	_T("glb")
#define FCFG_INI_AUT	_T("aut")

#include <list>
#include "Neo/PrefFunctions.h"



enum EFilePrefsLevel{
	CFP_GLOBAL = 0,
	CFP_CATEGORY = 1,
	CFP_FILE = 2
};



class CTag;
class CKnownFile;
class CPartFile;
class CFileDataIO;
class CIni;

#define	PARTNEO_EXT		_T(".neo")
#define	PARTNEO_BAK_EXT	_T(".bak")
#define	PARTNEO_TMP_EXT	_T(".backup")

///////////////////////////////////////////////////////////////////////
// CKnownPreferences
//

class CKnownPreferences
{
public:
	CKnownPreferences();
	~CKnownPreferences();

	void	Save(CFileDataIO* file);
	bool	Load(CFileDataIO* file);
	void	Save(CIni& ini);
	bool	Load(CIni& ini);

	virtual bool	IsEmpty() const							{return false;}

	virtual bool	IsGlobalPrefs() const					{return true;}
	virtual bool	IsCategoryPrefs() const					{return false;}
	virtual bool	IsFilePrefs() const						{return false;}



	CArray<CTag*, CTag*> taglist;

private:
	void ClearTags();
};

///////////////////////////////////////////////////////////////////////
// CPartPreferences
//

class CPartPreferences
{
public:
	CPartPreferences();
	~CPartPreferences();

	void	Save(CFileDataIO* file);
	bool	Load(CFileDataIO* file);
	void	Save(CIni& ini);
	bool	Load(CIni& ini);

	virtual bool	IsEmpty() const					{return false;}

	virtual bool	IsGlobalPrefs() const			{return true;}
	virtual bool	IsCategoryPrefs() const			{return false;}
	virtual bool	IsFilePrefs() const				{return false;}



	virtual void	CheckTweaks();
	virtual void	ResetTweaks() {ASSERT(0);}

protected:
	friend class CPPgNeo;
	friend class CPPgSources;
	friend class CPPgSourceStorage;
	friend class CPPgLancast;
	friend class CSharedFilesCtrl;


	CArray<CTag*, CTag*> taglist;

private:
	void ClearTags();
};



///////////////////////////////////////////////////////////////////////
// CKnownPreferencesEx
//

class CKnownPreferencesEx : public CKnownPreferences
{
public:
	CKnownPreferencesEx(EFilePrefsLevel Level);

	friend class CPreferences;
	friend class CKnownFileList;
	friend class CKnownFile;
	friend class CPartFile;

	virtual	void	SetParent(CKnownFile* File)	{KnownFile = File;}
	virtual	void	SetPrefs(CKnownPreferences* Prefs)	{KnownPrefs = Prefs;}

	virtual bool	IsEmpty() const;



	virtual void	ResetTweaks();

protected:
	CKnownPreferences* KnownPrefs;
	CKnownFile* KnownFile;
	EFilePrefsLevel m_Level;
};


///////////////////////////////////////////////////////////////////////
// CPartPreferencesEx
//

class CPartPreferencesEx : public CPartPreferences
{
public:
	CPartPreferencesEx(EFilePrefsLevel Level);

	friend class CPreferences;
	friend class CDownloadQueue;
	friend class CKnownFile;
	friend class CPartFile;

	virtual	void	SetParent(CPartFile* File)	{PartFile = File;}
	virtual	void	SetPrefs(CPartPreferences* Prefs)	{PartPrefs = Prefs;}

	virtual bool	IsEmpty() const;


	virtual bool	IsGlobalPrefs() const	{return false;}
	virtual bool	IsCategoryPrefs() const	{return m_Level == CFP_CATEGORY;}
	virtual bool	IsFilePrefs() const		{return m_Level == CFP_FILE;}

	virtual void	ResetTweaks();

protected:
	CPartPreferences* PartPrefs;
	CPartFile* PartFile;
	EFilePrefsLevel m_Level;
};

///////////////////////////////////////////////////////////////////////////////////////
// Helpers
//

// Helper Functions
int GetRightVal (int &mode, int def, int max, int val1, int val2, int val3 = 0);
CString EncodeFPValue(int Value);
int DecodeFPValue(CString Text, int Default);
void CheckFPValue(int val, int def, bool glb, bool cat);
bool CheckModes(int &val, int &mod);

// tag implements
#define IMPLEMENT_FP_B_SET(val,opcode) \
	if (val != FCFG_DEF){ \
		CTag tag(opcode, (uint32)val); \
		tag.WriteNewEd2kTag(file); \
		uTagCount++; \
	}

#define IMPLEMENT_FP_B_GET(val,opcode) \
			case opcode:{ \
                ASSERT( newtag->IsInt() ); \
                val = newtag->GetInt(); \
                delete newtag; \
                break; \
            }

// Ini implements
#define IMPLEMENT_FP_I_SET(val,entry) \
	if(val == FCFG_DEF) \
		ini.DeleteKey(entry); \
	else \
		ini.WriteString(entry, EncodeFPValue(val)); 

#define IMPLEMENT_FP_I_GET(val,entry,def) \
	val = DecodeFPValue(ini.GetString(entry, _T("")), IsGlobalPrefs() ? def : FCFG_DEF); 
#define IMPLEMENT_FP_I_GET2(val,entry,def,mod,def_mod) \
	val = DecodeFPValue(ini.GetString(entry, _T("")), IsGlobalPrefs() ? GetRightVal(mod, def_mod, 2, DEF_##def##_1, DEF_##def##_2) : FCFG_DEF); 
#define IMPLEMENT_FP_I_GET3(val,entry,def,mod,def_mod) \
	val = DecodeFPValue(ini.GetString(entry, _T("")), IsGlobalPrefs() ? GetRightVal(mod, def_mod, 3, DEF_##def##_1, DEF_##def##_2, DEF_##def##_3) : FCFG_DEF); 

// check implements
#define IMPLEMENT_FP_CHK_VAL(val,def) \
	if(val > FCFG_BASE) \
		CheckFPValue(val,DEF_##def,IsGlobalPrefs(),IsCategoryPrefs()); \
	else \
		MinMax(&val,MIN_##def,MAX_##def);

#define IMPLEMENT_FP_CHK_VAL2(val,def,mod) \
	if(CheckModes(val,mod)) \
	{ \
		if(val > FCFG_BASE) \
			CheckFPValue(val,GetRightVal(mod, 0, 2, DEF_##def##_1, DEF_##def##_2),IsGlobalPrefs(),IsCategoryPrefs()); \
		else \
			MinMax(&val,GetRightVal(mod, 0, 2, MIN_##def##_1, MIN_##def##_2),GetRightVal(mod, 0, 3, MAX_##def##_1, MAX_##def##_2)); \
	}

#define IMPLEMENT_FP_CHK_VAL3(val,def,mod) \
	if(CheckModes(val,mod)) \
	{ \
		if(val > FCFG_BASE) \
			CheckFPValue(val,GetRightVal(mod, 0, 3, DEF_##def##_1, DEF_##def##_2, DEF_##def##_3),IsGlobalPrefs(),IsCategoryPrefs()); \
		else \
			MinMax(&val,GetRightVal(mod, 0, 3, MIN_##def##_1, MIN_##def##_2, MIN_##def##_3),GetRightVal(mod, 0, 3, MAX_##def##_1, MAX_##def##_2, MIN_##def##_3)); \
	}

#define IMPLEMENT_FP_CHK_FLAG(val,def,mod) \
	if(val > mod && IsGlobalPrefs()) \
		val = def; \
	if(val > mod+2 && IsFilePrefs()) \
		val = FCFG_DEF; \
	if(val > mod+1 && IsCategoryPrefs()) \
		val = FCFG_DEF;


// Function implements
#define IMPLEMENT_CFPEX(cls, var, fx, pref) \
int cls::fx() const { \
	if(var == FCFG_GLB) \
		return NeoPrefs.pref.fx(); \
	if(var == FCFG_DEF) \
		return pref->fx(); \
	return var; \
}

#define ASSERT_VAL(val) ASSERT(val < FCFG_BASE || val == FCFG_AUT); // no other values are valid

// NEO: FCFG END <-- Xanatos --