/* This file is part of cardwords
   (c) 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_actionselection.cc

#include "cardwords_actionselection.hh"

// take_key_strike() returns an int.
// It returns 0 if everything went normal.
// It returns 1 if the user finished his request.
// It returns -1 if the user made an invalid key strike.
int
CardWords_ActionSelection::take_key_strike(char c)
{
  switch (input_state) {
  case TABLE_LOCATION_EXPECTED:
    if (c >= 'a' && c <= 'z') {
      // make it uppercase
      c += 'A' - 'a';
    }
    if (c == 'M' - 64
        || c == 'J' - 64) {
      // [Return] key pressed.
      return 1;
    }
    else if (c == '.') {
      // Make a trade from it
      user_wants_move = false;
      is_move = false;
      if (cards.size() > 0) {
	is_trade = true;
      }
      input_state = CARD_INPUT_MODE;
    }
    else if (c >= '0' && c <= '9') {
      // Digit first
      if ( static_cast<size_t>(c - '0')
	   > (use_digits_for_the_columns
	      ? table->get_width()
	      : table->get_height()
	      )
	   ) {
	// digit is too large
	return -1;
      }
      
      if (use_digits_for_the_columns) {
	move_direction = vertikal;
      }
      else {
	move_direction = horizontal;
      }
      user_digit_coordinate = c - '0';
      set_start_location_from_user_coordinates();
      user_wants_move = true;

      if ( user_digit_coordinate * 10
	   > (use_digits_for_the_columns
	      ? table->get_width()
	      : table->get_height()
	      )
	   ) {
	input_state = TABLE_LOCATION_NUMBER_GIVEN_CHAR_EXPECTED;
      }
      else {
	input_state = TABLE_LOCATION_NUMBER_BEGUN_MAYBE_NOT_FINISHED_YET;
      }

      move = cards;
      move.location = start_location;
      move.direction = move_direction;
      
      is_move = (move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;// maybe because start
      //                                     location not complete now.
    }
    else if (c >= 'A' && c <= 'Z') {
      // Char first:
      if ( size_t(c - 'A' + 1)
	   > (use_digits_for_the_columns
	      ? table->get_height()
	      : table->get_width()
	      )
	   ) {
	// Char is too large
	return -1;
      }
      if (use_digits_for_the_columns) {
	move_direction = horizontal;
      }
      else {
	move_direction = vertikal;
      }
      user_char_coordinate = c;
      set_start_location_from_user_coordinates();
      user_wants_move = true;

      input_state = TABLE_LOCATION_CHAR_GIVEN_NUMBER_EXPECTED;
      
      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;// maybe because start
      //                                     location not complete now.
    }
    else if (c == 27 ) {
      // escape
      input_state = CARD_INPUT_MODE;
    }
    else {
      // invalid request
      return -1;
    }
    break;
      
  case TABLE_LOCATION_CHAR_GIVEN_NUMBER_EXPECTED:
    if (c == '.') {
      // Make a trade from it
      user_wants_move = false;
      is_move = false;
      if (cards.size() > 0) {
	is_trade = true;
      }
      input_state = CARD_INPUT_MODE;
    }
    else if ( c == 27 ) {
      // escape table location mode
      input_state = CARD_INPUT_MODE;
    }
    else if (c >= '0' && c <= '9') {
      // Digit as expected
      if ( size_t(c - '0')
	   > (use_digits_for_the_columns
	      ? table->get_width()
	      : table->get_height()
	      )
	   ) {
	// digit is too large
	return -1;
      }

      user_digit_coordinate = c - '0';
      set_start_location_from_user_coordinates();
      user_wants_move = true;
      
      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;// maybe because start lo-
      // cation not complete now or because the user wants to delete a card.

      if ( user_digit_coordinate * 10
	   > (use_digits_for_the_columns
	      ? table->get_width()
	      : table->get_height()
	      )
	   ) {
	input_state = CARD_INPUT_MODE;
      }
      else {
	input_state = TABLE_LOCATION_CHAR_GIVEN_NUMBER_MAYBE_NOT_FINISHED_YET;
      }
    }
    else {
      // invalid request
      return -1;
    }
    break;
    
  case TABLE_LOCATION_CHAR_GIVEN_NUMBER_MAYBE_NOT_FINISHED_YET:
    if (c >= 'a' && c <= 'z') {
      // make it uppercase
      c += 'A' - 'a';
    }
    if (c == 'M' - 64 || c == 'J' - 64) {
      input_state = CARD_INPUT_MODE;
      return 1;
    }
    else if ( c == '/') {
      // toggle the move direction
      move_direction = ! move_direction;
      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;

      input_state = CARD_INPUT_MODE;
    }
    else if (c == '.') {
      // start again typing the table location:
      input_state = TABLE_LOCATION_EXPECTED;
    }
    else if (c >= '0' && c <= '9') {
      // Digit as could be
      if ( user_digit_coordinate * 10 + c - '0'
	   > (use_digits_for_the_columns
	      ? table->get_width()
	      : table->get_height()
	      )
	   ) {
	// digit is too large
	return -1;
      }

      user_wants_move = true;
      
      user_digit_coordinate *= 10;
      user_digit_coordinate += c - '0';
      set_start_location_from_user_coordinates();

      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;// maybe because start lo-
      // cation not complete now or because the user wants to delete a card.

      if ( user_digit_coordinate * 10
	   > (use_digits_for_the_columns
	      ? table->get_width()
	      : table->get_height()
	      )
	   ) {
	input_state = CARD_INPUT_MODE;
      }
      else {
	input_state = TABLE_LOCATION_CHAR_GIVEN_NUMBER_MAYBE_NOT_FINISHED_YET;
      }
    }
    else if (c == ' ') {
      // wildcard entry
      size_t no_of_matching_cards =
        hand->get_no_of_matching_cards(CardWords_Char::blanko);
      if (no_of_matching_cards == 0) {
        return -1;
      }
      // Do not add the card now.
      input_state = WILDCARD_MEANING_SPECIFICATION_NEEDED;
    }
    else {
      CardWords_Char kc = c;

      if (kc == CardWords_Char::blanko) {
        // invalid request: blanko would have been ' ' before
        return -1;
      }
      size_t no_of_matching_cards = hand->get_no_of_matching_cards(kc);
      if (no_of_matching_cards == 0) {
        return -1;
      }
      
      card_meaning = kc;
      
      if (no_of_matching_cards > 1) {
        // test if they have different points
        int points_of_first_card = hand->matching_card(kc, 1)->get_points();
        size_t card_index;
        for (card_index=2; card_index <= no_of_matching_cards; ++card_index) {
          if (points_of_first_card
              != hand->matching_card(kc, card_index)->get_points()) {
            // yes we have different points
            input_state = CARD_POINTS_NEEDED;
            return 0;
          }
        }
        // only one points value, we can take the first card
      }

      CardWords_Card * card = hand->matching_card(card_meaning, 1);

      initiated_add_myself = true;
      add_card(card);
      assert(initiated_add_myself == false);

      cards += *card;
      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;// maybe because start lo-
      // cation is to be changed or because the user wants to delete a card.

      input_state = CARD_INPUT_MODE;
    }
    break;
  case TABLE_LOCATION_NUMBER_GIVEN_CHAR_EXPECTED:
    if (c >= 'a' && c <= 'z') {
      // make it uppercase
      c += 'A' - 'a';
    }
    if (c == '.') {
      // Make a trade from it
      user_wants_move = false;
      is_move = false;
      if (cards.size() > 0) {
        is_trade = true;
      }
      input_state = CARD_INPUT_MODE;
    }
    else if (c == 27) {
      // escape from location mode
      input_state = CARD_INPUT_MODE;
    }
    else if (c >= 'A' && c <= 'Z') {
      // Char as expected
      if ( size_t(c - 'A' + 1)
	   > (use_digits_for_the_columns
	      ? table->get_height()
	      : table->get_width()
	      )
	   ) {
	// Char is too large
	return -1;
      }
      user_char_coordinate = c;
      set_start_location_from_user_coordinates();
      user_wants_move = true;
      
      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;// maybe because start lo-
      // cation is to be changed or because the user wants to delete a card.

      input_state = CARD_INPUT_MODE;
    }
    else {
      // invalid request
      return -1;
    }
    break;


  case TABLE_LOCATION_NUMBER_BEGUN_MAYBE_NOT_FINISHED_YET:
    if (c >= 'a' && c <= 'z') {
      // make it uppercase
      c += 'A' - 'a';
    }
    if (c == '.'){
      // Make a trade from it
      user_wants_move = false;
      is_move = false;
      if (cards.size() > 0) {
	is_trade = true;
      }
      input_state = CARD_INPUT_MODE;
    }
    else if (c == 27) {
      // escape from table location mode
      input_state = CARD_INPUT_MODE;
    }
    else if (c >= 'A' && c <= 'Z') {
      // Char as could be
      if ( size_t(c - 'A' + 1)
	   > (use_digits_for_the_columns
	      ? table->get_height()
	      : table->get_width()
	      )
	   ) {
	// Char is too large
	return -1;
      }
      user_char_coordinate = c;
      set_start_location_from_user_coordinates();
      user_wants_move = true;
      
      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;// maybe because start lo-
      // cation is to be changed or because the user wants to delete a card.

      input_state = CARD_INPUT_MODE;
    }
    else if (c >= '0' && c <= '9') {
      // Digit as could be
      if ( user_digit_coordinate * 10 + c - '0'
	   > (use_digits_for_the_columns
	      ? table->get_width()
	      : table->get_height()
	      )
	   ) {
	// digit is too large
	return -1;
      }

      user_digit_coordinate *= 10;
      user_digit_coordinate += c - '0';
      set_start_location_from_user_coordinates();

      user_wants_move = true;
      
      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;// maybe because start lo-
      // cation is to be changed or because the user wants to delete a card.

      if ( user_digit_coordinate * 10
	   > (use_digits_for_the_columns
	      ? table->get_width()
	      : table->get_height()
	      )
	   ) {
	input_state = TABLE_LOCATION_NUMBER_GIVEN_CHAR_EXPECTED;
      }
      else {
	input_state = TABLE_LOCATION_NUMBER_BEGUN_MAYBE_NOT_FINISHED_YET;
      }
    }
    else {
      // invalid request
      return -1;
    }
    break;

  case CARD_INPUT_MODE:
    if (c == 'M' - 64 || c == 'J' - 64) {
      return 1;
    }
    else if ( c == '/') {
      // toggle the move direction
      move_direction = ! move_direction;
      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;
    }
    else if (c == '.') {
      // start again typing the table location:
      input_state = TABLE_LOCATION_EXPECTED;
    }
    else if (c == ' ') {
      // wildcard entry
      size_t no_of_matching_cards =
        hand->get_no_of_matching_cards(CardWords_Char::blanko);
      if (no_of_matching_cards == 0) {
        return -1;
      }
      // Do not add the card now.
      input_state = WILDCARD_MEANING_SPECIFICATION_NEEDED;
      selected_wildcard = 0; // We don't know which wildcard yet
    }
    else if ( c == 'H' - 64/*BackSpace*/ && size() > 0) {
      // Delete the last card and its meaning if it is a wildcard
      CardWords_Card * last_card = get_card(size() - 1);
      if (last_card->is_wildcard()) {
        last_card->set_meaning(CardWords_Char::blanko);
      }
      initiated_remove_myself = true;
      hand->add_card(last_card);
      assert(initiated_remove_myself == false);
      cards.pop_back();

      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;

      input_state = CARD_INPUT_MODE;
    }
    else {
      CardWords_Char kc = c;

      if (kc == CardWords_Char::blanko) {
        // invalid request: blanko would have been ' ' before
        return -1;
      }
      size_t no_of_matching_cards = hand->get_no_of_matching_cards(kc);
      if (no_of_matching_cards == 0) {
        return -1;
      }
      
      card_meaning = kc;
      
      if (no_of_matching_cards > 1) {
        // test if they have different points
        int points_of_first_card = hand->matching_card(kc, 1)->get_points();
        size_t card_index;
        for (card_index=2; card_index <= no_of_matching_cards; ++card_index) {
          if (points_of_first_card
              != hand->matching_card(kc, card_index)->get_points()) {
            // yes we have different points
            input_state = CARD_POINTS_NEEDED;
            return 0;
          }
        }
        // only one points value, we can take the first card
      }

      CardWords_Card * card = hand->matching_card(card_meaning, 1);

      initiated_add_myself = true;
      add_card(card);
      assert(initiated_add_myself == false);

      cards += *card;
      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;// maybe because start lo-
      //                                           cation is to be changed.

      input_state = CARD_INPUT_MODE;
    }
    break;

  case WILDCARD_MEANING_SPECIFICATION_NEEDED:
    if ( c == '/') {
      // toggle the move direction
      move_direction = ! move_direction;
      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;
    }
    else if (c == '.') {
      // start again typing the table location:
      input_state = TABLE_LOCATION_EXPECTED;
    }
    else if ( c == 27 ) {
      // escape from wildcard mode
      input_state = CARD_INPUT_MODE;
    }
    else {
      CardWords_Char kc = c;
      CardWords_Card * card = 0;

      if (kc == CardWords_Char::blanko) {
        // invalid request: blanko can not be the meaning of a wildcard
        return -1;
      }
      size_t no_of_matching_cards =
        hand->get_no_of_matching_cards(CardWords_Char::blanko);
      if (no_of_matching_cards == 0) {
        return -1;
      }
      
      card_meaning = kc;

      if (selected_wildcard != 0) {
        // We know already which wildcard to add:
        card = selected_wildcard;
        selected_wildcard = 0;
        assert (hand->find(card) != hand->end());
      }
      else {
        // selected_wildcard == 0
        if (no_of_matching_cards > 1) {
          // test if they have different points
          int points_of_first_card =
            hand->matching_card(CardWords_Char::blanko, 1)->get_points();
          size_t card_index;
          for (card_index=2;
               card_index <= no_of_matching_cards;
               ++card_index) {
            if (points_of_first_card
                != hand->matching_card(CardWords_Char::blanko,
                                        card_index)->get_points()) {
              // yes we have different points
              input_state = WILDCARD_POINTS_NEEDED;
              return 0;
            }
          }
          // only one points value, we can take the first card
        }
        card = hand->matching_card(CardWords_Char::blanko, 1);
      }

      initiated_add_myself = true;
      add_card(card);
      assert(initiated_add_myself == false);

      card->set_meaning(card_meaning);
      
      cards += *card;

      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;// maybe because start lo-
      //                                           cation is to be changed.

      input_state = CARD_INPUT_MODE;
    }
    break;
    
  case CARD_POINTS_NEEDED:
    if ( c == '/') {
      // toggle the move direction
      move_direction = ! move_direction;
      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;
    }
    else if (c == '.') {
      // start again typing the table location:
      input_state = TABLE_LOCATION_EXPECTED;
    }
    else if ( c == 27 ) {
      // escape from current card input
      input_state = CARD_INPUT_MODE;
    }
    else if ( c == '-' ) {
      
      card_points_negative = true;
      absolute_card_points = card_points = 0;
      
      // count the cards with a negative value:
      size_t no_of_matching_cards =
        hand->get_no_of_matching_cards(card_meaning);
      size_t index_of_first_card_with_negative_points = 0;
      int   points_of_first_card_with_negative_points;
      
      if (no_of_matching_cards == 0 || no_of_matching_cards == 1) {
        // Something has changed here, the last check had a value > 1
        // Be upset but mostly silent about it:
        input_state = CARD_INPUT_MODE;
        return -1;
      }

      // check if there are different negative points:
      size_t card_index;
      CardWords_Card * card = 0;
      for (card_index=1; card_index <= no_of_matching_cards; ++card_index) {
        card = hand->matching_card(card_meaning, card_index);

        if (card->get_points() < 0) {
          if (index_of_first_card_with_negative_points == 0) {
            // We found the first negative points card:
            index_of_first_card_with_negative_points = card_index;
            points_of_first_card_with_negative_points = card->get_points();
          }
          else {
            // This is another card with negative points, check if the value
            // is the same:
            
            if (points_of_first_card_with_negative_points
                != card->get_points()) {
              // yes we have different points
              input_state = CARD_POINTS_NOT_FINISHED_YET;
              return 0;
            }
          }
        }
      }
      if (index_of_first_card_with_negative_points == 0) {
        // We did not find any negative value:
        return -1;
      }
      
      // Only one negative points value, we can take the first card:

      initiated_add_myself = true;
      add_card(card);
      assert(initiated_add_myself == false);

      cards += *card;

      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;

      input_state = CARD_INPUT_MODE;
    }
    else if (c >= '0' && c <= '9') {
      card_points_negative = false;
      absolute_card_points = card_points = c - '0';
      
      // count the cards with matching values:
      size_t no_of_matching_cards =
        hand->get_no_of_matching_cards(card_meaning);
      size_t index_of_first_matching_card = 0;

      bool greater_number_possible = false;
      
      if (no_of_matching_cards == 0 || no_of_matching_cards == 1) {
        // Something has changed here, the last check had a value > 1
        // Be upset but mostly silent about it:
        input_state = CARD_INPUT_MODE;
        return -1;
      }

      // check if there are matching cards:
      size_t card_index;
      CardWords_Card * card = 0;
      for (card_index=1; card_index <= no_of_matching_cards; ++card_index) {
        card = hand->matching_card(card_meaning, card_index);

        if (card->get_points() == card_points
            && index_of_first_matching_card == 0) {
            // We found the first card with the desired points:
            index_of_first_matching_card = card_index;
        }
        else if (card_points != 0) {
          // Check if this card's points consist of multiple digits and could
          // start with card_points:
          int test_points = card->get_points() / 10;
          while (test_points != 0) {
            if (card_points == test_points) {
              // Yes, adding some digits and this card's points could be
              // reached:
              greater_number_possible = true;
              break;
            }
            test_points /= 10;
          }
        }
      }
      if (index_of_first_matching_card != 0) {
      // We found an exact match

        initiated_add_myself = true;
        add_card(card);
        assert(initiated_add_myself == false);

        cards += *card;

        move = cards;
        move.location = start_location;
        move.direction = move_direction;

        is_move = (user_wants_move
                   && move.size() > 0
                   && table->check_move_fits(move));
        is_trade = (!is_move) && cards.size() > 0;

        input_state = ( greater_number_possible
                        ? CARD_POINTS_MAYBE_NOT_FINISHED_YET
                        : CARD_INPUT_MODE);
      }
      else {
        // no match found
        if (greater_number_possible) {
          input_state = CARD_POINTS_NOT_FINISHED_YET;
        }
        else {
          return -1;
        }
      }
    }
    else {
      // invalid request
      return -1;
    }
      
    break;
    
  case WILDCARD_POINTS_NEEDED:
    if ( c == '/') {
      // toggle the move direction
      move_direction = ! move_direction;
      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;
    }
    else if (c == '.') {
      // start again typing the table location:
      input_state = TABLE_LOCATION_EXPECTED;
    }
    else if ( c == 27 ) {
      // escape from current card input
      input_state = CARD_INPUT_MODE;
    }
    else if ( c == '-' ) {
      
      card_points_negative = true;
      absolute_card_points = card_points = 0;
      
      // count the cards with a negative value:
      size_t no_of_matching_cards =
        hand->get_no_of_matching_cards(CardWords_Char::blanko);
      size_t index_of_first_card_with_negative_points = 0;
      int   points_of_first_card_with_negative_points;
      
      if (no_of_matching_cards == 0 || no_of_matching_cards == 1) {
        // Something has changed here, the last check had a value > 1
        // Be upset but mostly silent about it:
        input_state = CARD_INPUT_MODE;
        return -1;
      }

      // check if there are different negative points:
      size_t card_index;
      CardWords_Card * card = 0;
      for (card_index=1; card_index <= no_of_matching_cards; ++card_index) {
        card = hand->matching_card(CardWords_Char::blanko, card_index);

        if (card->get_points() < 0) {
          if (index_of_first_card_with_negative_points == 0) {
            // We found the first negative points card:
            index_of_first_card_with_negative_points = card_index;
            points_of_first_card_with_negative_points = card->get_points();
          }
          else {
            // This is another card with negative points, check if the value
            // is the same:
            
            if (points_of_first_card_with_negative_points
                != card->get_points()) {
              // yes we have different points
              input_state = WILDCARD_POINTS_NOT_FINISHED_YET;
              return 0;
            }
          }
        }
      }
      if (index_of_first_card_with_negative_points == 0) {
        // We did not find any negative value:
        return -1;
      }
      
      // Only one negative points value, we can take the first card:

      initiated_add_myself = true;
      add_card(card);
      assert(initiated_add_myself == false);

      card->set_meaning(card_meaning);

      cards += *card;

      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;

      input_state = CARD_INPUT_MODE;
    }
    else if (c >= '0' && c <= '9') {
      card_points_negative = false;
      absolute_card_points = card_points = c - '0';
      
      // count the cards with matching values:
      size_t no_of_matching_cards =
        hand->get_no_of_matching_cards(CardWords_Char::blanko);
      size_t index_of_first_matching_card = 0;

      bool greater_number_possible = false;
      
      if (no_of_matching_cards == 0 || no_of_matching_cards == 1) {
        // Something has changed here, the last check had a value > 1
        // Be upset but mostly silent about it:
        input_state = CARD_INPUT_MODE;
        return -1;
      }

      // check if there are matching cards:
      size_t card_index;
      CardWords_Card * card = 0;
      for (card_index=1; card_index <= no_of_matching_cards; ++card_index) {
        card = hand->matching_card(CardWords_Char::blanko, card_index);

        if (card->get_points() == card_points
            && index_of_first_matching_card == 0) {
            // We found the first card with the desired points:
            index_of_first_matching_card = card_index;
        }
        else if (card_points != 0) {
          // Check if this card's points consist of multiple digits and could
          // start with card_points:
          int test_points = card->get_points() / 10;
          while (test_points != 0) {
            if (card_points == test_points) {
              // Yes, adding some digits and this card's points could be
              // reached:
              greater_number_possible = true;
              break;
            }
            test_points /= 10;
          }
        }
      }
      if (index_of_first_matching_card != 0) {
      // We found an exact match

        initiated_add_myself = true;
        add_card(card);
        assert(initiated_add_myself == false);

        card->set_meaning(card_meaning);

        cards += *card;

        move = cards;
        move.location = start_location;
        move.direction = move_direction;

        is_move = (user_wants_move
                   && move.size() > 0
                   && table->check_move_fits(move));
        is_trade = (!is_move) && cards.size() > 0;

        input_state = ( greater_number_possible
                        ? WILDCARD_POINTS_MAYBE_NOT_FINISHED_YET
                        : CARD_INPUT_MODE);
      }
      else {
        // no match found
        if (greater_number_possible) {
          input_state = WILDCARD_POINTS_NOT_FINISHED_YET;
        }
        else {
          // no such point value
          return -1;
        }
      }
    }
    else {
      // invalid request
      return -1;
    }
      
    break;
    
  case CARD_POINTS_NOT_FINISHED_YET:
    if ( c == '/') {
      // toggle the move direction
      move_direction = ! move_direction;
      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;
    }
    else if (c == '.') {
      // start again typing the table location:
      input_state = TABLE_LOCATION_EXPECTED;
    }
    else if ( c == 27 || c == 'H' - 64/*BackSpace*/) {
      // escape from current card input
      input_state = CARD_INPUT_MODE;
    }
    else if (c >= '0' && c <= '9') {
      int old_absolute_card_points = absolute_card_points;
      absolute_card_points *= 10;
      absolute_card_points += c - '0';
      card_points = ( card_points_negative
                      ? -absolute_card_points
                      : absolute_card_points);
      
      // count the cards with matching values:
      size_t no_of_matching_cards =
        hand->get_no_of_matching_cards(card_meaning);
      size_t index_of_first_matching_card = 0;

      bool greater_number_possible = false;
      
      if (no_of_matching_cards == 0 || no_of_matching_cards == 1) {
        // Something has changed here, the last check had a value > 1
        // Be upset but mostly silent about it:
        input_state = CARD_INPUT_MODE;
        return -1;
      }

      // check if there are matching cards:
      size_t card_index;
      CardWords_Card * card = 0;
      for (card_index=1; card_index <= no_of_matching_cards; ++card_index) {
        card = hand->matching_card(card_meaning, card_index);

        if (card->get_points() == card_points
            && index_of_first_matching_card == 0) {
            // We found the first card with the desired points:
            index_of_first_matching_card = card_index;
        }
        else if (card_points != 0) {
          // Check if this card's points consist of multiple digits and could
          // start with card_points:
          if ((card->get_points() < 0)
              != card_points_negative) {
            continue;
          }
          int test_points = ( card_points_negative
                              ? ((-card->get_points()) / 10)
                              : (card->get_points() / 10)   );
          while (test_points != 0) {
            if (absolute_card_points == test_points) {
              // Yes, adding some digits and this card's points could be
              // reached:
              greater_number_possible = true;
              break;
            }
            test_points /= 10;
          }
        }
      }
      if (index_of_first_matching_card != 0) {
      // We found an exact match

        initiated_add_myself = true;
        add_card(card);
        assert(initiated_add_myself == false);

        cards += *card;

        move = cards;
        move.location = start_location;
        move.direction = move_direction;

        is_move = (user_wants_move
                   && move.size() > 0
                   && table->check_move_fits(move));
        is_trade = (!is_move) && cards.size() > 0;

        input_state = ( greater_number_possible
                        ? CARD_POINTS_MAYBE_NOT_FINISHED_YET
                        : CARD_INPUT_MODE);
      }
      else {
        // no match found
        if (greater_number_possible) {
          input_state = CARD_POINTS_NOT_FINISHED_YET;
        }
        else {
          // invalid request, restore state
          absolute_card_points = old_absolute_card_points;
          card_points = ( card_points_negative
                          ? -absolute_card_points
                          : absolute_card_points);
          return -1;
        }
      }
    }
    else {
      return -1;
    }
      
    break;
    
  case CARD_POINTS_MAYBE_NOT_FINISHED_YET:
    if (c == 'M' - 64 || c == 'J' - 64) {
      input_state = CARD_INPUT_MODE;
      return 1;
    }
    else if ( c == '/') {
      // toggle the move direction
      move_direction = ! move_direction;
      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;
    }
    else if (c == '.') {
      // start again typing the table location:
      input_state = TABLE_LOCATION_EXPECTED;
    }
    else if ( c == 'H' - 64/*BackSpace*/) {
      // Delete the last card.
      initiated_remove_myself = true;
      hand->add_card(get_card(size()-1));
      assert(initiated_remove_myself == false);
      cards.pop_back();

      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;

      input_state = CARD_INPUT_MODE;
    }
    else if (c >= '0' && c <= '9') {
      int old_absolute_card_points = absolute_card_points;
      absolute_card_points *= 10;
      absolute_card_points += c - '0';
      card_points = ( card_points_negative
                      ? -absolute_card_points
                      : absolute_card_points);
      
      // count the cards with matching values:
      size_t no_of_matching_cards =
        hand->get_no_of_matching_cards(card_meaning);
      size_t index_of_first_matching_card = 0;

      bool greater_number_possible = false;
      
      if (no_of_matching_cards == 0) {
        // Something has changed here, the last check had a value > 1,
        // now 1 is subtracted from that because a card is already added to
        // *this.
        // Be upset but mostly silent about it:
        input_state = CARD_INPUT_MODE;
        return -1;
      }

      // check if there are matching cards:
      size_t card_index;
      CardWords_Card * card = 0;
      for (card_index=1; card_index <= no_of_matching_cards; ++card_index) {
        card = hand->matching_card(card_meaning, card_index);

        if (card->get_points() == card_points
            && index_of_first_matching_card == 0) {
            // We found the first card with the desired points:
            index_of_first_matching_card = card_index;
        }
        else if (card_points != 0) {
          // Check if this card's points consist of multiple digits and could
          // start with card_points:
          if ((card->get_points() < 0) != card_points_negative) {
            continue;
          }
          int test_points = ( card_points_negative
                              ? ((-card->get_points()) / 10)
                              : (card->get_points() / 10)   );
          while (test_points != 0) {
            if (absolute_card_points == test_points) {
              // Yes, adding some digits and this card's points could be
              // reached:
              greater_number_possible = true;
              break;
            }
            test_points /= 10;
          }
        }
      }
      if (index_of_first_matching_card != 0) {
        // We found an exact match.
        // Remove the previously added card:

        initiated_remove_myself = true;
        hand->add_card(get_card(size() - 1));
        assert(initiated_remove_myself == false);
        cards.pop_back();
        
        initiated_add_myself = true;
        add_card(card);
        assert(initiated_add_myself == false);

        cards += *card;

        move = cards;
        move.location = start_location;
        move.direction = move_direction;

        is_move = (user_wants_move
                   && move.size() > 0
                   && table->check_move_fits(move));
        is_trade = (!is_move) && cards.size() > 0;

        input_state = ( greater_number_possible
                        ? CARD_POINTS_MAYBE_NOT_FINISHED_YET
                        : CARD_INPUT_MODE);
      }
      else {
        // no match found
        if (greater_number_possible) {
          input_state = CARD_POINTS_MAYBE_NOT_FINISHED_YET;
        }
        else {
          // invalid request, restore state
          absolute_card_points = old_absolute_card_points;
          card_points = ( card_points_negative
                          ? -absolute_card_points
                          : absolute_card_points);
          return -1;
        }
      }
    }
    else {
      return -1;
    }
      
    break;
    
  case WILDCARD_POINTS_NOT_FINISHED_YET:
    if ( c == '/') {
      // toggle the move direction
      move_direction = ! move_direction;
      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;
    }
    else if (c == '.') {
      // start again typing the table location:
      input_state = TABLE_LOCATION_EXPECTED;
    }
    else if ( c == 27 || c == ('H' - 64)/*BackSpace*/) {
      // escape from current card input
      input_state = CARD_INPUT_MODE;
    }
    else if (c >= '0' && c <= '9') {
      int old_absolute_card_points = absolute_card_points;
      absolute_card_points *= 10;
      absolute_card_points += c - '0';
      card_points = ( card_points_negative
                      ? -absolute_card_points
                      : absolute_card_points);
      
      // count the cards with matching values:
      size_t no_of_matching_cards =
        hand->get_no_of_matching_cards(CardWords_Char::blanko);
      size_t index_of_first_matching_card = 0;

      bool greater_number_possible = false;
      
      if (no_of_matching_cards == 0 || no_of_matching_cards == 1) {
        // Something has changed here, the last check had a value > 1
        // Be upset but mostly silent about it:
        input_state = CARD_INPUT_MODE;
        return -1;
      }

      // check if there are matching cards:
      size_t card_index;
      CardWords_Card * card = 0;
      for (card_index=1; card_index <= no_of_matching_cards; ++card_index) {
        card = hand->matching_card(CardWords_Char::blanko, card_index);

        if (card->get_points() == card_points
            && index_of_first_matching_card == 0) {
          // We found the first card with the desired points:
          index_of_first_matching_card = card_index;
        }
        else if (card_points != 0) {
          // Check if this card's points consist of multiple digits and could
          // start with card_points:
          if ((card->get_points() < 0)
              != card_points_negative) {
            continue;
          }
          int test_points = ( card_points_negative
                              ? ((-card->get_points()) / 10)
                              : (card->get_points() / 10)   );
          while (test_points != 0) {
            if (absolute_card_points == test_points) {
              // Yes, adding some digits and this card's points could be
              // reached:
              greater_number_possible = true;
              break;
            }
            test_points /= 10;
          }
        }
      }
      if (index_of_first_matching_card != 0) {
      // We found an exact match

        initiated_add_myself = true;
        add_card(card);
        assert(initiated_add_myself == false);

        card->set_meaning(card_meaning);

        cards += *card;

        move = cards;
        move.location = start_location;
        move.direction = move_direction;

        is_move = (user_wants_move
                   && move.size() > 0
                   && table->check_move_fits(move));
        is_trade = (!is_move) && cards.size() > 0;

        input_state = ( greater_number_possible
                        ? WILDCARD_POINTS_MAYBE_NOT_FINISHED_YET
                        : CARD_INPUT_MODE);
      }
      else {
        // no match found
        if (greater_number_possible) {
          input_state = WILDCARD_POINTS_NOT_FINISHED_YET;
        }
        else {
          // invalid request, restore state
          absolute_card_points = old_absolute_card_points;
          card_points = ( card_points_negative
                          ? -absolute_card_points
                          : absolute_card_points);
          return -1;
        }
      }
    }
    else {
      return -1;
    }
      
    break;

  case WILDCARD_POINTS_MAYBE_NOT_FINISHED_YET:
    if (c == ('M' - 64) || c == ('J' - 64)) {
      input_state = CARD_INPUT_MODE;
      return 1;
    }
    else if ( c == '/') {
      // toggle the move direction
      move_direction = ! move_direction;
      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;
    }
    else if (c == '.') {
      // start again typing the table location:
      input_state = TABLE_LOCATION_EXPECTED;
    }
    else if ( c == ('H' - 64)/*BackSpace*/) {
      // Delete the last card and its meaning
      CardWords_Card * last_card = get_card(size() - 1);
      last_card->set_meaning(CardWords_Char::blanko);
      initiated_remove_myself = true;
      hand->add_card(last_card);
      assert(initiated_remove_myself == false);
      cards.pop_back();

      move = cards;
      move.location = start_location;
      move.direction = move_direction;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;

      input_state = CARD_INPUT_MODE;
    }
    else if (c >= '0' && c <= '9') {
      int old_absolute_card_points = absolute_card_points;
      absolute_card_points *= 10;
      absolute_card_points += c - '0';
      card_points = ( card_points_negative
                      ? -absolute_card_points
                      : absolute_card_points);
      
      // count the cards with matching values:
      size_t no_of_matching_cards =
        hand->get_no_of_matching_cards(card_meaning);
      size_t index_of_first_matching_card = 0;

      bool greater_number_possible = false;
      
      if (no_of_matching_cards == 0) {
        // Something has changed here, the last check had a value > 1,
        // now 1 is subtracted from that because a card is already added to
        // *this.
        // Be upset but mostly silent about it:
        input_state = CARD_INPUT_MODE;
        return -1;
      }

      // check if there are matching cards:
      size_t card_index;
      CardWords_Card * card = 0;
      for (card_index=1; card_index <= no_of_matching_cards; ++card_index) {
        card = hand->matching_card(CardWords_Char::blanko, card_index);

        if (card->get_points() == card_points
            && index_of_first_matching_card == 0) {
            // We found the first card with the desired points:
            index_of_first_matching_card = card_index;
        }
        else if (card_points != 0) {
          // Check if this card's points consist of multiple digits and could
          // start with card_points:
          if ((card->get_points() < 0) != card_points_negative) {
            continue;
          }
          int test_points = ( card_points_negative
                              ? ((-card->get_points()) / 10)
                              : (card->get_points() / 10)   );
          while (test_points != 0) {
            if (absolute_card_points == test_points) {
              // Yes, adding some digits and this card's points could be
              // reached:
              greater_number_possible = true;
              break;
            }
            test_points /= 10;
          }
        }
      }
      if (index_of_first_matching_card != 0) {
        // We found an exact match.
        // Remove the previously added card:
        CardWords_Card * last_card = get_card(size() - 1);
        last_card->set_meaning(CardWords_Char::blanko);        
        initiated_remove_myself = true;
        hand->add_card(last_card);
        assert(initiated_remove_myself == false);
        cards.pop_back();
        
        initiated_add_myself = true;
        add_card(card);
        assert(initiated_add_myself == false);
        card->set_meaning(card_meaning);
        

        cards += *card;

        move = cards;
        move.location = start_location;
        move.direction = move_direction;

        is_move = (user_wants_move
                   && move.size() > 0
                   && table->check_move_fits(move));
        is_trade = (!is_move) && cards.size() > 0;

        input_state = ( greater_number_possible
                        ? WILDCARD_POINTS_MAYBE_NOT_FINISHED_YET
                        : CARD_INPUT_MODE);
      }
      else {
        // no match found
        if (greater_number_possible) {
          input_state = WILDCARD_POINTS_MAYBE_NOT_FINISHED_YET;
        }
        else {
          // invalid request, restore state
          absolute_card_points = old_absolute_card_points;
          card_points = ( card_points_negative
                          ? -absolute_card_points
                          : absolute_card_points);
          return -1;
        }
      }
    }
    else {
      return -1;
    }
      
    break;
    
  }
  return 0;
}

