/*
 * The Cryptonit security software suite is developped by IDEALX
 * Cryptonit Team (http://IDEALX.org/ and http://cryptonit.org).
 *
 * Copyright 2003-2006 IDEALX
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 as published by the Free Software Foundation.
 * 
 * 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 St, Fifth Floor, Boston, MA
 * 02110-1301, USA. 
 *
 * In addition, as two special exceptions:
 *
 * 1) IDEALX S.A.S gives permission to:
 *  * link the code of portions of his program with the OpenSSL library under
 *    certain conditions described in each source file
 *  * distribute linked combinations including the two, with respect to the
 *    OpenSSL license and with the GPL
 *
 * You must obey the GNU General Public License in all respects for all of the
 * code used other than OpenSSL. If you modify file(s) with this exception,
 * you may extend this exception to your version of the file(s), but you are
 * not obligated to do so. If you do not wish to do so, delete this exception
 * statement from your version, in all files (this very one along with all
 * source files).

 * 2) IDEALX S.A.S acknowledges that portions of his sourcecode uses (by the
 * way of headers inclusion) some work published by 'RSA Security Inc.'. Those
 * portions are "derived from the RSA Security Inc. PKCS #11Cryptographic
 * Token Interface (Cryptoki)" as described in each individual source file.
 */

#ifndef ConfigDatabase_hh
#define ConfigDatabase_hh

#include "DirectoryService.hh"

#include <openssl/conf.h>

namespace Cryptonit
{

/* Configuration key names */
#define NB_ENTRY               "count"
#define ENTRY_NAME             "name"
#define ENTRY_BASE             "entry"

#define NB_FIELD               "count"
#define FIELD_NAME             "name"
#define FIELD_BASE             "field"
#define ENTRY_FIELD_SEPARATOR  "_"

#define NB_VALUE               "count"
#define VALUE_BASE             "value"
#define VALUE_TYPE_BASE        "type"

#define INTEGER_TYPE           "INTEGER"
#define LONG_TYPE              "LONG"
#define FLOAT_TYPE             "FLOAT"
#define STRING_TYPE            "STRING"
#define BINARY_TYPE            "BINARY"
#define BASE64_TYPE            "BASE64"



    /** OpenSSL NCONF backend.
     *  This backend uses the OpenSSL configuration parsing engine.
     *  The followed schema is understood by this backend:
     *
     *
     * # Global parameters
     * 
     * # Total number of entries
     * count=2
     * 
     * 
     * [entry1]
     * # Entry name
     * name=myentry
     * # Total number of fields
     * count=3
     * 
     * [entry1_field1]
     * # Field name
     * name=mail
     * # Number of values in this field
     * count=1
     * # Value type
     * type1=string
     * # Value data
     * value1=user@domain.com
     * 
     * [entry1_field2]
     * name=userCertificate
     * count=1
     * type1=binary
     * value1=...
     * 
     * [entry1_field3]
     * name=multi
     * count=2
     * type1=string
     * value1=toto
     * type2=string
     * value2=titi
     * 
     * 
     * [entry2]
     * ...
     */
    class ConfigDatabase: public DirectoryService
    {
    private:

	/** Pointer on the current configuration.
	 *  This backend can handle only one configuration
	 *  in the same time.
	 */
	CONF* current_conf;


	/** Current configuration filename.
	 */
	std::string current_filename;


	/** Line number where the error occured.
	 */
	long current_error_line;


	/** Initialize a new OpenSSL NCONF engine only if conf == NULL.
	 *  Returns a pointer on the new CONF, NULL if the operation failed.
	 *
	 *  @param filename : configuration filename
	 *  @param method : NCONF method to be used, at this time you may don't
	 *                  need it. (OPTIONAL)
	 */
	CONF* initOpenSSLNCONF( const std::string filename, const std::string method="" );


	/** Adds all fields of a specified entry with their values into the hash table.
	 *  Parses the content of an entry section.
	 *
	 *  @param section_name : the section name to be parsed, eg "entry1"
	 *  @param entry_name : the entry name given by the "name=" key
	 */
	bool addEntry( const std::string section_name, const std::string entry_name );


	/** Adds all values of a specified field with their values into the hash table.
	 *  Parses the content of a field section.
	 *
	 *  @param section_name : the section name to be parsed, eg "entry1_field1"
	 *  @param entry_name : the entry name.
	 */
	bool addField( const std::string section_name, const std::string entry_name );


	/** Adds the value numbered 'value_nb' into the internals hash maps.
	 *
	 *  @param entry_name : the entry name.
	 *  @param field_name : the field name given by the "name=".
	 *  @param value_nb : the value's number to be added.
	 */
	bool addValue( const std::string entry_name, const std::string field_name, unsigned int value_nb );


    public:

	/** Instantiates a new OpenSSL NCONF backend. And sets default NCONF method.
	 *  You need to parse the configuration file with the read() method.
	 */
	ConfigDatabase();


	/** Instantiates a new OpenSSL NCONF backend. And sets default NCONF method.
	 *  Parses the given URI, and read() the given filename. The URI can be a 
	 *  simple filename.
	 *  This constructor is used by the DirectoryService::factory(URI), with the
	 *  preparsed URI.
	 *
	 *  @param uri : URI
	 */
	ConfigDatabase( const std::string uri );


	~ConfigDatabase();


	/** Parses a configuration file, and copy all of its data into memory.
	 *
	 *  @param params[0] : configuration filename
	 *  @param params[1] : NCONF method (optional)
	 */
	bool read( const std::string params[] );


	/** Saves internal hash maps datas into a file. If the filename is not
	 *  specified the datas are stored into the current configuration filename,
	 *  overwriting its content, without warning.
	 *
	 *  @param params[O] : destination filename
	 */
	bool commit( const std::string params[] );

    };

} // Namespace
#endif
