// ============================================================================
// File:               $File$
//
// Project:            
//
// Purpose:            
//
// Author:             Rammi
//
// Copyright Notice:   (c) 2008  Rammi (rammi@caff.de)
//                     This code is in the public domain.
//                     Use at own risk.
//                     No guarantees given.
//
// Latest change:      $Date$
//
// History:	       $Log$
//=============================================================================
package de.caff.asteroid;

/**
 *   Automatically fill hall of fame entry.
 *
 *  This class is part of a solution for a
 *  <a href="http://www.heise.de/ct/creativ/08/02/details/">competition by the German computer magazine c't</a>
 */
public class HallOfFameFiller
        implements FrameListener,
                   GameData
{
  /** Somehow this needs some longer presses/releases, possibly to avoid glitches (and resulting long faces). */
  private static final int KEY_HOLD_TIME = 8;
  /** Length of Hall of Fame entry. */
  private static final int HOF_LENGTH = 3;
  /** Character sequence. */
  private static final String SEQUENCE = "ABCDEFGHIJKLMN"+
                                         "0PQRTSTUVWXYZ ";
  /** Communication to MAME access. */
  private Communication com;
  /** HOF entry to set. */
  private String text;
  /** Current position in entry. */
  private int currentPos = -1;
  /** Count down counter for key press/release. */
  private int releaseKey = 0;

  /**
   *  Constructor.
   *  @param com  communication
   *  @param text text to input
   */
  public HallOfFameFiller(Communication com, String text)
  {
    this.com = com;
    this.text = prepareText(text);
  }

  /**
   *  Prepare a text so it can be placed into the Hall of Fame.
   *  @param text text to prepare
   *  @return prepared text
   */
  private static String prepareText(String text)
  {
    text = FrameInfo.canonize(text.replaceAll("[1-9]", " "));
    if (text.length() > HOF_LENGTH) {
      text = text.substring(0, HOF_LENGTH);
    }
    else while (text.length() < HOF_LENGTH) {
      text += ' ';
    }

    return text;
  }

  /**
   * Called each time a frame is received.
   * <p/>
   * <b>ATTENTION:</b> this is called from the communication thread!
   * Implementing classes must be aware of this and take care by synchronization or similar!
   *
   * @param frame the received frame
   */
  public void frameReceived(FrameInfo frame)
  {
    if (!frame.isGameRunning()) {
      if (releaseKey > 0) {
        com.setButton(BUTTON_HYPERSPACE, releaseKey > KEY_HOLD_TIME);
        --releaseKey;
      }
      else {
        if (currentPos < HOF_LENGTH) {
          for (Text txt: frame.getTexts()) {
            if (txt.hasLocation(FrameInfo.NAME_INPUT_LOCATION)) {
              // here we are
              // System.out.println("currentChar="+ currentPos +", text="+txt);
              String displayText = txt.getText();
              if (displayText.length() - 1 > currentPos) {
                currentPos = displayText.length() - 1; // at least, but may be more because of spaces
              }
              char currentChar = displayText.length() > currentPos ?
                      displayText.charAt(currentPos) : ' ';
              pushButton(currentChar);
              return;
            }
          }
          if (currentPos >= 0) {
            pushButton(' ');
          }
        }
      }
    }
    else {
      currentPos = -1;
      releaseKey = 0;
    }
  }

  /**
   * Push a button depending on the displayed letter.
   * @param currentChar the displayed letter at the current position
   */
  private void pushButton(char currentChar)
  {
    if (currentChar == text.charAt(currentPos)) {
      pushHyperspace();
    }
    else {
      com.pushButton(SEQUENCE.indexOf(text.charAt(currentPos)) > SEQUENCE.length()/2 ?
              BUTTON_RIGHT :
              BUTTON_LEFT);
    }
  }

  /** Push the hyperspace button long enough so it is registered. */
  private void pushHyperspace()
  {
    com.pushButton(BUTTON_HYPERSPACE);
    releaseKey = 2*KEY_HOLD_TIME;
  }

}