// reset() causes the current user interaction process to be terminated,
// eg because the server assumes that the player wants to pass because of
// a timeout.
void
CardWords_ActionSelection::reset(void)
{
  clear(hand);
  input_state = TABLE_LOCATION_EXPECTED;
}
  
CardWords_ActionSelection::
CardWords_ActionSelection(CardWords_Hand *ben, // The hand from where to get
                          // the cards. The hand will be modified, but will
                          // be restored when take_key_strike returns 1 or
                          // when reset() is called.
                          const CardWords_CardTable *boa, // With this
                          //     pointer, in-
                          //     valid geometric moves will be detected.

                          bool s_use_digits_for_the_columns,
                          // and chars for the rows, otherwise the other way
                          // round
			  
                        bool s_column_indices_grow_rightwards,
                        // if true, the rightmost column has the greatest
                        // index
			  
                        bool s_row_indices_grow_upwards)
  

  : CardWords_CardContainer1Dim(ben->total_places()),
    hand(ben),
    table(boa),
    input_state(TABLE_LOCATION_EXPECTED),
    is_move(false),
    is_trade(false),
    user_wants_move(true),
    start_location(table->get_width() / 2,
                   table->get_height() / 2),
    move_direction(horizontal),

    use_digits_for_the_columns(s_use_digits_for_the_columns),

    column_indices_grow_rightwards(s_column_indices_grow_rightwards),

    row_indices_grow_upwards(s_row_indices_grow_upwards),
      
    last_char('\0'),

    initiated_add_myself(false),
    initiated_remove_myself(false),

    selected_wildcard(0)
      
