/*
 * Java-Gnome Bindings Library
 *
 * Copyright 1998-2004 the Java-Gnome Team, all rights reserved.
 *
 * The Java-Gnome bindings library is free software distributed under
 * the terms of the GNU Library General Public License version 2.
 */

package org.gnu.gdk;

import org.gnu.glib.GObject;

/**
 * TODO:
 *	wrap many methods.
 *	implement new methods like getTitle, getDimension, ... using attributes field.
 *	Look through the window events model.
 */
public class Window extends Drawable {

	// not a good idea, native accesors for attributes are already present in this class
	//private WindowAttr attributes;

	public Window(int handle) {
		super(handle);
	}

	/*public Window(org.gnu.gdk.WindowAttr attributes, int attributesMask){
		// is -1 a null value?
		// does it accept null?
		handle=Window.gdk_window_new(,attributes.getHandle(),attributesMask);
		//this.attributes=attributes;
	}*/

	public Window(Window parent, WindowAttr attributes, int attributesMask) {
		super(gdk_window_new(parent.getHandle(), attributes.getHandle(), attributesMask));
	}

	public void destroy() {
		Window.gdk_window_destroy(getHandle());
	}

	// if the window returned by the native is null, 
	// how do we know it?
	
	/**
	* Obtains the window underneath the mouse pointer, returning the location of that window in win_x, win_y. 
	* Returns NULL if the window under the mouse pointer is not known to GDK (for example, belongs to another application).
	* 
	* @param x X position of the window.
	* @param y Y position of the window.
	* @return The window at the specified location.
	*/
	public Window getWindowAt(int x, int y) {
		int X[] = new int[1];
		int Y[] = new int[1];
		X[0] = x;
		Y[0] = y;
		int hndl = Window.gdk_window_at_pointer(X, Y);
		GObject obj = retrieveGObject(hndl);
		if (null != obj)
			return (Window)obj;
		return new Window(hndl);
	}

	/**
	 * Raises the <code>window</code> to the top of the window stack (moves the window to the front of the Z-order). 
	 */
	public void show() {
		Window.gdk_window_show(getHandle());
	}

	/**
	 * For toplevel windows, withdraws them, so they will no longer be known to the window manager; 
	 * for all windows, unmaps them, so they won't be displayed.
	 */
	public void hide() {
		Window.gdk_window_hide(getHandle());
	}
	
	/**
	 * Withdraws a window (unmaps it and asks the window manager to forget about it).
	 */
	public void withdraw() {
		Window.gdk_window_withdraw(getHandle());
	}

	/**
	 * Shows a <code>GdkWindow</code> onscreen, but does not modify its stacking order. 
	 * In contrast, <code>show()</code> will raise the window to the top of the window stack.
	 */
	public void showUnraised() {
		Window.gdk_window_show_unraised(getHandle());
	}

	/**
	 * Repositions a window relative to its parent window. For toplevel windows, 
	 * window managers may ignore or modify the move; For child windows, the move will reliably succeed.
	 * 
	 * @param x new x position.
	 * @param y new y position.
	 * 
	 */
	public void move(int x, int y) {
		Window.gdk_window_move(getHandle(), x, y);
	}

	
	/**
	 * Resizes window; for toplevel windows, asks the window manager to resize the window. 
	 * The window manager may not allow the resize. Windows may not be resized below 1x1.
	 *
	 * @param width the new window width.
	 * @param height the new window height.
	 */
	public void resize(int width, int height) {
		Window.gdk_window_resize(getHandle(), width, height);
	}

	
	/**
	 * Equivalent to calling <code>move()</code> and <code>resize()</code>, 
	 * except that both operations are performed at once, avoiding strange visual effects 
	 * (i.e. the user may be able to see the window first move, 
	 * then resize, if you don't use <code>moveAndResize()</code>).
	 * 
	 * @param x the new x position.
	 * @param y the new y position.
	 * @param width the new width.
	 * @param height the new height.
	 */
	public void moveAndResize(int x, int y, int width, int height){
		Window.gdk_window_move_resize(getHandle(), x, y, width, height);
	}

	/**
	 * Reparents window into the given <code>parent</code>. 
	 * The window being reparented will be unmapped as a side effect.
	 * 
	 * @param parent the new parent to move window into.
	 * @param x X location inside the new parent.
	 * @param y Y location inside the new parent.
	 * 
	 */
	public void reparent(org.gnu.gdk.Window parent, int x, int y) {
		Window.gdk_window_reparent(getHandle(), parent.getHandle(), x, y);
	}


	/**
	 * Clears an entire <code>window</code> to the background color or background pixmap.
	 */
	public void clear() {
		Window.gdk_window_clear(getHandle());
	}

	// it will generate an event in the future.
	// gdk_window_clear_area will not be used.
	public void clearArea(int x, int y, int width, int height) {
		Window.gdk_window_clear_area_e(getHandle(), x, y, width, height);
	}

	public void raise() {
		Window.gdk_window_raise(getHandle());
	}

	public void lower() {
		Window.gdk_window_lower(getHandle());
	}

