/* WCEMemoryImage.java
   Copyright (C) 2005 Free Software Foundation, Inc.

This file is part of GNU Classpath.

GNU Classpath 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; version 2 of the License.

GNU Classpath 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 GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */

package gnu.java.awt.peer.wce;

import java.awt.AWTError;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.ColorModel;
import java.awt.image.ImageConsumer;
import java.awt.image.ImageObserver;
import java.awt.image.ImageProducer;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;


/**
 * ImageProducerの内容に基づくImage
 */
public class WCEMemoryImage extends WCEImage implements ImageConsumer {
	private ColorModel colorModel;
	private int[] imageData;
	
	public WCEMemoryImage(ImageProducer producer) {
		this.source = producer;
		this.source.startProduction(this);
	}
	
	/**
	 * イメージのサイズが確定した時点で、ImageProducerから呼び出される
	 */
	public void setDimensions(int width, int height) {
		super.setDimension(width, height);
	}
	
	/**
	 * イメージのプロパティが報告される
	 */
	public void setProperties(Hashtable props) {
		// 現在の実装では無視
	}
	
	/**
	 * カラーモデルが通知される
	 */
	public void setColorModel(ColorModel model) {
		this.colorModel = model;
	}
	
	/**
	 * ヒントが通知される
	 */
	public void setHints(int hintflags) {
		// 現在の実装では無視
	}
	
	/**
	 * イメージのピクセルが通知される
	 */
	public void setPixels(int x,
                      int y,
                      int w,
                      int h,
                      ColorModel model,
                      byte[] pixels,
                      int off,
                      int scansize) {
		throw new AWTError("byte[] pixels not supported.");
	}
	
	/**
	 * 
	 */
	public void setPixels(int x,
                      int y,
                      int w,
                      int h,
                      ColorModel model,
                      int[] pixels,
                      int off,
                      int scansize) {
		
		if (this.imageData == null) {
			// RGBイメージを格納するバッファを作成する
			int width = getWidth();
			int height = getHeight();
			if (width == -1 || height == -1) {
				// イメージサイズがわからない場合はリターン
				return;
			}
			this.imageData = new int[width * height];
		}
		
		// 使用するカラーモデルを決定する
		ColorModel currentModel = model;
		if (currentModel == null) {
			currentModel = this.colorModel;
		}
		
		if (ColorModel.getRGBdefault().equals(currentModel)) {
			// デフォルトRGB形式の場合、配列の内容を単純にコピーする
			if (x == 0 && y == 0) {
				System.arraycopy(pixels, off, this.imageData, y * scansize + x, w * h);
			} else {
				for (int j = y; j < h; ++j) {
					for (int i = x; i < w; ++i) {
						this.imageData[i + j * getWidth()] = pixels[i + j * scansize + off];
					}
				}
			}
		} else {
			// RGB形式に変換した後、内部バッファに入れていく
			for (int i = x; i < w; ++i) {
				for (int j = y; j < h; ++j) {
					// 標準RGB形式に変換する
					int pixel = pixels[off + j * scansize + i];
					int rgb = currentModel.getRGB(pixel);
					imageData[j * w + i] = rgb;	// w と scansize のどちらを使用するのが正しい？
				}
			}
		}
	}
	
	/**
	 * イメージの完成が通知される
	 */
	public void imageComplete(int status) {
		// System.err.println("WCEMemoryImage.imageComlete() called.");
		switch (status) {
			case STATICIMAGEDONE:
			case SINGLEFRAMEDONE:
			case SINGLEFRAME:		// GNU ClasspathのMemoryImageSourceはこのフラグを渡してくる
				{
					if (this.imageData != null) {
						// ネイティブビットマップを更新する
						updateNativeBitmap(getWindowHandle(),
										   getBitmapHandle(),
										   this.imageData,
										   getWidth(),
										   getHeight());
						
						// データを転送したのでバッファは不要になる
						this.imageData = null;
					}
					// フラグを設定する
					int flags = ((status & STATICIMAGEDONE) != 0)
									? ImageObserver.ALLBITS
									: ImageObserver.FRAMEBITS;
					setFlags(getFlags() | flags);
					
					// オブザーバに通知する
					notifyImageObservers(getFlags(), 0, 0, getWidth(), getHeight());
				}
				break;
			default:
				{
					// オブザーバにエラーを通知する
					setFlags(ImageObserver.ERROR | ImageObserver.ABORT);
					notifyImageObservers(getFlags(), -1, -1, -1, -1);
				}
				break;
		// System.err.println("\tWCEMemoryImage.imageComlete() return.");
		}
	}
	
	/**
	 * ネイティブビットマップの内容を更新する
	 */
	private native void updateNativeBitmap(int windowHandle,
										   int bitmapHandle,
										   int[] imageData,
										   int width,
										   int height);
	
	
	/**
	 * ビットマップを作成する。
	 *
	 * @param	windowHandle			ウインドウハンドル
	 * @return	デバイスコンテキスト。作成できなかった場合は0
	 *
	 */
	protected int createBitmapHandle(int windowHandle) {
		int hBitmap = 0;
		int width = getWidth();
		int height = getHeight();
		if (width >= 0 && height >= 0) {
			// イメージのサイズが決定されていれば、その時点でビットマップハンドルを作成する
			// イメージの内容はこの後も変更される可能性がある
			hBitmap = createNativeBitmapHandle(windowHandle,
										   width,
										   height);
		}
		return hBitmap;
	}
	
	/**
	 * ネイティブビットマップを作成する
	 */
	private native int createNativeBitmapHandle(int windowHandle,
												 int width,
												 int height);
}