{
  change_start_location(start_location);
  input_state = TABLE_LOCATION_EXPECTED;
}
// These functions are for access to CardWords_ActionSelection for GUIs.
// This way they don't have to bother about the current state the object
// is in.
void
CardWords_ActionSelection::
change_start_location(CardWords_CardTableLocation loc)
{
  start_location = loc;
  if (use_digits_for_the_columns) {
    if (column_indices_grow_rightwards) {
      user_digit_coordinate = start_location.first + 1;
    }
    else {
      // !column_indices_grow_rightwards
      user_digit_coordinate = table->get_width() - start_location.first;
    }
    if (row_indices_grow_upwards) {
      user_char_coordinate = 'A' + 
        table->get_height() - start_location.second - 1 ;
    }
    else {
      // !row_indices_grow_upwards
      user_char_coordinate = start_location.second + 'A';
    }
  }
  else {
    // !use_digits_for_the_columns
    if (row_indices_grow_upwards) {
      user_digit_coordinate = table->get_height() - start_location.second;
    }
    else {
      // !row_indices_grow_upwards
      user_digit_coordinate = start_location.second + 1;
    }
    if (column_indices_grow_rightwards) {
      user_char_coordinate = start_location.first + 'A';
    }
    else {
      // !column_indices_grow_rightwards
      user_char_coordinate = 'A' - 1 + 
        table->get_width() - start_location.first;
    }
  }
  move = cards;
  move.location = start_location;
  move.direction = move_direction;

  user_wants_move = true;
  
  is_move = (user_wants_move
             && move.size() > 0
             && table->check_move_fits(move));
  is_trade = (!is_move) && cards.size() > 0;

  switch (input_state) {
  case TABLE_LOCATION_EXPECTED:
  case TABLE_LOCATION_CHAR_GIVEN_NUMBER_EXPECTED:
  case TABLE_LOCATION_CHAR_GIVEN_NUMBER_MAYBE_NOT_FINISHED_YET:
  case TABLE_LOCATION_NUMBER_GIVEN_CHAR_EXPECTED:
  case TABLE_LOCATION_NUMBER_BEGUN_MAYBE_NOT_FINISHED_YET:
    input_state = CARD_INPUT_MODE;
    break;
  default:
    break;
  }
}
void
CardWords_ActionSelection::change_direction(CardWords_Direction new_direction)
{
  move_direction = new_direction;
  move = cards;
  move.location = start_location;
  move.direction = move_direction;

  user_wants_move = true;
  
  is_move = (user_wants_move
             && move.size() > 0
             && table->check_move_fits(move));
  is_trade = (!is_move) && cards.size() > 0;

  switch (input_state) {
  case TABLE_LOCATION_EXPECTED:
  case TABLE_LOCATION_CHAR_GIVEN_NUMBER_EXPECTED:
  case TABLE_LOCATION_CHAR_GIVEN_NUMBER_MAYBE_NOT_FINISHED_YET:
  case TABLE_LOCATION_NUMBER_GIVEN_CHAR_EXPECTED:
  case TABLE_LOCATION_NUMBER_BEGUN_MAYBE_NOT_FINISHED_YET:
    input_state = CARD_INPUT_MODE;
    break;
  default:
    break;
  }
}