	// How do i set the timeStamp?
	public void getKeyboardFocus() {
		//Window.gdk_window_focus(handle, timeStamp??);
	}

	public void setUnmanaged(boolean unmanaged) {
		Window.gdk_window_set_override_redirect(getHandle(), unmanaged);
	}

	public void scrollContent(int x, int y) {
		Window.gdk_window_scroll(getHandle(), x, y);
	}

	// to unset the mask mask should be null;
	//public void unsetBitmapMask(null, ...);
	public void setBitmapMask(org.gnu.gdk.Bitmap mask, int x, int y) {
		Window.gdk_window_shape_combine_mask(getHandle(), mask.getHandle(), x, y);
	}

	//the same as above.
	public void setRegionMask(org.gnu.gdk.Region region, int x, int y) {
		Window.gdk_window_shape_combine_region(getHandle(), region.getHandle(), x, y);
	}

	public void setChildMask(boolean masked) {
		if (masked)
			Window.gdk_window_set_child_shapes(getHandle());
	}

	public boolean isVisible() {
		return Window.gdk_window_is_visible(getHandle());
	}

	public boolean isViewable() {
		return Window.gdk_window_is_viewable(getHandle());
	}

	public WindowState getWindowState() {
		return WindowState.intern(Window.gdk_window_get_state(getHandle()));
	}

	// According to the api, not very usefull, so leave it unimplemented.
	//public void setStaticGravity(boolean static){
	//} 	

	// It seems to be not usefull. NativeWindow is not implemented.
	//public static org.gnu.gdk.Window wrapNativeWindow(org.gnu.gdk.NativeWindow nw){}

	public void setHint(WindowTypeHint hint) {
		// if the window is already mapped it has no effect.
		if (hint != null && !isVisible())
			Window.gdk_window_set_type_hint(getHandle(), hint.getValue());
	}

	// ModalWindow will extend this class and implement this method.
	//public void setModal(boolean modal)
	//	Window.gdk_window_set_modal_hint(....);
	//}

	//not sure if it is going to be implemented.
	//public void setGeometryHints(){}

	/** Drawing Functions **/

	public void drawPoint(GC gcontext, int x, int y) {
		Window.gdk_draw_point(gcontext.getHandle(), x, y);
	}

	public void drawPoint(int x, int y) {
		drawPoint(org.gnu.gdk.GC.getDefaultGC(this), x, y);
	}

	public void drawLine(GC gcontext, int x1, int y1, int x2, int y2) {
		Window.gdk_draw_line(gcontext.getHandle(), x1, y1, x2, y2);
	}

	public void drawLine(int x1, int y1, int x2, int y2) {
		drawLine(org.gnu.gdk.GC.getDefaultGC(this), x1, y1, x2, y2);
	}

	public static Window[] getTopLevelWindows() {
		org.gnu.glib.List l = new org.gnu.glib.List(Window.gdk_window_get_toplevels());
		Window wlist[] = new Window[l.length()];
		for (int i = 0; i < l.length(); i++) {
			wlist[i] = new Window(l.next());
		}
		return wlist;
	}
	
	/**
	 * Retrieve the current width of the Window.
	 * 
	 * @return The width of the Window.
	 */
	public int getWidth() {
		int [] x = new int[1];
		int [] y = new int[1];
		int [] width = new int[1];
		int [] height = new int[1];
		int [] depth = new int[1];
		Window.gdk_window_get_geometry(getHandle(), x, y, width, height, depth);
		return width[0];
	}
	
	/**
	 * Retrieve the current height of the Window.
	 * 
	 * @return The height of the Window.
	 */
	public int getHeight() {
		int [] x = new int[1];
		int [] y = new int[1];
		int [] width = new int[1];
		int [] height = new int[1];
		int [] depth = new int[1];
		Window.gdk_window_get_geometry(getHandle(), x, y, width, height, depth);
		return height[0];
	}

