/*
 * Copyright (c) 2010, 2011, Oracle  and/or its affiliates. All rights reserved.
 */


package com.sun.javafx.tk.quantum;

import javafx.event.EventType;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseButton;
import javafx.scene.input.TransferMode;

import com.sun.glass.events.KeyEvent;
import com.sun.glass.events.MouseEvent;
import com.sun.glass.ui.Clipboard;

public class PrismEventUtils {

    private static EventType<javafx.scene.input.MouseEvent> glassMouseEventType(
            GlassPrismMouseEvent e) {
        
        switch (e.type()) {
            case MouseEvent.DOWN:
                return javafx.scene.input.MouseEvent.MOUSE_PRESSED;
            case MouseEvent.UP:
                return javafx.scene.input.MouseEvent.MOUSE_RELEASED;
            case MouseEvent.CLICK:
                return javafx.scene.input.MouseEvent.MOUSE_CLICKED;
            case MouseEvent.ENTER:
                return javafx.scene.input.MouseEvent.MOUSE_ENTERED;
            case MouseEvent.EXIT:
                return javafx.scene.input.MouseEvent.MOUSE_EXITED;
            case MouseEvent.MOVE:
                return javafx.scene.input.MouseEvent.MOUSE_MOVED;
            case MouseEvent.DRAG:
                return javafx.scene.input.MouseEvent.MOUSE_DRAGGED;
            case MouseEvent.WHEEL:
                throw new IllegalArgumentException("WHEEL event cannot "
                        + "be translated to MouseEvent, must be translated to "
                        + "ScrollEvent");
            default:
                throw new UnsupportedOperationException("unhandled MouseEvent type: " + e.type());
        }
    }

    private static EventType<javafx.scene.input.KeyEvent> glassKeyEventType(GlassPrismKeyEvent e) {
        switch (e.type()) {
            case KeyEvent.PRESS:
                return (javafx.scene.input.KeyEvent.KEY_PRESSED);
            case KeyEvent.RELEASE:
                return (javafx.scene.input.KeyEvent.KEY_RELEASED);
            case KeyEvent.TYPED:
                return (javafx.scene.input.KeyEvent.KEY_TYPED);
            default:
                return null;

        }
    }



    public static javafx.scene.input.MouseEvent glassMouseEventToFX(GlassPrismMouseEvent event) {
        int x = event.x();
        int y = event.y();
        int screenX = event.xAbs();
        int screenY = event.yAbs();
        MouseButton mouseButton;
        switch (event.button()) {
            case com.sun.glass.events.MouseEvent.BUTTON_LEFT:
                mouseButton = MouseButton.PRIMARY;
                break;
            case com.sun.glass.events.MouseEvent.BUTTON_RIGHT:
                mouseButton = MouseButton.SECONDARY;
                break;
            case com.sun.glass.events.MouseEvent.BUTTON_OTHER:
                mouseButton = MouseButton.MIDDLE;
                break;
            default:
                mouseButton = MouseButton.NONE;
                break;
        }
        int clickCount = event.clickCount();
        final int modifiers = event.modifiers();
        boolean isShiftDown = (modifiers & com.sun.glass.events.KeyEvent.MODIFIER_SHIFT) > 0;
        boolean isControlDown = (modifiers & com.sun.glass.events.KeyEvent.MODIFIER_CONTROL) > 0;
        boolean isAltDown = (modifiers & com.sun.glass.events.KeyEvent.MODIFIER_ALT) > 0;
        boolean isMetaDown = (modifiers & com.sun.glass.events.KeyEvent.MODIFIER_WINDOWS) > 0;
        boolean isPopupTrigger = event.isPopupTrigger();
        boolean primaryButtonDown = (modifiers & com.sun.glass.events.KeyEvent.MODIFIER_BUTTON_PRIMARY) > 0;
        boolean middleButtonDown = (modifiers & com.sun.glass.events.KeyEvent.MODIFIER_BUTTON_MIDDLE) > 0;
        boolean secondaryButtonDown = (modifiers & com.sun.glass.events.KeyEvent.MODIFIER_BUTTON_SECONDARY) > 0;
        boolean synthesized = event.isSynthesized();
        EventType<javafx.scene.input.MouseEvent> eventType = glassMouseEventType(event);

        return javafx.scene.input.MouseEvent.impl_mouseEvent (
            x, y,
            screenX, screenY,
            mouseButton,
            clickCount,
            isShiftDown,
            isControlDown,
            isAltDown,
            isMetaDown,
            isPopupTrigger,
            primaryButtonDown,
            middleButtonDown,
            secondaryButtonDown,
            synthesized,
            eventType
        );
    }