void
CardWords_ActionSelection::toggle_direction(void)
{
  
  change_direction(!move_direction);
}

void
CardWords_ActionSelection::make_trade(void) // Deletes the start location.
{
  user_wants_move = false;
  is_move = false;
  is_trade = cards.size() > 0;
}

// info methods. They do always work, not only after the input finished:
// If there is no move or trade, thez return 0. If both return 0, the
// current action is a pass.
const CardWords_Move *
CardWords_ActionSelection::get_move(void) const
{
  if (is_move == true) {
    return & move;
  }
  return 0;
}
  
const CardWords_CardSelection *
CardWords_ActionSelection::get_trade(void) const
{
  if (is_trade == true) {
    return  & cards;
  }
  return  0;
}

// Will sometimes return a start location even if get_move returns 0. This
// is the case if the user seems to want to make a move, but the move does
// not fit on the table at the current start location
const CardWords_CardTableLocation *
CardWords_ActionSelection::get_start_location(void) const
{
  if (user_wants_move == true) {
    return  & start_location;
  }
  return 0;
}
// Will sometimes return a direction even if get_move returns 0. This
// is the case if the user seems to want to make a move, but the move does
// not fit on the table at the current start location
const CardWords_Direction *
CardWords_ActionSelection::get_move_direction(void) const
{
  if (user_wants_move == true) {
    return & move_direction;
  }
  return 0;
}

