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

package com.sun.javafx.tk.quantum;

import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.scene.input.InputMethodHighlight;
import javafx.scene.input.InputMethodTextRun;

import com.sun.javafx.collections.TrackableObservableList;

/**
 *
 * @author naoto
 */
public class GlassPrismInputMethodEvent implements PrismEvent {
    ViewScene view;
    String text;
    int[] clauseBoundary;
    int[] attrBoundary;
    byte[] attrValue;
    int commitCount;
    int cursorPos;

    // TODO: Define these somewhere else. It is Windows specific for now.
    private final static byte ATTR_INPUT                 = 0x00;
    private final static byte ATTR_TARGET_CONVERTED      = 0x01;
    private final static byte ATTR_CONVERTED             = 0x02;
    private final static byte ATTR_TARGET_NOTCONVERTED   = 0x03;
    private final static byte ATTR_INPUT_ERROR           = 0x04;

    public void handleInputMethodEvent(final long time, final String text,
            final int[] clauseBoundary,
            final int[] attrBoundary, final byte[] attrValue,
            final int commitCount, final int cursorPos) {

    }
    
    protected GlassPrismInputMethodEvent(final ViewScene view, String text,
            int[] clauseBoundary,
            int[] attrBoundary, byte[] attrValue,
            int commitCount, int cursorPos) {
        this.view = view;
        this.text = (text == null ? "" : text);
        this.clauseBoundary = clauseBoundary;
        this.attrBoundary = attrBoundary;
        this.attrValue = attrValue;
        this.commitCount = commitCount;
        this.cursorPos = cursorPos;
    }

    protected ViewScene view() {
        return this.view;
    }
    
    protected ObservableList<InputMethodTextRun> getComposed() {
        ObservableList<InputMethodTextRun> composed = new TrackableObservableList<InputMethodTextRun>() {
            @Override
            protected void onChanged(Change<InputMethodTextRun> c) {

            }
        };

        if (commitCount < text.length()) {
            if (clauseBoundary == null) {
                // Create one single segment as UNSELECTED_RAW
                composed.add(InputMethodTextRun.impl_inputMethodTextRun(
                        text.substring(commitCount),
                        InputMethodHighlight.UNSELECTED_RAW));
            } else {
                for (int current = 0; current < clauseBoundary.length-1; current++) {
                    if (clauseBoundary[current] < commitCount) {
                        continue;
                    }

                    InputMethodHighlight highlight;
                    switch (getAttrValue(clauseBoundary[current])) {
                    case ATTR_TARGET_CONVERTED:
                        highlight = InputMethodHighlight.SELECTED_CONVERTED;
                        break;
                    case ATTR_CONVERTED:
                        highlight = InputMethodHighlight.UNSELECTED_CONVERTED;
                        break;
                    case ATTR_TARGET_NOTCONVERTED:
                        highlight = InputMethodHighlight.SELECTED_RAW;
                        break;
                    case ATTR_INPUT:
                    case ATTR_INPUT_ERROR:
                    default:
                        highlight = InputMethodHighlight.UNSELECTED_RAW;
                        break;
                    }
                    composed.add(InputMethodTextRun.impl_inputMethodTextRun(
                            text.substring(clauseBoundary[current],
                                           clauseBoundary[current+1]),
                            highlight));
                }
            }
        }
        return composed;
    }
    
    protected String getCommitted() {
        return text.substring(0, commitCount);
    }
    
    protected int getCursorPos() {
        return this.cursorPos;
    }

    private byte getAttrValue(int pos) {
        byte retVal = ATTR_INPUT_ERROR;

        if (attrBoundary != null) {
            for (int current = 0; current < attrBoundary.length-1; current++) {
                if (pos >= attrBoundary[current] &&
                    pos < attrBoundary[current+1]) {
                    retVal = attrValue[current];
                    break;
                }
            }
        }

        return retVal;
    }
}
