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

This file is part of GNU Classpath.

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;

/**
 * Base class of Image.
 */
public abstract class WCEImage extends Image
{
  /**
   * use BitBlt() to draw the image.
   */
  public static final int BIT_BLT = 0;
	
  /**
   * use TransparentBlt() to draw the image.
   */
  public static final int TRANSPARENT_BLT = 1;
	
  /**
   * use AlphaBlend() to draw the image.
   */
  public static final int ALPHA_BLEND = 2;

  /**
   * width of this image.
   */
  private int width = -1;
	
  /**
   * height of this image.
   */
  private int height = -1;
	
  /**
   * status flag of this image.
   */
  private int flags;
	
  /**
   * property of this image.
   */
  private Hashtable props;
	
  /**
   * ImageObserver
   */
  private Set imageObservers = new HashSet();
	
  /**
   * a native bitmap handle associated with this 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();
  }

  /**
   * add specified <code>ImageObserver</code>.
   */
  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);
    }
  }

  /**
   * returns status of this image.
   */
  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;
  }
}