// returns the number of digits in this number
inline static int
digitcount(long int number)
{
  int digits = 1;
  if (number < 0) {
    number = -number;
    ++digits; // the '-' sign
  }
  while ((number /= 10) != 0) {
    ++digits;
  }
 return digits;
}

int
CardWords_ActionSelection::print_user_start_coordinates(ostream & ostr) const
{
  int cursorpos;

  switch (input_state) {
  case TABLE_LOCATION_EXPECTED:
    cursorpos = 0;
    break;
  case TABLE_LOCATION_CHAR_GIVEN_NUMBER_EXPECTED: 
    cursorpos = 1;
    break;
  case TABLE_LOCATION_CHAR_GIVEN_NUMBER_MAYBE_NOT_FINISHED_YET:
    cursorpos = 1 + digitcount(user_digit_coordinate);
    break;
  case TABLE_LOCATION_NUMBER_GIVEN_CHAR_EXPECTED:
  case TABLE_LOCATION_NUMBER_BEGUN_MAYBE_NOT_FINISHED_YET:
    cursorpos = digitcount(user_digit_coordinate);
    break;
  default:
    cursorpos = -1; // cursor not in Tablelocation
    break;
  }
  
  if (is_move == false) {
    ostr << '{';
    if (cursorpos != -1) {
      cursorpos += 1;
    }
  }
  if (move_direction == horizontal) {
    if (use_digits_for_the_columns) {
      ostr << user_char_coordinate << user_digit_coordinate;
    }
    else {
      // !use_digits_for_the_columns
      ostr << user_digit_coordinate << user_char_coordinate;
    }
  }
  else {
    // ! (move_direction == horizontal)
    // move_direction == vertikal
    if (use_digits_for_the_columns) {
      ostr << user_digit_coordinate << user_char_coordinate;
    }
    else {
      // !use_digits_for_the_columns
      ostr << user_char_coordinate << user_digit_coordinate;
    }
  }
  if (is_move == false) {
    ostr << '}';
  }
  return cursorpos;
}    
int
CardWords_ActionSelection::print(ostream & ostr) const
{
  int cursorpos = -1;
  size_t no_of_printed_chars = 0;
  if (user_wants_move == true) {
    cursorpos = print_user_start_coordinates(ostr);
    ostr << ' ';
    no_of_printed_chars =
      1 // user_char_coordinate
      + digitcount(user_digit_coordinate)
      + ((is_move == false)
         ? 2 // braces
         : 0)
      + 1; // space
  }
  if (cards.size() > 0) {
    ostrstream selection_stream;
    selection_stream << cards << ends;
    
    selection_stream.freeze(true);

    const string selection_string = selection_stream.str();

    // skip number of cards
    size_t not_number_index =
      selection_string.find_first_not_of("0123456789");

    ostr << selection_string.substr(not_number_index);

    no_of_printed_chars += selection_string.length() - not_number_index;

    selection_stream.freeze(false);
  }
  
  switch (input_state) {
  case WILDCARD_MEANING_SPECIFICATION_NEEDED:
    ostr << " ( )";
    no_of_printed_chars += 4;
    cursorpos = no_of_printed_chars - 1;
    break;
  case CARD_POINTS_NEEDED:
    ostr << " (" << card_meaning << " )";
    no_of_printed_chars += 5;
    cursorpos = no_of_printed_chars - 1;
    break;
  case CARD_POINTS_NOT_FINISHED_YET:
    ostr << " (" << card_meaning << ' ' << card_points << ")";
    no_of_printed_chars += 4 + digitcount(card_points) + 1;
    cursorpos = no_of_printed_chars - 1;
    break;
  case WILDCARD_POINTS_NEEDED:
    ostr << " ( " << card_meaning << ")";
    no_of_printed_chars += 5;
    cursorpos = no_of_printed_chars - 1;
    break;
  case WILDCARD_POINTS_NOT_FINISHED_YET:
    ostr << " ( " << card_meaning << card_points << ")";
    no_of_printed_chars += 4 + digitcount(card_points) + 1;
    cursorpos = no_of_printed_chars - 1;
    break;
  default:
    if (cursorpos == -1) {
      cursorpos = no_of_printed_chars;
    }
    break;
  }
  return cursorpos;
}

