/***************************************************************************
 *   Copyright (C) 2007 Nicolas Hadacek <hadacek@kde.org>                  *
 *                                                                         *
 *   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.                                   *
 ***************************************************************************/
#ifndef KEY_ENUM_H
#define KEY_ENUM_H

#include <tqdatastream.h>

#include "misc.h"
#include "common/global/global.h"

class GenericEnum
{
public:
  GenericEnum(uint value) : _value(value) {}
  bool operator ==(GenericEnum e) const { return _value==e._value; }
  bool operator !=(GenericEnum e) const { return _value!=e._value; }
  bool operator <(GenericEnum e) const { return _value<e._value; }
  bool operator <=(GenericEnum e) const { return _value<=e._value; }
  bool operator >(GenericEnum e) const { return _value>e._value; }
  bool operator >=(GenericEnum e) const { return _value>=e._value; }
  GenericEnum &operator ++() { _value++; return *this; }

protected:
  uint _value;

private:
  friend TQDataStream &operator >>(TQDataStream &s, GenericEnum &e);
  friend TQDataStream &operator <<(TQDataStream &s, const GenericEnum &e);
};

inline TQDataStream &operator <<(TQDataStream &s, const GenericEnum &e)
{
  s << e._value;
  return s;
}
inline TQDataStream &operator >>(TQDataStream &s, GenericEnum &e)
{
  s >> e._value;
  return s;
}

#define BEGIN_DECLARE_ENUM(Enum) \
class Enum : public GenericEnum \
{ \
public: \
  enum Type {

#define DECLARE_DATA \
public: \
  static Type fromKey(const TQString &key) { \
    for (uint i=0; i<Nb_Types; i++) \
      if ( key==DATA[i].key ) return Type(i); \
    return Type(Nb_Types); \
  } \
  const Data &data() const { \
    CRASH_ASSERT( _value!=Nb_Types ); \
    return DATA[_value]; \
  } \
  const char *key() const { \
    if ( _value==Nb_Types ) return 0; \
    Q_ASSERT(DATA[_value].key); \
    return DATA[_value].key; \
  } \
  TQString label() const { \
    CRASH_ASSERT( _value!=Nb_Types ); \
    Q_ASSERT(DATA[_value].label); \
    return i18n(DATA[_value].label); \
  } \
  private: \
    static const Data DATA[Nb_Types]; \

#define DECLARE_ENUM_CLASS(Enum) \
public: \
  Enum(Type value = Type(0)) : GenericEnum(value) { Q_ASSERT( value>=0 && value<=Type(Nb_Types)); } \
  Type type() const { return Type(_value); } \
};

#define END_DECLARE_ENUM(Enum, EnumData) \
    , Nb_Types \
  }; \
  typedef EnumData Data; \
  DECLARE_DATA \
  DECLARE_ENUM_CLASS(Enum) \

#define END_DECLARE_ENUM_STD(Enum) \
    , Nb_Types \
  }; \
  struct Data { \
    const char *key, *label; \
  }; \
  DECLARE_DATA \
  DECLARE_ENUM_CLASS(Enum)

#define END_DECLARE_ENUM_NO_DATA(Enum) \
    , Nb_Types \
  }; \
  DECLARE_ENUM_CLASS(Enum)

#define FOR_EACH(Enum, e) for(Enum e; e<Enum::Type(Enum::Nb_Types); ++e)

#endif
