/**
 * @file
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 *
 * The iWear Framework 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 as in version 2 of the License.

 * 
 * The iWear Framework 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
 * The iWear Framework; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef __IWEAR_HASHBASE_H
#define __IWEAR_HASHBASE_H

#ifndef __IWEAR_EXCEPTIONS_H
#include <iwear/exceptions.h>
#endif

#include <iwear/uid.h>

namespace iwear
{

class HashBase
{
private:
protected:
public:
    HashBase( );
    virtual ~HashBase( );

    virtual string asHex( void ) const = 0;
    virtual const unsigned char * theHash( void ) const = 0;
    virtual size_t getHashsize( void ) const = 0;

    virtual int Reset( void ) = 0;

    virtual int Update( const string& str ) = 0;
    virtual int Update( const void* data, unsigned long len ) = 0;

    virtual int From( const string& str ) = 0;
    virtual int From( const unsigned char* d, unsigned long n ) = 0;

    virtual int Final( void ) = 0;
};

const char * const hash_formatcodes[] =
{
    "%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X", // 16
    "%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X", // 20
};

template<size_t hashsize>
class HashCode
{
private:
protected:
    unsigned char hashcode[hashsize];
    const char * get_formatcode( void ) const;
public:

    HashCode();
    string asHex( void ) const;
    inline size_t getHashsize( void ) const { return hashsize; }

    inline unsigned char * code( void ) { return hashcode; }
    inline unsigned const char * code( void ) const { return hashcode; }

    inline bool operator!=( const HashCode<hashsize>& oh ) 
	    { return memcmp(reinterpret_cast<const char *>(hashcode),
		    reinterpret_cast<const char *>(oh.hashcode),hashsize); }
    inline bool operator==( const HashCode<hashsize>& oh ) { return ! operator!=(oh); }
    operator iwear::uid ( ) const;
};
template<size_t hashsize>
HashCode<hashsize>::operator iwear::uid ( ) const
{
    iwear::uid u;
    memcpy((void*)&u.the_id,code(),(hashsize<16) ? hashsize : 16 );
    return u;
}

template<size_t hashsize>
HashCode<hashsize>::HashCode( )
{
    memset(hashcode,0,hashsize);
}

template<size_t hashsize>
inline const char * HashCode<hashsize>::get_formatcode( void ) const/*{{{*/
{
    switch(hashsize)
    {
	case 16:
	    return hash_formatcodes[0];
	case 20:
	    return hash_formatcodes[1];
	default:
	    THROW( iwlogic_error,("Invalid Hash Size"));
    }
}/*}}}*/

template<size_t hashsize>
string HashCode<hashsize>::asHex( void ) const/*{{{*/
{
    char hex[hashsize*2 + 1];
    switch(hashsize)
    {
	case 16:
	    sprintf(hex,get_formatcode(),
	    hashcode[0], hashcode[1], hashcode[2], hashcode[3], hashcode[4], hashcode[5], hashcode[6], 
	    hashcode[7], hashcode[8], hashcode[9], hashcode[10], hashcode[11], hashcode[12], hashcode[13], 
	    hashcode[14], hashcode[15]);
	    break;
	case 20:
	    sprintf(hex,get_formatcode(),
	    hashcode[0], hashcode[1], hashcode[2], hashcode[3], hashcode[4], hashcode[5], hashcode[6], 
	    hashcode[7], hashcode[8], hashcode[9], hashcode[10], hashcode[11], hashcode[12], hashcode[13], 
	    hashcode[14], hashcode[15], hashcode[16], hashcode[17], hashcode[18], hashcode[19]);
	    break;
	default:
	    THROW(iwlogic_error,("Invalid Hash Size"));
    }
    return hex;
}/*}}}*/

typedef HashCode<16> MD2HashCode;
typedef HashCode<16> MD4HashCode;
typedef HashCode<16> MD5HashCode;
typedef HashCode<20> SHAHashCode;
typedef HashCode<20> SHA1HashCode;
typedef HashCode<16> MDC2HashCode;
typedef HashCode<20> RipeMD160HashCode;

}

#endif