void
CardWords_ActionSelection::set_start_location_from_user_coordinates(void)
{
  if (use_digits_for_the_columns) {
    if (column_indices_grow_rightwards) {
      start_location.first = user_digit_coordinate - 1;
    }
    else {
      // !column_indices_grow_rightwards
      start_location.first = table->get_width() - user_digit_coordinate;
    }
    if (row_indices_grow_upwards) {
      start_location.second =
        table->get_height() - (user_char_coordinate - 'A' + 1);
    }
    else {
      // !row_indices_grow_upwards
      start_location.second = user_char_coordinate - 'A';
    }
  }
  else {
    // !use_digits_for_the_columns
    if (row_indices_grow_upwards) {
      start_location.second = table->get_height() - user_digit_coordinate;
    }
    else {
      // !row_indices_grow_upwards
      start_location.second = user_digit_coordinate - 1;
    }
    if (column_indices_grow_rightwards) {
      start_location.first = user_char_coordinate - 'A';
    }
    else {
      // !column_indices_grow_rightwards
      start_location.first =
        table->get_width() - (user_char_coordinate - 'A' + 1);
    }
  }
}

void
CardWords_ActionSelection::add_card(CardWords_Card * p)
{
  // check redundant values:
  assert(cards.size() == card_pos.size());
  assert(cards.size() == move.size());
  assert(cards.size() == size());

  if (initiated_add_myself) {
    CardWords_CardContainer1Dim::add_card(p);
    initiated_add_myself = false;

    // update card_pos:
    card_pos[p] = size() - 1;
  }
  else {
    if (p->is_wildcard() == true
        && p->get_meaning() == CardWords_Char::blanko) {
      // do not add the wildcard now, we need to know its meaning:
      input_state = WILDCARD_MEANING_SPECIFICATION_NEEDED;
      selected_wildcard = p;
    }
    else {
      card_pos[p] = size();
      CardWords_CardContainer1Dim::add_card(p);
      
      cards += *p;

      move = cards;

      is_move = (user_wants_move
                 && move.size() > 0
                 && table->check_move_fits(move));
      is_trade = (!is_move) && cards.size() > 0;

      input_state = CARD_INPUT_MODE;

      // check redundant values again:
      assert(cards.size() == card_pos.size());
      assert(cards.size() == move.size());
      assert(cards.size() == size());
    }
  }
}

