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

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 com.sun.glass.events.KeyEvent;

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 MacApplication extends Application {
    private boolean isEmbedded = false;
    private long shareContextPtr = 0;

    native private static void _initIDs();
    static {
        Application.loadNativeLibrary();
        _initIDs();
    }

    Menu appleMenu;

    native void _runLoop(String args[], ClassLoader classLoader, Launchable launchable,
                         boolean isEmbedded, long shareContextPtr);
    protected void runLoop(String args[], Launchable launchable) {
        isEmbedded =
            AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                public Boolean run() {
                    return Boolean.getBoolean("javafx.macosx.embedded");
                }
            });
   
        shareContextPtr =
            AccessController.doPrivileged(new PrivilegedAction<Long>() {
		public Long run() {
                    long ptr = 0;
                    Map deviceDetails = getDeviceDetails();
                    if (deviceDetails != null) {
                        Object value = deviceDetails.get("shareContextPtr");
                        if (value != null) {
                            ptr = ((Long)value).longValue();
                        }
                    }
                    return ptr;
                }
            });

        ClassLoader classLoader = MacApplication.class.getClassLoader();
        _runLoop(args, classLoader, launchable, isEmbedded, shareContextPtr);
    }

    native private void _finishTerminating();
    @Override
    protected void finishTerminating() {
        setEventThread(null);
        if (!isEmbedded) {
            _finishTerminating();
        }

        super.finishTerminating();
    }

    // Called from the native code
    private void setEventThread() {
        setEventThread(Thread.currentThread());
    }

    @Override native protected Object _enterNestedEventLoop();
    @Override native protected void _leaveNestedEventLoop(Object retValue);

    public void installAppleMenu(MenuBar menubar) {
        this.appleMenu = createMenu("Apple");
        
        MenuItem quitMenu = createMenuItem("Quit "+getName(), new MenuItem.Callback() {
            @Override public void action() {
                Application.EventHandler eh = getEventHandler();
                if (eh != null) {
                    eh.handleQuitAction(Application.GetApplication(), System.nanoTime());
                }
            }
        }, 'q', KeyEvent.MODIFIER_COMMAND);
        this.appleMenu.add(quitMenu);

        menubar.add(this.appleMenu);
    }
    
    public Menu getAppleMenu() {
        return this.appleMenu;
    }

    @Override public void installDefaultMenus(MenuBar menubar) {
        installAppleMenu(menubar);
    }


    // FACTORY METHODS

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

    @Override public Window createWindow(long parent) {
        // return new MacWindow(parent);
        throw new RuntimeException("child windows aren't supported on Mac");
    }

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

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

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

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

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

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

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

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

    @Override public Robot createRobot() {
        return new MacRobot();
    }

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

    @Override protected Screen staticScreen_getMainScreen() {
        return MacScreen.getMainScreen_impl();
    }

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

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

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

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

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

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

    @Override protected String[] staticCommonDialogs_showFileChooser(Window owner, String folder, String title, int type,
                                                     boolean multipleMode, ExtensionFilter[] extensionFilters) {
        return MacCommonDialogs.showFileChooser_impl(owner, folder, title, type, multipleMode, extensionFilters);
    }

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

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

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

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

    @Override native protected void _invokeAndWait(Runnable runnable);

    @Override native protected void _invokeLater(Runnable runnable);

    @Override native protected void _postOnEventQueue(Runnable runnable);

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