	/****************************************
	 * BEGINNING OF GENERATED CODE
	 ****************************************/
	native static final protected int gdk_window_new(int parent, int attriutes, int attributesMask);
	native static final protected int gdk_window_get_window_type(int window);
	native static final protected void gdk_window_destroy(int window);
	native static final protected int gdk_window_at_pointer(int[] winX, int[] winY);
	native static final protected void gdk_window_show(int window);
	native static final protected void gdk_window_hide(int window);
	native static final protected void gdk_window_withdraw(int window);
	native static final protected void gdk_window_show_unraised(int window);
	native static final protected void gdk_window_move(int window, int x, int y);
	native static final protected void gdk_window_resize(int window, int width, int height);
	native static final protected void gdk_window_move_resize(int window, int x, int y, int width, int height);
	native static final protected void gdk_window_reparent(int window, int newParent, int x, int y);
	native static final protected void gdk_window_clear(int window);
	native static final protected void gdk_window_clear_area(int window, int x, int y, int width, int height);
	native static final protected void gdk_window_clear_area_e(int window, int x, int y, int width, int height);
	native static final protected void gdk_window_raise(int window);
	native static final protected void gdk_window_lower(int window);
	native static final protected void gdk_window_focus(int window, int timestamp);
	native static final protected void gdk_window_set_user_data(int window, int userData);
	native static final protected void gdk_window_set_override_redirect(int window, boolean overrideRedirect);
	native static final protected void gdk_window_scroll(int window, int dx, int dy);
	native static final protected void gdk_window_shape_combine_mask(int window, int shape_mask, int offsetX, int offsetY);
	native static final protected void gdk_window_shape_combine_region(int window, int shape_region, int offsetX, int offsetY);
	native static final protected void gdk_window_set_child_shapes(int window);
	native static final protected void gdk_window_merge_child_shapes(int window);
	native static final protected boolean gdk_window_is_visible(int window);
	native static final protected boolean gdk_window_is_viewable(int window);
	native static final protected int gdk_window_get_state(int window);
	native static final protected boolean gdk_window_set_static_gravities(int window, boolean useStatic);
	native static final protected int gdk_window_foreign_new(int anid);
	native static final protected void gdk_window_set_type_hint(int window, int hint);
	native static final protected void gdk_window_set_modal_hint(int window, boolean modal);
	native static final protected void gdk_window_set_geometry_hints(int window, int geometry, int flags);
	native static final protected void gdk_window_begin_paint_rect(int window, int rectangle);
	native static final protected void gdk_window_begin_paint_region(int window, int region);
	native static final protected void gdk_window_end_paint(int window);
	native static final protected void gdk_window_set_title(int window, String title);
	native static final protected void gdk_window_set_role(int window, String role);
	native static final protected void gdk_window_set_transient_for(int Window, int leader);
	native static final protected void gdk_window_set_background(int window, int color);
	native static final protected void gdk_window_set_back_pixmap(int window, int pixmap, boolean parentRelative);
	native static final protected void gdk_window_set_cursor(int window, int cursor);
	native static final protected void gdk_window_get_geometry(int window, int[] x, int[] y, int[] width, int[] height, int[] depth);
	native static final protected void gdk_window_get_position(int window, int[] x, int[] y);
	native static final protected int gdk_window_get_origin(int window, int[] x, int[] y);
	native static final protected void gdk_window_get_root_origin(int window, int[] x, int[] y);
	native static final protected void gdk_window_get_frame_extents(int window, int rect);
	native static final protected int gdk_window_get_parent(int window);
	native static final protected int gdk_window_get_toplevel(int window);
	native static final protected int gdk_window_get_children(int window);
	native static final protected int gdk_window_peek_children(int window);
	native static final protected int gdk_window_get_events(int window);
	native static final protected void gdk_window_set_events(int window, int eventMask);
	native static final protected void gdk_window_set_icon_list(int window, int pixbufs);
	native static final protected void gdk_window_set_icon(int window, int iconWindow, int pixmap, int mask);
	native static final protected void gdk_window_set_icon_name(int window, String name);
	native static final protected void gdk_window_set_group(int window, int leader);
	native static final protected void gdk_window_set_decorations(int window, int decorations);
	native static final protected void gdk_window_set_functions(int window, int functions);
	native static final protected int gdk_window_get_toplevels();
	native static final protected void gdk_window_iconify(int window);
	native static final protected void gdk_window_deiconify(int window);
	native static final protected void gdk_window_stick(int window);
	native static final protected void gdk_window_unstick(int window);
	native static final protected void gdk_window_maximize(int window);
	native static final protected void gdk_window_unmaximize(int window);
	native static final protected void gdk_window_register_dnd(int window);
	native static final protected void gdk_window_begin_resize_drag(int window, int edge, int button, int rootX, int rootY, int timestamp);
	native static final protected void gdk_window_begin_move_drag(int window, int button, int rootX, int rootY, int timestamp);
	native static final protected void gdk_window_invalidate_rect(int window, int rect, boolean invalidateChildren);
	native static final protected void gdk_window_invalidate_region(int window, int region, boolean invalidateChildren);
	native static final protected int gdk_window_get_update_area(int window);
	native static final protected void gdk_window_freeze_updates(int window);
	native static final protected void gdk_window_thaw_updates(int window);
	native static final protected void gdk_window_process_all_updates();
	native static final protected void gdk_window_process_updates(int window, boolean updateChildren);
	native static final protected void gdk_window_set_debug_updates(boolean setting);
	native static final protected void gdk_window_constrain_size(int geometry, int flags, int width, int height, int[] newWidth, int[] newHeight);
	native static final protected void gdk_window_get_internal_paint_info(int window, int[] realDrawable, int[] xOffset, int[] yOffset);
	native static final protected void gdk_draw_point(int gc, int x, int y);
	native static final protected void gdk_draw_line(int gc, int x1, int y1, int x2, int y2);
	native static final protected void gdk_draw_rectangle(int gc, boolean filled, int x, int y, int width, int height);
	native static final protected void gdk_draw_arc(int gc, boolean filled, int x, int y, int width, int height, int angle1, int angle2);
	/****************************************
	 * END OF GENERATED CODE
	 ****************************************/
}