void
CardWords_ActionSelection::remove_card(CardWords_Card * p)
{
  assert(find(p) != end());
  
  if (initiated_remove_myself) {
    CardWords_CardContainer1Dim::remove_card(p);
    initiated_remove_myself = false;
    assert(card_pos[p] == size()); // self initiated removes always remove the
    //                               last  card.
    assert(cards.size() == card_pos.size()); // checking redundant values
    assert(cards.size() == move.size());
    assert(cards.size() == size() + 1); 

    // update the card_pos map, trade and move will be updated by
    // take_key_strike() which is somewhere in the backtrace
    card_pos.erase(p);
  }
  else {
    // remove called from outside this class:

    // check redundant values:
    assert(cards.size() == card_pos.size());
    assert(cards.size() == move.size());
    assert(cards.size() == size());

    // delete the meaning of a wildcard:
    if (p->is_wildcard() == true) {
      p->set_meaning(CardWords_Char::blanko);
    }

    // update this and cards and move and card_pos:
    CardWords_CardContainer1Dim::remove_card(p);
    size_t index;
    for (index = card_pos[p] + 1; index < cards.size(); ++index) {
      // copy all cards after p one pos to the begin:
      cards[index - 1] = cards[index];
    }
    cards.pop_back();

    map<CardWords_Card *, size_t>::iterator iter;
    const size_t card_p_index = card_pos[p];
    for (iter = card_pos.begin(); iter != card_pos.end(); ++iter) {
      // diminish the position of all cards after p:
      if ((*iter).second > card_p_index) {
        --((*iter).second);
      }
    }
    card_pos.erase(p);

    move = cards;

    is_move = (user_wants_move
               && move.size() > 0
               && table->check_move_fits(move));
    is_trade = (!is_move) && cards.size() > 0;
    
    // update the input state:
    switch (input_state) {
    case CARD_POINTS_MAYBE_NOT_FINISHED_YET:
    case WILDCARD_POINTS_MAYBE_NOT_FINISHED_YET:
      input_state = CARD_INPUT_MODE;
      break;
    default:
      // leave it as it is
      break;
    }
  }
}

// returns the actual card that is described in (*get_move())[n] or
// (*get_trade())[n]:
CardWords_Card *
CardWords_ActionSelection::get_card(size_t n) const
{
  if (n >= card_pos.size()) {
    return 0;
  }
  // search that card:
  map<CardWords_Card *, size_t>::const_iterator iter;
  for (iter = card_pos.begin(); iter != card_pos.end(); ++iter) {
    if ((*iter).second == n) {
      // found that position:
      return (*iter).first;
    }
  }
  return 0;
}
