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

This file is part of Mysaifu JVM.

Mysaifu JVM 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.

Mysaifu JVM 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 Mysaifu JVM; 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.Graphics;
import java.awt.Image;
import java.awt.image.ImageObserver;
import java.awt.image.ImageProducer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Set;


/**
 * Imageの基底クラス
 */
public abstract class WCEImage extends Image {
	/**
	 * BitBlt()で描画する
	 */
	public static final int BIT_BLT = 0;
	
	/**
	 * TransparentBlt()で描画する
	 */
	public static final int TRANSPARENT_BLT = 1;
	
	/**
	 * AlphaBlend()で描画する
	 */
	public static final int ALPHA_BLEND = 2;

	/**
	 * イメージの幅
	 */
	private int width = -1;
	
	/**
	 * イメージの高さ
	 */
	private int height = -1;
	
	/**
	 * イメージの状態フラグ
	 */
	private int flags;
	
	/**
	 * イメージのプロパティ
	 */
	private Hashtable props;
	
	/**
	 * ImageObserver
	 */
	private Set imageObservers = new HashSet();
	
	/**
	 * このImageに関連付けられたビットマップハンドル
	 */
	protected int bitmapHandle;
	
	/**
	 * ImageProducer
	 */
	protected ImageProducer source;
	
	/**
	 * イメージの幅とサイズを設定する
	 */
	protected void setDimension(int width, int height) {
		synchronized (this) {
			this.width = width;
			this.height = height;
			
			// フラグを設定する
			setFlags(getFlags() | ImageObserver.WIDTH | ImageObserver.HEIGHT);
		}
		
		// 各 ImageObserver に通知する
		notifyImageObservers(ImageObserver.WIDTH | ImageObserver.HEIGHT, 0, 0, width, height);
	}
	
	/**
	 * イメージの幅を返す。
	 */
	public int getWidth() {
		return this.width;
	}
	
	/**
	 * イメージの幅を返す。
	 */
	public int getWidth(ImageObserver observer) {
		addImageObserver(observer);
		return getWidth();
	}
	
	/**
	 * イメージの高さを返す
	 */
	public int getHeight() {
		return this.height;
	}

	/**
	 * イメージの高さを返す
	 */
	public int getHeight(ImageObserver observer) {
		addImageObserver(observer);
		return getHeight();
	}

	/**
	 * ImageObserverを追加する
	 */
	protected void addImageObserver(ImageObserver io) {
		if (io != null) {
			synchronized (this.imageObservers) {
				this.imageObservers.add(io);
			}
		}
	}

	public Object getProperty(String name, ImageObserver observer) {
		if (this.props == null) {
			return UndefinedProperty;
		} else {
			return props.get(name);
		}
	}

	/**
	 * このイメージの状態を返す
	 */
	int checkImage(ImageObserver observer) {
		addImageObserver(observer);
		return this.flags;
	}
	
	protected void finalize() {
		// システムリソースを開放する
		flush();
	}

	/**
	 * このImageに関連付けられたウインドウハンドルを返す。
	 */
	protected int getWindowHandle() {
		return 0;	// HWND == NULL (スクリーン全体)
	}
	
	/**
	 * このImageに関連付けられたビットマップハンドルを返す。
	 */
	public int getBitmapHandle() {
		if (this.bitmapHandle == 0) {
			this.bitmapHandle = createBitmapHandle(getWindowHandle());
		}
		return this.bitmapHandle;
	}
	
	/**
	 * ビットマップを作成する。
	 *
	 * @param	windowHandle			ウインドウハンドル
	 * @return	ビットマップハンドル。作成できなかった場合は0
	 *
	 */
	protected abstract int createBitmapHandle(int windowHandle);
	
	public ImageProducer getSource() {
		if (this.source == null) {
			this.source = new WCEImageProducer(this);
		}
		return this.source;
	}
	
	
	public Graphics getGraphics() {
		// このクラスはGraphicsを返さない
		return null;
	}
	
	/**
	 * このインスタンスに関連付けられたネイティブリソースを削除する
	 */
	public void flush() {
		deleteNativeBitmapHandle(this.bitmapHandle);
	}
	
	/**
	 * ビットマップを削除する
	 *
	 * @param	bitmapHandle			削除対象となるビットマップハンドル
	 * @return	削除に成功した場合はtrue。
	 */
	protected native boolean deleteNativeBitmapHandle(int bitmapHandle);
	
	/**
	 * 指定されたフラグの設定／解除を行う
	 * ここで設定した値が checkImage() メソッドの返り値になる。
	 *
	 * @param
	 */
	protected void setFlags(int flag) {
		this.flags = flag;
	}

	protected int getFlags() {
		return this.flags;
	}

	/**
	 * 登録ざれたImageObserverに通知する
	 */
	protected void notifyImageObservers(int flags, int x, int y, int width, int height) {
		// System.err.println("WCEImage.notifyImageObservers() called. flags=" + flags);
		
		// デッドロックを避けるため、synchronized ブロック外で imageUpdate()を呼び出す
		List removeList = new ArrayList();
		ImageObserver[] observers = null;
		synchronized (this.imageObservers) {
			observers = (ImageObserver[]) this.imageObservers.toArray(new ImageObserver[0]);
		}
		if (observers != null) {
			for (int i = 0; i < observers.length; ++i) {
				ImageObserver observer = observers[i];
				if (observer != null) {
					if (! observer.imageUpdate(this, flags, x, y, width, height)) {
						// もう通知は不要
						removeList.add(observer);
					}
				}
			}
		}
		
		// 通知が不要になったImageObserverを削除する
		synchronized (this.imageObservers) {
			for (int i = 0; i < removeList.size(); ++i) {
				this.imageObservers.remove(removeList.get(i));
			}
		}
		
		// System.err.println("\tWCEImage.notifyImageObservers() return.");
	}
	
	/**
	 * 推奨描画APIを返す
	 */
	public int getPreferredBltAPI() {
		// デフォルトは BitBlt()
		return BIT_BLT;
	}
	
	/**
	 * 透明色を返す。
	 * 返された値は、Windows APIのCOLORREF型 (0x00BBGGRR)となる。
	 * {@link #getPreferredBltAPI()}が{@link BIT_BLT}を返す場合にのみ意味のある値を返す。
	 */
	public int getTransparentColor() {
		// デフォルトでは意味のある値を返さない。
		return 0;
	}
}