    public static javafx.scene.input.KeyEvent glassKeyEventToFX(GlassPrismKeyEvent event)  {
        int type = event.type();
        String chars = new String(event.characters());
        String text = chars; // TODO: this must be a text like "HOME", "F1", or "A"
        int code = event.key();
        final int modifiers = event.modifiers();
        boolean isShiftDown = (modifiers & com.sun.glass.events.KeyEvent.MODIFIER_SHIFT) > 0;
        boolean isControlDown = (modifiers & com.sun.glass.events.KeyEvent.MODIFIER_CONTROL) > 0;
        boolean isAltDown = (modifiers & com.sun.glass.events.KeyEvent.MODIFIER_ALT) > 0;
        boolean isMetaDown = (modifiers & com.sun.glass.events.KeyEvent.MODIFIER_WINDOWS) > 0;
        EventType<javafx.scene.input.KeyEvent> keyEventType = glassKeyEventType(event);

        return javafx.scene.input.KeyEvent.impl_keyEvent (
            null,
            chars,
            text,
            code,
            isShiftDown,
            isControlDown,
            isAltDown,
            isMetaDown,
            keyEventType
        );
    }

    public static javafx.scene.input.InputMethodEvent glassInputMethodEventToFX(GlassPrismInputMethodEvent event)  {
        return javafx.scene.input.InputMethodEvent.impl_inputMethodEvent (
            null, event.getComposed(), event.getCommitted(), event.getCursorPos(),
            javafx.scene.input.InputMethodEvent.INPUT_METHOD_TEXT_CHANGED
        );
    }

    private static DragEvent glassDragEventToFX(GlassDragEvent event, Dragboard board) {
        DragEvent e = DragEvent.impl_create((float)event.getX(), (float)event.getY(), (float)event.getXAbs(), (float)event.getYAbs(),
                convertToTransferMode(event.getRecommendedDropAction()), // transfer mode

                //NOTE: the dragboard is initially created based on the handleDragStart()'s ClipboardAssistant from Glass
                board != null ? board : event.getDragboard(), //XXX; verify if this is correct

                event);

        e.impl_setRecognizedEvent(event);
        return e;

    }

    public static DragEvent glassDragGestureToFX(GlassDragEvent event, Dragboard board)  {
        // we could check with the event.getType()
        return glassDragEventToFX(event, board);
    }

    public static DragEvent glassDragSourceEventToFX(GlassDragEvent event, Dragboard board)  {
        // we could check with the event.getType()
        return glassDragEventToFX(event, board);
   }

    public static DragEvent glassDropTargetEventToFX(GlassDragEvent event, Dragboard board)  {
        // we could check with the event.getType()
        return glassDragEventToFX(event, board);
    }

    public static TransferMode convertToTransferMode(int dropActions) {
        if (dropActions == Clipboard.ACTION_NONE) {
            return null;
        } else if (dropActions == Clipboard.ACTION_COPY) {
            return TransferMode.COPY;
        } else if (dropActions == Clipboard.ACTION_MOVE) {
            return TransferMode.MOVE;
        } else if (dropActions == Clipboard.ACTION_REFERENCE) {
            return TransferMode.LINK;
        } else if (dropActions == Clipboard.ACTION_COPY_OR_MOVE) {
            throw new IllegalArgumentException("PrismEventUtils.convertToTransferMode: ambiguous drop action: " + Integer.toHexString(dropActions));
        } else {
            throw new IllegalArgumentException("PrismEventUtils.convertToTransferMode: bad drop action: " + Integer.toHexString(dropActions));
        }
    }
}



