// distribution boxbackup-0.11.1 (svn version: 2821_2827)
// Box Backup, http://www.boxbackup.org/
// 
// Copyright (c) 2003-2010, Ben Summers and contributors.
// All rights reserved.
// 
// Note that this project uses mixed licensing. Any file with this license
// attached, or where the code LICENSE-DUAL appears on the first line, falls
// under this license. See the file COPYING.txt for more information.
// 
// This file is dual licensed. You may use and distribute it providing that you
// comply EITHER with the terms of the BSD license, OR the GPL license. It is
// not necessary to comply with both licenses, only one.
// 
// The BSD license option follows:
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//  
// 3. Neither the name of the Box Backup nor the names of its contributors may
//    be used to endorse or promote products derived from this software without
//    specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// 
// [http://en.wikipedia.org/wiki/BSD_licenses#3-clause_license_.28.22New_BSD_License.22.29]
// 
// The GPL license option follows:
// 
// 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
// 
// [http://www.gnu.org/licenses/old-licenses/gpl-2.0.html#SEC4]
// --------------------------------------------------------------------------
//
// File
//		Name:    Configuration
//		Purpose: Reading configuration files
//		Created: 2003/07/23
//
// --------------------------------------------------------------------------

#ifndef CONFIGURATION__H
#define CONFIGURATION__H

#include <map>
#include <list>
#include <vector>
#include <string>
#include <memory>

// For defining tests
enum
{
	ConfigTest_LastEntry = 1,
	ConfigTest_Exists = 2,
	ConfigTest_IsInt = 4,
	ConfigTest_IsUint32 = 8, 
	ConfigTest_MultiValueAllowed = 16,
	ConfigTest_IsBool = 32
};

class ConfigurationVerifyKey
{
public:
	typedef enum
	{
		NoDefaultValue = 1
	} NoDefaultValue_t;

	ConfigurationVerifyKey(std::string name, int flags,
		void *testFunction = NULL);
	// to allow passing ConfigurationVerifyKey::NoDefaultValue
	// for default ListenAddresses
	ConfigurationVerifyKey(std::string name, int flags,
		NoDefaultValue_t t, void *testFunction = NULL);
	ConfigurationVerifyKey(std::string name, int flags,
		std::string defaultValue, void *testFunction = NULL);
	ConfigurationVerifyKey(std::string name, int flags,
		const char* defaultValue, void *testFunction = NULL);
	ConfigurationVerifyKey(std::string name, int flags,
		int defaultValue, void *testFunction = NULL);
	ConfigurationVerifyKey(std::string name, int flags,
		bool defaultValue, void *testFunction = NULL);
	const std::string& Name() const { return mName; }
	const std::string& DefaultValue() const { return mDefaultValue; }
	const bool HasDefaultValue() const { return mHasDefaultValue; }
	const int Flags() const { return mFlags; }
	const void* TestFunction() const { return mTestFunction; }
	ConfigurationVerifyKey(const ConfigurationVerifyKey& rToCopy);

private:
	ConfigurationVerifyKey& operator=(const ConfigurationVerifyKey&
		noAssign);

	std::string mName;         // "*" for all other keys (not implemented yet)
	std::string mDefaultValue; // default for when it's not present
	bool mHasDefaultValue;
	int mFlags;
	void *mTestFunction; // set to zero for now, will implement later
};

class ConfigurationVerify
{
public:
	std::string mName; // "*" for all other sub config names
	const ConfigurationVerify *mpSubConfigurations;
	const ConfigurationVerifyKey *mpKeys;
	int Tests;	
	void *TestFunction; // set to zero for now, will implement later
};

class FdGetLine;

// --------------------------------------------------------------------------
//
// Class
//		Name:    Configuration
//		Purpose: Loading, checking, and representing configuration files
//		Created: 2003/07/23
//
// --------------------------------------------------------------------------
class Configuration
{
public:
	Configuration(const std::string &rName);
	Configuration(const Configuration &rToCopy);
	~Configuration();
	
	enum
	{
		// The character to separate multi-values
		MultiValueSeparator = '\x01'
	};
	
	static std::auto_ptr<Configuration> LoadAndVerify(
		const std::string& rFilename,
		const ConfigurationVerify *pVerify,
		std::string &rErrorMsg);

	static std::auto_ptr<Configuration> Load(
		const std::string& rFilename,
		std::string &rErrorMsg)
	{ return LoadAndVerify(rFilename, 0, rErrorMsg); }
	
	bool KeyExists(const std::string& rKeyName) const;
	const std::string &GetKeyValue(const std::string& rKeyName) const;
	int GetKeyValueInt(const std::string& rKeyName) const;
	uint32_t GetKeyValueUint32(const std::string& rKeyName) const;
	bool GetKeyValueBool(const std::string& rKeyName) const;
	std::vector<std::string> GetKeyNames() const;
	
	bool SubConfigurationExists(const std::string& rSubName) const;
	const Configuration &GetSubConfiguration(const std::string& rSubName) const;
	Configuration &GetSubConfigurationEditable(const std::string& rSubName);
	std::vector<std::string> GetSubConfigurationNames() const;
	
	void AddKeyValue(const std::string& rKey, const std::string& rValue);
	void AddSubConfig(const std::string& rName, const Configuration& rSubConfig);
	
	bool Verify(const ConfigurationVerify &rVerify, std::string &rErrorMsg)
	{
		return Verify(rVerify, std::string(), rErrorMsg);
	}

private:	
	std::string mName;
	// Order of keys not preserved
	std::map<std::string, std::string> mKeys;
	// Order of sub blocks preserved
	typedef std::list<std::pair<std::string, Configuration> > SubConfigListType;
	SubConfigListType mSubConfigurations;
	
	static bool LoadInto(Configuration &rConfig, FdGetLine &rGetLine, std::string &rErrorMsg, bool RootLevel);
	bool Verify(const ConfigurationVerify &rVerify, const std::string &rLevel,
		std::string &rErrorMsg);
};

#endif // CONFIGURATION__H

