/*
 * $Id: RotateFilter.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.tools;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.image.ColorModel;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageConsumer;
import java.awt.image.ImageFilter;
import java.awt.image.ImageProducer;

/** @deprecated Use {@link VASSAL.tools.imageop.RotateOp} instead. */
@Deprecated
public class RotateFilter extends ImageFilter {
  private double angle;
  private double cos, sin;
  private Rectangle rotatedSpace;
  private Rectangle originalSpace;
  private ColorModel defaultRGBModel;
  private int inPixels[], outPixels[];

  public RotateFilter(double angle) {
    this.angle = angle * (Math.PI / 180);
    cos = Math.cos(this.angle);
    sin = Math.sin(this.angle);
    defaultRGBModel = ColorModel.getRGBdefault();
  }

  private void transform(int x, int y, double out[]) {
    out[0] = (x * cos) + (y * sin);
    out[1] = (y * cos) - (x * sin);
  }

  private void transformBack(int x, int y, double out[]) {
    out[0] = (x * cos) - (y * sin);
    out[1] = (y * cos) + (x * sin);
  }

  public void transformSpace(Rectangle rect) {
    double out[] = new double[2];
    double minx = Double.MAX_VALUE;
    double miny = Double.MAX_VALUE;
    double maxx = Double.MIN_VALUE;
    double maxy = Double.MIN_VALUE;
    int w = rect.width;
    int h = rect.height;
    int x = rect.x;
    int y = rect.y;
    for (int i = 0; i < 4; i++) {
      switch (i) {
        case 0:
          transform(x + 0, y + 0, out);
          break;
        case 1:
          transform(x + w-1, y + 0, out);
          break;
        case 2:
          transform(x + 0, y + h-1, out);
          break;
        case 3:
          transform(x + w-1, y + h-1, out);
          break;
      }
      minx = Math.min(minx, out[0]);
      miny = Math.min(miny, out[1]);
      maxx = Math.max(maxx, out[0]);
      maxy = Math.max(maxy, out[1]);
    }
/*
    rect.x = (int) Math.floor(minx);
    rect.y = (int) Math.floor(miny);
    rect.width = (int) Math.ceil(maxx) - rect.x;
    rect.height = (int) Math.ceil(maxy) - rect.y;
*/
    rect.x = (int) Math.round(minx);
    rect.y = (int) Math.round(miny);
    rect.width = (int) Math.round(maxx) - rect.x+1;
    rect.height = (int) Math.round(maxy) - rect.y+1;
  }

  /**
   * Tell the consumer the new dimensions based on our
   * rotation of coordinate space.
   * @see ImageConsumer#setDimensions
   */
  public void setDimensions(int width, int height) {
    originalSpace = new Rectangle(0, 0, width, height);
    rotatedSpace = new Rectangle(0, 0, width, height);
    transformSpace(rotatedSpace);
    inPixels = new int[originalSpace.width * originalSpace.height];
    consumer.setDimensions(rotatedSpace.width, rotatedSpace.height);
  }

  /**
   * Tell the consumer that we use the defaultRGBModel color model
   * NOTE: This overrides whatever color model is used underneath us.
   * @param model contains the color model of the image or filter
   * beneath us (preceding us)
   * @see ImageConsumer#setColorModel
   */
  public void setColorModel(ColorModel model) {
    consumer.setColorModel(defaultRGBModel);
  }

  /**
   * Set the pixels in our image array from the passed
   * array of bytes. Xlate the pixels into our default
   * color model (RGB).
   * @see ImageConsumer#setPixels
   */
  public void setPixels(int x, int y, int w, int h,
                        ColorModel model, byte pixels[],
                        int off, int scansize) {
    int index = y * originalSpace.width + x;
    int srcindex = off;
    int srcinc = scansize - w;
    int indexinc = originalSpace.width - w;
    for (int dy = 0; dy < h; dy++) {
      for (int dx = 0; dx < w; dx++) {
        inPixels[index++] = model.getRGB(pixels[srcindex++] & 0xff);
      }
      srcindex += srcinc;
      index += indexinc;
    }
  }

  /**
   * Set the pixels in our image array from the passed
   * array of integers. Xlate the pixels into our default
   * color model (RGB).
   * @see ImageConsumer#setPixels
   */
  public void setPixels(int x, int y, int w, int h,
                        ColorModel model, int pixels[],
                        int off, int scansize) {
    int index = y * originalSpace.width + x;
    int srcindex = off;
    int srcinc = scansize - w;
    int indexinc = originalSpace.width - w;
    for (int dy = 0; dy < h; dy++) {
      for (int dx = 0; dx < w; dx++) {
        inPixels[index++] = model.getRGB(pixels[srcindex++]);
      }
      srcindex += srcinc;
      index += indexinc;
    }
  }

  /**
   * Notification that the image is complete and there will
   * be no further setPixel calls.
   * @see ImageConsumer#imageComplete
   */
  public void imageComplete(int status) {
    if (status == IMAGEERROR || status == IMAGEABORTED) {
      consumer.imageComplete(status);
      return;
    }
    double point[] = new double[2];
    int srcwidth = originalSpace.width;
    int srcheight = originalSpace.height;
    int outwidth = rotatedSpace.width;
    int outheight = rotatedSpace.height;
    int outx, outy, srcx, srcy;
    outPixels = new int[outwidth * outheight];
    outx = rotatedSpace.x;
    outy = rotatedSpace.y;
    int index = 0;
    for (int y = 0; y < outheight; y++) {
      for (int x = 0; x < outwidth; x++) {
        // find the originalSpace point
        transformBack(outx + x, outy + y, point);
        srcx = (int) Math.round(point[0]);
        srcy = (int) Math.round(point[1]);
        // if this point is within the original image
        // retreive its pixel value and store in output
        // else write a zero into the space. (0 alpha = transparent)
        if (srcx < 0 || srcx >= srcwidth ||
          srcy < 0 || srcy >= srcheight) {
          outPixels[index++] = 0;
        }
        else {
          outPixels[index++] = inPixels[(srcy * srcwidth) + srcx];
        }
      }
    }
    // write the entire new image to the consumer
    consumer.setPixels(0, 0, outwidth, outheight, defaultRGBModel,
                       outPixels, 0, outwidth);
    // tell consumer we are done
    consumer.imageComplete(status);
  }

  public static void main(String args[]) {
    final Image unrotated = Toolkit.getDefaultToolkit().getImage("ASL/images/Climb1d.gif");

    ImageFilter filter = new RotateFilter(-60.0);
    ImageProducer producer = new FilteredImageSource(unrotated.getSource(), filter);
    final Image rotated = new javax.swing.JLabel().createImage(producer);
    javax.swing.JFrame f = new javax.swing.JFrame() {
      private static final long serialVersionUID = 1L;

      public void paint(Graphics g) {
        g.setColor(Color.blue);
        g.fillRect(0, 0, getSize().width, getSize().height);
        g.drawImage(rotated, 100, 100, this);
        g.drawImage(unrotated, 0, 0, this);
        g.drawImage(unrotated,
                    100 + unrotated.getWidth(this),
                    unrotated.getHeight(this),
                    100, 0,
                    0, 0,
                    0 + unrotated.getWidth(this),
                    unrotated.getHeight(this),
                    this);
      }
    };
    f.setSize(300, 300);
    f.setVisible(true);
  }
}
