/*
 * $Id: GamePieceOpImpl.java 4483 2008-11-16 18:15:32Z uckelman $
 *
 * Copyright (c) 2007 by Joel Uckelman
 *
 * 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.tools.imageop;

import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import VASSAL.counters.GamePiece;
import VASSAL.counters.Properties;
import VASSAL.tools.image.ImageUtils;
import VASSAL.tools.opcache.Op;
import VASSAL.tools.opcache.OpObserver;

/**
 * An {@link ImageOp} which uses a {@link GamePiece} as its source.
 * 
 * @since 3.1.0
 * @author Joel Uckelman
 */
public class GamePieceOpImpl extends AbstractTileOpImpl implements GamePieceOp {
  /** The image source for this <code>ImageOp</code>. */
  private final GamePiece piece;
  private final String state;
  private final int hash;

  /**
   * Constructs an <code>ImageOp</code> which will produce an image
   * from the given <code>GamePiece</code>.
   *
   * @param gp the source
   * @throws IllegalArgumentException if <code>gp == null</code>.
   */
  public GamePieceOpImpl(GamePiece gp) {
    if (gp == null) throw new IllegalArgumentException();
    piece = gp;
    state = String.valueOf(piece.getProperty(Properties.VISIBLE_STATE));
    hash = piece.hashCode();
  }

  @Override
  public BufferedImage get(OpObserver<BufferedImage> obs)
    throws CancellationException, InterruptedException, ExecutionException
  {
    // GamePieceOpImpl CANNOT be called asynchronously becuase it cannot
    // reliably report on its dependencies.
    if (obs != null) throw new UnsupportedOperationException();
    return super.get(obs);
  }

  @Override
  public Future<BufferedImage> getFuture(OpObserver<BufferedImage> obs)
                                                  throws ExecutionException {
    // GamePieceOpImpl CANNOT be called asynchronously becuase it cannot
    // reliably report on its dependencies.
    if (obs != null) throw new UnsupportedOperationException();
    return super.getFuture(obs);
  }

  public List<Op<?>> getSources() {
    return Collections.emptyList();
  }

  /** {@inheritDoc} */
  public BufferedImage eval() {
    final Rectangle b = piece.boundingBox();
    final BufferedImage im = ImageUtils.createCompatibleTranslucentImage(
      Math.max(b.width, 1),
      Math.max(b.height, 1)
    );
    final Graphics2D g = im.createGraphics();
    piece.draw(g, -b.x, -b.y, null, 1.0);
    g.dispose();
    return im;
  }

  /** {@inheritDoc} */
  protected void fixSize() {
    size = piece.boundingBox().getSize();
    if (size.width < 1) size.width = 1;
    if (size.height < 1) size.height = 1;
  }

  /**
   * Returns the source <code>GamePiece</code>.
   *
   * @return the source
   */
  public GamePiece getPiece() {
    return piece;
  }

  public String getState() {
    return state;
  }

  /**
   * Returns <code>true</code> iff the source <code>GamePiece</code>
   * has changed state.
   *
   * @return <code>true</code> iff the source has changed.
   */
  public boolean isChanged() {
    return !state.equals(piece.getProperty(Properties.VISIBLE_STATE));
  }

  /** {@inheritDoc} */
  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || !(o instanceof GamePieceOp)) return false;

    GamePieceOp op = (GamePieceOp) o;
    return piece.equals(op.getPiece()) &&
           state.equals(op.getState());
  }

  /** {@inheritDoc} */
  @Override
  public int hashCode() {
    return hash;
  }
}
