/*
 * $Id: ChangePiece.java 2893 2008-01-27 20:15:23Z uckelman $
 *
 * Copyright (c) 2000-2003 by Rodney Kinney
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License (LGPL) as published by the Free Software Foundation.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, copies are available 
 * at http://www.opensource.org.
 */
package VASSAL.command;

import VASSAL.build.GameModule;
import VASSAL.build.module.GlobalOptions;
import VASSAL.counters.BoundsTracker;
import VASSAL.counters.GamePiece;
import VASSAL.counters.Properties;
import VASSAL.counters.StateMergeable;

/**
 * This Command changes the state of a {@link GamePiece}.  Its undo
 * Command is another ChangePiece with the new and old states
 * reversed.  */
public class ChangePiece extends Command {
  protected String newState, oldState;
  private String id;
  private Command undo;

  /**
   * @param id the id of the {@link GamePiece} to change
   * @param oldState the previous state of the piece
   * @param newState the new state of the piece
   */
  public ChangePiece(String id, String oldState, String newState) {
    this.id = id;
    this.newState = newState;
    this.oldState = oldState;
  }

  /**
   * When using this constructor, the previous state will be set
   * to that of the piece when this Command is executed.
   * @deprecated
   */
  @Deprecated public ChangePiece(String id, String newState) {
    this(id, null, newState);
  }

  /**
   * Changes the state of a {@link GamePiece} by invoking {@link GamePiece#setState}
   */
  protected void executeCommand() {
    GamePiece target = GameModule.getGameModule().getGameState().getPieceForId(id);
    if (target != null) {
      BoundsTracker bounds = new BoundsTracker();
      bounds.addPiece(target);
      if (oldState != null) {
        if (target instanceof StateMergeable) {
          ((StateMergeable) target).mergeState(newState, oldState);
        }
        else {
          target.setState(newState);
        }
      }
      else {
        oldState = target.getState();
        target.setState(newState);
      }
      bounds.addPiece(target);
      bounds.repaint();
      if (target.getMap() != null
        && GlobalOptions.getInstance().centerOnOpponentsMove()
        && !Boolean.TRUE.equals(target.getProperty(Properties.INVISIBLE_TO_ME))) {
        target.getMap().ensureVisible(target.getMap().selectionBoundsOf(target));
      }
    }
  }

  public Command append(Command c) {
    Command last = this;
    Command[] sub = getSubCommands();
    if (sub.length > 0) {
      last = sub[sub.length - 1];
    }
    if (c instanceof ChangePiece
      && last instanceof ChangePiece
      && ((ChangePiece) c).id != null
      && ((ChangePiece) c).id.equals(((ChangePiece) last).id)
      && ((ChangePiece) c).newState != null) {
      ((ChangePiece) last).newState = ((ChangePiece) c).newState;
      sub = c.getSubCommands();
      for (int i = 0; i < sub.length; ++i) {
        append(sub[i]);
      }
      return this;
    }
    else {
      return super.append(c);
    }
  }

  protected Command myUndoCommand() {
    if (undo == null && oldState != null) {
      undo = new ChangePiece(id, newState, oldState);
    }
    return undo;
  }

  public String getId() {
    return id;
  }

  public String getNewState() {
    return newState;
  }

  public String getOldState() {
    return oldState;
  }

  public boolean isNull() {
    return newState.equals(oldState) && isAtomic();
  }
  
  public String getDetails() {
    return "id="+id+",oldState="+oldState+",newState="+newState;
  }
}
