/*
 * 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 Entry_hh
#define Entry_hh

#include "config.h"
#if defined(HAVE_EXT_HASH_MAP)
#include <ext/hash_map>
using namespace __gnu_cxx;
#else
#if defined(HAVE_HASH_MAP)
#include <hash_map>
#else
#error Cannot find hash_map header !
#endif
#endif

#include <vector>

#include "Attribute.hh"


namespace Cryptonit 
{

   /** This class represents entry's attribute list.
    *  Each attributes are designated by a name and a pointer
    *  to a Attribute object, which contains
    *  the values list.
    */
   class Entry
   {

private:

    // Hash function for string class
    struct Entry_hash_str
    {
	inline size_t __stl_hash_string(const char* __s) const
	{
	    unsigned long __h = 0; 
	    for ( ; *__s; ++__s)
		__h = 5*__h + *__s;
	    
	    return size_t(__h);
	}
	
	size_t operator()(const std::string s1) const
	{
	    return  __stl_hash_string( s1.c_str() );
	}
    };
    

    struct Entry_eqstr
    {
	bool operator()(const std::string s1, const std::string s2) const {
	    return s1 == s2;
	}
    };

    hash_map<const std::string, Attribute*, Entry_hash_str, Entry_eqstr>  attributeList;



public:

    /** Instensiate a new entry.
     */
    Entry( );

    /** Copy constructor.
     */
    Entry( const Entry& entry );

    /** Copy constructor.
     */
    Entry( Entry* entry );

    /** Instensiate a new entry and add a new attribute.
     *
     *  @param name : attribute name
     */
    Entry( const std::string  name );

    /** Instensiate a new entry and add a new attribute with its value.
     *
     *  @param name : attribute name
     *  @param val : attribute value
     */
    Entry( const std::string  name, const std::string& val );

    /** Instensiate a new entry and add a new attribute with its value.
     *
     *  @param name : attribute name
     *  @param val : attribute value
     *  @param t : attribute type (AttributeType)
     */
    Entry( const std::string  name, const std::string& val, AttributeType t );

    /** Instensiate a new entry and add a new attribute with its value.
     *  The value length has to be specified. Use this method if you
     *  want to add binary values.
     *
     *  @param name : attribute name
     *  @param val : attribute value
     *  @param len : attribute value length
     *  @param t : attribute type (AttributeType)
     */
    Entry( const std::string  name, const char* val, unsigned long len, AttributeType t );


    /** Destroy a Entry object, erasing all data contained
     *  in the attribute list.
     */
    virtual ~Entry( );
  


    /** Returns a pointer on a specified attribute.
     *
     *  @param name : attribute name
     */
    virtual Attribute* getAttribute( const std::string name );

    /** Returns a vector containing the attribute values.
     *
     *  @param name : attribute name
     */
    virtual std::vector<std::string> getAttributeValues( const std::string name );

    /** Returns the first value of the specified attribute.
     *
     *  @param name : attribute name
     */
    virtual std::string getAttributeFirstValue( const std::string name );

    /** Returns a reference on the first value of the specified attribute.
     *  If the attribute does not exist, 'val' is untouched.
     *
     *  @param name : attribute name
     *  @param val : a reference on the attribute value
     */
    virtual void getAttributeFirstValue( const std::string name, std::string& val );

    /** Returns the last value of the specified attribute.
     *
     *  @param name : attribute name
     */
    virtual std::string getAttributeLastValue( const std::string name );

    /** Returns a reference on the last value of the specified attribute.
     *  If the attribute does not exist, 'val' is untouched.
     *
     *  @param name : attribute name
     *  @param val : a reference on the attribute value
     */
    virtual void getAttributeLastValue( const std::string name, std::string& val );


    /** Appends a value to the attribute's list. If the attribute does not exist
     *  it will be automatically created.
     *
     *  @param name : attribute name
     *  @param val : a reference on the attribute value
     */
    virtual bool appendAttributeValue( const std::string name, const std::string &val );


    /** Appends a value to the attribute's list. If the attribute does not exist
     *  it will be automatically created.
     *
     *  @param name : attribute name
     *  @param val : a reference on the attribute value
     *  @param t : attribute value's type
     */
    virtual bool appendAttributeValue( const std::string name, const std::string &val, const AttributeType t );


    /** Appends a value to the attribute's list. If the attribute does not exist
     *  it will be automatically created.
     *
     *  @param name : attribute name
     *  @param val : a reference on the attribute value
     *  @param len : attribute value's length
     *  @param t : attribute value's type
     */
    virtual bool appendAttributeValue( const std::string name, const char* val, const unsigned long len, const AttributeType t );


    // Modifie la valeur d'un attribut, l'ajoute si il n'existe pas
    // Retourne true si l'élément existe et qu'il est du même type que 'val'
    //virtual bool SetAttributeValue( const std::string name, const std::string &val );


    // Retourne la valeur de l'attribut 'name'
    // Retourne true si l'élément existe et qu'il est du même type que 'val'
    // La valeur de l'attribut est copié, il doit être libéré "manuellement"
    //virtual bool GetAttributeValue( const std::string name, std::string &val ) const;

    
    /** Erases the specified attribute.
     *  Returns true if the operation succeed.
     *
     *  @param name : attribute name
     */
    virtual bool erase( const std::string name );


    /** Erases all attributes.
     *  Returns true if the operation succeed.
     */
    virtual bool clear();


    // Supprime l'attribut 'name' de valeur 'value'
    // Retourne true si il a été supprimé
    //virtual bool DeleteAttribute( const std::string name, std::string val);


    /** Appends a previously created attribute in the attribute list.
     *  Returns true if the operation succeed.
     *
     *  @param name : attribute name
     *  @param attribute : a pointer on a previously created Attribute
     */
    virtual bool append( const std::string name, Attribute* attribute );


    /** Returns the total number of attributes.
     */
    virtual unsigned int getNbAttribute() const;

    
    /** Fill a list of given attributes with current values of this object.
     *
     *  @param entry : list of wanted attributes
     */
    virtual bool fillEntry( class Entry& entry );


    // Recherches
    //virtual Attribute& FindAttribute( const std::string name ) const;
    virtual bool findExpression( const std::string expr ) const { return false; }
    virtual Entry* findNext() const { return NULL; }



    class iterator;
    friend class iterator;

    /** Nested class for iterating inside the attributeList.
     */
    class iterator {

	/** Reference on the current Entry object.
	 */
	Entry& ds;

	/** Current iterator on the attributeList hash map.
	 */
	hash_map<const std::string, Attribute*, Entry_hash_str, Entry_eqstr>::iterator itr;

    public:

	/** Returns the first element of the pair, aka attribute name.
	 *
	 *  @return Attribute name.
	 */
	const std::string first() { return itr->first; }

	/** Returns the second element of the pair, a pointer on the Attribute.
	 *
	 *  @return a pointer on the Attribute.
	 */
	Attribute* second() { return itr->second; }

	/** Creates the iterator.
	 */
	iterator(class Entry& d) : ds(d), itr( ds.attributeList.begin() ) {}

	/** Creates the "end sentinel" iterator
	 */
	iterator(class Entry& d, bool) : ds(d), itr( ds.attributeList.end() ) {}

	/** Returns the current value, use it for iterator operation.
	 *  You'd better use first() and second() method if you want to access the iterator content.
	 */
	hash_map<const std::string, Attribute*, Entry_hash_str, Entry_eqstr>::iterator 
	current() const { return itr; }

	/** Prefix incrementation.
	 */
	hash_map<const std::string, Attribute*, Entry_hash_str, Entry_eqstr>::iterator 
	operator++() { return ++itr; }

	/** Postfix incrementation.
	 */
	hash_map<const std::string, Attribute*, Entry_hash_str, Entry_eqstr>::iterator 
	operator++( int ) { return itr++; }

	/** Comparaison equality operator.
	 */
	bool operator==(const iterator& rv) const {
	    return itr == rv.itr;
	}

	/** Comparaison difference operator.
	 */
	bool operator!=(const iterator& rv) const {
	    return itr != rv.itr;
	}
	// 	friend ostream& operator<<(ostream& os, const iterator& it) {
	// 	    return os << it.current();
	// 	}

    };
    
    /** Returns an iterator on the begin of the attributeList hash map.
     */
    iterator begin() { return iterator(*this); }

    /** Returns an iterator on the end of the attributeList hash map.
     */
    iterator end() { return iterator(*this, true);}


};

} // Namespace
#endif
