#ifndef _xbODREGISTRY_
#define _xbODREGISTRY_
/*<<<***************************************************************************
The MIT License (MIT)

Copyright(C) 2013 - 2015 Marc Mirti Mancinelli, Christophe Lardau and Philippe Pamart (xdcube.org)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
////////////////////////////////////////////////////////////////////////////////
#Title: xbODregistry
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<15/09/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#ifndef _xbVariant_
#	include "../../xbVariant.h"
#endif

#ifndef _xbENGINE_
#	include "../../xbEngine.h"
#endif

#ifndef _xbSTRING_
#	include "../../xbString.h"
#endif

enum xbODregRoot
{
	xbODregCurrentUser=0,
	xbODregCurrentConfig=1,
	xbODregClassesRoot=2,
	xbODregUsers=3,
	xbODregLocalMachine=4,
	xbODregDynData=5,
	xbODregPerformance=6
};

class xbODregKeyInfo;
class xbODregEnumKey;
class xbODregEnumValue;

class xbEXPORT xbODregKey
{
public:
	xbODregKey(const xbODregRoot mk,const xbString &keyname);
	xbODregKey(HKEY hKey, bool bRdOnly,const xbODregRoot mk,const xbString &keyname);
	xbODregKey(xbODregKey &parent,const xbString &keyname);
	xbODregKey(xbODregKey &key);
	xbODregKey();

	xbODregKey &operator=(const xbODregKey &key);

	void Init(const xbODregRoot mk,const xbString &keyname);
	void Init(xbODregKey &parent,const xbString &keyname);
	void Init(xbODregKey &key);
	
	bool	  DefaultValueExists() const;
	xbVariant GetDefaultValue() const;
	void	 SetDefaultValue(const xbVariant &val,bool bAltFrmt = false);
	xbPropertyRW(xbVariant,DefaultValue);
	
	bool	  ValueExists(const char *valname) const;
	xbVariant GetValue(const char *valname) const;
	void	  SetValue(const char *valname,const xbVariant &val,bool bAltFrmt = false);
	xbArrayPropertyRW(xbVariant,xbString,Value);

	bool		DeleteValue(const char *valname,xbOpMode opMode = xbOp_Optional);
	bool		DeleteDefaultValue(xbOpMode opMode = xbOp_Optional);
	bool		DeleteKey(bool bRecurse = false,xbOpMode opMode = xbOp_Optional);
	bool		DeleteKey(const char *keyname,bool bRecurse = false,xbOpMode opMode = xbOp_Optional);

	bool		Exists() const;
	xbODregKey	&CreateKey();
	xbString	GetName() const;
	xbPropertyR(xbString,Name);
	xbString	GetPath() const;
	xbPropertyR(xbString,Path);
	xbODregRoot	GetRoot() const;
	xbPropertyR(xbODregRoot,Root);

	void	Close();
	virtual ~xbODregKey();

	HKEY		getHKey(bool bCreate);

	bool SetFullPath(const xbString &str,xbOpMode opm =xbOp_Required);		//FromStr !!
	xbString GetFullPath() const;								//ToStr !!
	xbPropertyRW(xbString,FullPath);
protected:
	void Init(xbODregKeyInfo *pInfo,const xbString &keyname);
	friend			xbODregEnumKey;
	friend			xbODregEnumValue;
private:
	xbODregKeyInfo	*m_pInfo;
};

class xbEXPORT xbODregEnumKey
{
public:
	xbODregEnumKey(xbODregKey &key);
	void Init(xbODregKey &key);
	bool	Next(xbString *pKeyName);
	bool	Next(xbODregKey *pSubKey);
	bool	Next();
	void	Reset();
	void	Close();
	virtual ~xbODregEnumKey();
	void setPosition(ulong pos) {m_pos = pos;}
	ulong getPosition() const {return m_pos;}
protected:
	xbODregEnumKey(xbODregKeyInfo *pInfo);
	friend xbODregKeyInfo;
	DWORD			m_pos;
private:
	xbODregKeyInfo	*m_pInfo;
};

class xbEXPORT xbODregEnumValue
{
public:
	xbODregEnumValue(xbODregKey &key);
	void Init(xbODregKey &key);
	bool	Next(xbString *pValName);
	bool	Next(xbString *pValName,xbVariant *pvalue);
	bool	Next();
	void	Reset();
	void	Close();
	virtual ~xbODregEnumValue();
	void setPosition(ulong pos) {m_pos = pos;}
	ulong getPosition() const {return m_pos;}
protected:
	DWORD			m_pos;
private:
	xbODregKeyInfo	*m_pInfo;
};

class xbODregPath;
class xbEXPORT __declspec(uuid("{11CBDDB3-98E3-4931-B3D3-572420E72913}")) 
	xbODregEngine:public xbEngine
{
public:
	xbODregEngine(const char *pLabel,const xbEngines &engUsed = xbEngines())
		:xbEngine(xbEngineStart_Auto,pLabel,engUsed)
	{
	}
	virtual ~xbODregEngine()
	{
		Destroy();
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbODregEngine);
		return xbEngine::GetInterface(riid,ppInterf);
	}

	void GetPath(xbODregRoot root,xbODregRoot *pRoot,xbString *pStr) const;
	xbODregPath *GetRegPath(xbODregRoot root);
	bool GetRoot(const xbString &rootName,xbODregRoot *pRoot,xbOpMode opm =xbOp_Required);
	xbString GetRootName(xbODregRoot root);
	int Add(xbODregPath *pRegPath);
	void Remove(int id);

	virtual bool isLockedByMe() const {return m_sectData.IsLockedByMe();}
protected:
	virtual void onStart() {}
	virtual bool onStop(bool) {m_arrPath.Clear(); return true;}

	xbArray<xbODregPath*>	m_arrPath;

	mutable xbSectShare	m_sectData;
};

extern xbODregEngine	xbEXPORT g_xbODregEngine;

class xbEXPORT __declspec(uuid("{D40DFD5E-A423-40de-9D2E-AFAFCC8D293A}"))
	xbODregPath:public xbEngine
{
public:
	xbODregPath(const char *pName,const char *pLabel,xbODregRoot root,const char *pPath)
		:xbEngine(/*xbEngineStart_Auto*/ xbEngineStart_OnUse,pLabel,xbEngines(&g_xbODregEngine))
	{
		m_pName = pName;
		if (int(root) < 0)
			m_pRegPath = g_xbODregEngine.GetRegPath(root);
		else
			m_pRegPath = NULL;
		m_root = root;
		m_path = pPath;
		m_id = 0;
	}
	xbODregPath(const char *pName,const char *pLabel,xbODregPath *pRegPathRoot,const char *pPath)
		:xbEngine(/*xbEngineStart_Auto*/ xbEngineStart_OnUse,pLabel,xbEngines(&g_xbODregEngine,pRegPathRoot))
	{
		m_pName = pName;
		m_pRegPath = pRegPathRoot;
		m_root = xbODregCurrentUser;
		m_path = pPath;
		m_id = 0;
	}
	virtual ~xbODregPath()
	{
		Destroy();
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbODregPath);
		return xbEngine::GetInterface(riid,ppInterf);
	}
	void GetAbsPath(xbODregRoot *pRoot,xbString *pPath) const;
	xbString GetPath() const;
	void SetPath(const xbString &path);
	xbPropertyRW(xbString,Path);

	xbODregRoot	GetRoot() const;
	void SetRoot(xbODregRoot root);
	void SetRoot(xbODregPath *pRegPathRoot);
	xbPropertyRW(xbODregRoot,Root);

	xbString GetName() {CheckReady();return m_pName;}
	xbPropertyR(xbString,Name);

	operator xbODregRoot()
	{
		xbLock lckStart(this);
		return xbODregRoot(-m_id);
	};

	virtual bool isLockedByMe() const {return m_sectData.IsLockedByMe();}
	mutable xbSectShare	m_sectData;
protected:
	virtual void onStart() 
	{
		m_id = g_xbODregEngine.Add(this);
	}
	virtual bool onStop(bool) 
	{
		g_xbODregEngine.Remove(m_id);
		m_id = 0;
		return true;
	}

	friend xbODregEngine;

	int			m_id;
	xbODregPath	*m_pRegPath;
	xbODregRoot	m_root;
	xbString	m_path;

	const char	*m_pName;
};

//extern xbODregPath	xbEXPORT xbODregXdcMachine;
//extern xbODregPath	xbEXPORT xbODregXdcUser;

#endif
