/* This file is part of cardwords
   (c) 1998 1999 Tobias Peters
   see file COPYING for the copyright terms.
   
   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

// cardwords_char.hh

#ifndef CARDWORDS_CHAR_HH
#define CARDWORDS_CHAR_HH

#include <assert.h>
#include "cardwords_iostream.hh"
#include <string>

#ifndef CHAR_SET_LENGTH
#define CHAR_SET_LENGTH 256
#endif

class CardWords_Char {
public:
  // the default copy constructor is ok
  // CardWords_Char (const CardWords_Char &);

  CardWords_Char (unsigned char = 0);
  CardWords_Char (char);
  
  // the default copy-assignment-operator is ok
  // CardWords_Char & operator= (const CardWords_Char &);

  CardWords_Char &
  operator= (unsigned char);
  CardWords_Char &
  operator= (char c);

  operator char() const;

  // defining a CardWords_Char means: give a set(string!) of Machine_Chars
  // that are represented by the same CardWords_Char (e.g. "Hh")
  static CardWords_Char
  define ( const string & );

  // read these definition strings from a file:
  static void
  define_from_file (const string & filename);

  static void define_from_stream (istream &);
  static void write_definitions_to_stream (ostream &);
  
  // How many different CardWords_Chars have been defined now?
  // (After calling this method, no new CardWords_Char can be defined)
  static size_t noOfChars (void);

  // Discard all defined CardWords_Chars:
  static void reset(void);
  
  bool
  operator < (const CardWords_Char&) const;
  bool
  operator > (const CardWords_Char&) const;
  bool
  operator == (const CardWords_Char&) const;
  bool
  operator != (const CardWords_Char&) const;
  int
  compare (const CardWords_Char&) const;

  // Inkrement und dekrement-Operatoren:
  CardWords_Char &
  operator ++ ();
  CardWords_Char &
  operator -- ();
  CardWords_Char
  operator ++ (int);
  CardWords_Char
  operator -- (int);
  
private:
  typedef unsigned char CardWords_CharNumber;

  CardWords_CharNumber cardwordsCharNumber;

  // cardwordsCharNumbers[some_unsigned_char_from_user_charset]
  //  == internal number that specifies the CardWords_Char that has the
  //  same meaning as the char in the index.
  static CardWords_CharNumber cardwordsCharNumbers[CHAR_SET_LENGTH];

  // machineChars[internal_number]
  //   == *one* of the machinechars that are mapped to this internal_number
  //   by cardwordsCharNumbers[]
  static unsigned char        machineChars [CHAR_SET_LENGTH];

  static CardWords_CharNumber nextFreeNumber;
  static bool                 definitionPossible;
public:
  static CardWords_Char        blanko;
public: // why not public?
  size_t internal_no(void) const {return cardwordsCharNumber;}

  static CardWords_Char get_cardwords_char_with_internal_no(unsigned char no)
    {return machineChars[no];}
};

inline
CardWords_Char::CardWords_Char (unsigned char uc = 0)
{
  cardwordsCharNumber = cardwordsCharNumbers[uc];
}
inline
CardWords_Char::CardWords_Char (char c)
{
  cardwordsCharNumber = cardwordsCharNumbers[static_cast<unsigned char>(c)];
}

inline
CardWords_Char &
CardWords_Char::operator= (unsigned char uc)
{
  cardwordsCharNumber = cardwordsCharNumbers[uc];
  return *this;
}
inline
CardWords_Char &
CardWords_Char::operator= (char c)
{
  return *this = static_cast<unsigned char>(c);
}

inline
CardWords_Char::operator char() const
{
  return machineChars [cardwordsCharNumber];
}

inline ostream &
operator << (ostream &os, const CardWords_Char &kc)
{
  return os << static_cast<char>(kc);
}

inline istream &
operator >> (istream &is, CardWords_Char &kc)
{
  bool skipped_ws = (is.flags() & ios::skipws);
  if (skipped_ws) {
    is.unsetf(ios::skipws);
  }
  char mc;
  is >> mc;
  kc = mc;
  if (skipped_ws) {
    is.setf(ios::skipws);
  }
  return is;
}

inline bool
CardWords_Char::operator < (const CardWords_Char &other) const
{
  return cardwordsCharNumber < other.cardwordsCharNumber;
}

inline bool
CardWords_Char::operator > (const CardWords_Char &other) const
{
  return cardwordsCharNumber > other.cardwordsCharNumber;
}

inline bool
CardWords_Char::operator == (const CardWords_Char &other) const
{
  return cardwordsCharNumber == other.cardwordsCharNumber;
}

inline bool
CardWords_Char::operator != (const CardWords_Char &other) const
{
  return cardwordsCharNumber != other.cardwordsCharNumber;
}

inline int
CardWords_Char::compare (const CardWords_Char & other) const
{
  return (*this == other) ? 0 : (*this < other) ? -1 : 1;
}

// Inkrement und dekrement-Operatoren:
inline
CardWords_Char &
CardWords_Char::operator ++ ()
{
  if (++cardwordsCharNumber >= nextFreeNumber) {
    cardwordsCharNumber = 0;
  }
  return *this;
}

inline
CardWords_Char &
CardWords_Char::operator -- ()
{
  if (cardwordsCharNumber-- == 0) {
    if (nextFreeNumber > 0) {
      cardwordsCharNumber = nextFreeNumber - 1;
    }
    else {
      cardwordsCharNumber = 0;
    }
  }
  return *this;
}

inline
CardWords_Char
CardWords_Char::operator ++ (int)
{
  CardWords_Char temp = *this;
  ++(*this);
  return temp;
}
inline
CardWords_Char
CardWords_Char::operator -- (int)
{
  CardWords_Char temp = *this;
  --(*this);
  return temp;
}

#endif
