/*
 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 */
package com.sun.glass.ui.x11;

import com.sun.glass.events.KeyEvent;
import com.sun.glass.ui.Application;
import com.sun.glass.ui.CommonDialogs.ExtensionFilter;
import com.sun.glass.ui.Cursor;
import com.sun.glass.ui.Launchable;
import com.sun.glass.ui.Menu;
import com.sun.glass.ui.MenuBar;
import com.sun.glass.ui.MenuItem;
import com.sun.glass.ui.Pixels;
import com.sun.glass.ui.Pen;
import com.sun.glass.ui.Robot;
import com.sun.glass.ui.Screen;
import com.sun.glass.ui.Size;
import com.sun.glass.ui.Timer;
import com.sun.glass.ui.View;
import com.sun.glass.ui.Window;

import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.List;
import java.util.Map;

public class X11Application extends Application {
    Menu windowMenu;
    Menu editMenu;
    Menu fileMenu;

    protected static void initLibrary() {
        //Note: using an non-default native library name here.
        loadNativeLibrary("glass-x11");
    }

    long display = 0; // Native handle for display struct

    private native void _runLoop(String args[], Launchable launchable,
                                 long display, int screen, long visualID);

    protected void runLoop(final String args[], final Launchable launchable) {

        final Thread toolkitThread =
            AccessController.doPrivileged(new PrivilegedAction<Thread>() {
                public Thread run() {
                    Thread th = new Thread(new Runnable() {
                        public void run() {
                            int screen = -1;
                            long visualID = 0;

                            Map ds = getDeviceDetails();
                            if (ds != null) {
                                Object value;
                                value = ds.get("XDisplay");
                                if (value != null) {
                                    display = ((Long)value).longValue();
                                }
                                value = ds.get("XVisualID");
                                if (value != null) {
                                    visualID = ((Long)value).longValue();
                                }
                                value = ds.get("XScreenID");
                                if (value != null) {
                                    screen = ((Integer)value).intValue();
                                }
                            }
                            _runLoop(args, launchable, display, screen, visualID);
                        }
                    }, "X11NativeRunloopThread");

                    return th;
                }
            });
        setEventThread(toolkitThread);
        toolkitThread.start();
    }

    native void _terminate(boolean isEventThread);

    protected void finishTerminating() {
        final Thread toolkitThread = getEventThread();
        if (toolkitThread != null) {
            _terminate(Thread.currentThread().equals(toolkitThread));
            setEventThread(null);
        }
        super.finishTerminating();
    }

    @Override protected Object _enterNestedEventLoop() { return null; } //TODO
    @Override protected void _leaveNestedEventLoop(Object retValue) {} //TODO

    @Override public void installDefaultMenus(MenuBar menubar) {
        //ToDo: do we care ?
    }

    // FACTORY METHODS

    @Override public Window createWindow(Window owner, Screen screen, int styleMask) {
        return new X11Window(owner, screen, styleMask);
    }

    @Override public Window createWindow(long parent) {
        return new X11Window(parent);
    }

    @Override public View createView(Pen pen) {
        return new X11View(pen);
    }

    @Override public Cursor createCursor(int type) {
        return new X11Cursor(type);
    }

    @Override public Cursor createCursor(int x, int y, Pixels pixels) {
        return new X11Cursor(x, y, pixels);
    }

    @Override protected void staticCursor_setVisible(boolean visible) {
        X11Cursor.setVisible_impl(visible);
    }

    @Override protected Size staticCursor_getBestSize(int width, int height) {
        return X11Cursor.getBestSize_impl(width, height);
    }

    @Override public Pixels createPixels(int width, int height, ByteBuffer data) {
        return new X11Pixels(width, height, data);
    }

    @Override public Pixels createPixels(int width, int height, IntBuffer data) {
        return new X11Pixels(width, height, data);
    }

    @Override protected int staticPixels_getNativeFormat() {
        return X11Pixels.getNativeFormat_impl();
    }

    @Override public Robot createRobot() {
        throw new UnsupportedOperationException("not implmented");
        //return new X11Robot();
    }

    @Override protected Screen staticScreen_getDeepestScreen() {
        return X11Screen.getDeepestScreen_impl();
    }

    @Override protected Screen staticScreen_getMainScreen() {
        return X11Screen.getMainScreen_impl();
    }
    @Override protected Screen staticScreen_getScreenForLocation(int x, int y) {
        return X11Screen.getScreenForLocation_impl(x, y);
    }

    @Override protected Screen staticScreen_getScreenForPtr(long screenPtr) {
        return X11Screen.getScreenForPtr_impl(screenPtr);
    }

    @Override protected List<Screen> staticScreen_getScreens() {
        return X11Screen.getScreens_impl();
    }

    @Override public Timer createTimer(Runnable runnable) {
        return new X11Timer(runnable);
    }

    @Override protected int staticTimer_getMinPeriod() {
        return X11Timer.getMinPeriod_impl();
    }

    @Override protected int staticTimer_getMaxPeriod() {
        return X11Timer.getMaxPeriod_impl();
    }

    @Override protected String[] staticCommonDialogs_showFileChooser(Window owner, String folder, String title, int type,
                                                  boolean multipleMode, ExtensionFilter[] extensionFilters) {
        //TODO: implement owner window support
        return X11CommonDialogs.showFileChooser_impl(folder, title, type, multipleMode, extensionFilters);
    }

    @Override protected String staticCommonDialogs_showFolderChooser(Window owner, String folder, String title) {
        // TODO: handle owner, folder and title
        return X11CommonDialogs.showFolderChooser_impl();
    }

    @Override protected long staticView_getMultiClickTime() {
        return X11View.getMultiClickTime_impl();
    }

    @Override protected int staticView_getMultiClickMaxX() {
        return X11View.getMultiClickMaxX_impl();
    }

    @Override protected int staticView_getMultiClickMaxY() {
        return X11View.getMultiClickMaxY_impl();
    }

    @Override protected native void _invokeAndWait(Runnable runnable);

    @Override protected native void _invokeLater(Runnable runnable);

    @Override protected native void _postOnEventQueue(Runnable runnable);

    @Override
    public boolean supportsTransparentWindows() {
        return true;
    }
}
