/*
 * Copyright 2006-2007 Queplix Corp.
 *
 * Licensed under the Queplix Public License, Version 1.1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.queplix.com/solutions/commercial-open-source/queplix-public-license/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */
package com.queplix.core.client.common.ui;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.EventPreview;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.InvocationException;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.KeyboardListenerCollection;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.queplix.core.client.app.rpc.DisplayableException;
import com.queplix.core.client.app.rpc.DisplayableStackTraceException;
import com.queplix.core.client.common.StringUtil;
import com.queplix.core.client.i18n.I18N;

/**
 * Helps to create dialogs
 *
 * @author Sergey Kozmin
 * @since 6 Oct 2006
 */
public class DialogHelper {
    private static final String BUTTON_STYLE = "styled_button";
    private static final String BORDER_STYLE = "ocp_border";
    private static final String DIALOG_STYLE = "ocp_area";
    private static final String CAPTION_STYLE = "ocp_text";
    private static final String QUESTION_IMAGE = "common/question_icon.gif";

    public static final int YES = 0x000001;
    public static final int NO = 0x000002;
    public static final int CANCEL = 0x000004;
    public static final int OK = 0x000008;
    public static final int LOG_OFF = 0x000010;

    private static EventPreview ep;
    private static final char YES_HOTKEY = 'Y';
    private static final char NO_HOTKEY = 'N';

    private DialogHelper() {
    }

    public static DialogBox showQuestionDialog(String question, int answerSet,
                                               int xPos, int yPos,
                                               final DialogAnswerListener listener) {
        return showQuestionDialog(question, answerSet, xPos, yPos, listener, 0);
    }

    public static DialogBox showQuestionDialog(String question,
                                               final int answerSet,
                                               int xPos, int yPos,
                                               final DialogAnswerListener listener,
                                               int buttonToFocus) {
        //todo make it static one-initialized
        final DialogBox questionBox = new DialogBox();
        questionBox.addStyleName(BORDER_STYLE);
        questionBox.addStyleName(DIALOG_STYLE);
        VerticalPanel questionPanel = new VerticalPanel();
        Label textLabel = new Label(question);
        textLabel.addStyleName(CAPTION_STYLE);
        HorizontalPanel buttonsPanel = new HorizontalPanel();

        Button buttonToF = null;
        Button current;
        current = addButton(answerSet, YES, I18N.getMessages().yes(), listener,
                questionBox, buttonsPanel, buttonToFocus);
        buttonToF = getButton(current, buttonToF);
        current = addButton(answerSet, NO, I18N.getMessages().no(), listener,
                questionBox, buttonsPanel, buttonToFocus);
        buttonToF = getButton(current, buttonToF);
        current = addButton(answerSet, CANCEL, I18N.getMessages().cancel(),
                listener, questionBox, buttonsPanel, buttonToFocus);
        buttonToF = getButton(current, buttonToF);
        current = addButton(answerSet, OK, I18N.getMessages().ok(), listener,
                questionBox, buttonsPanel, buttonToFocus);
        buttonToF = getButton(current, buttonToF);
        current = addButton(answerSet, LOG_OFF, I18N.getMessages().logOff(),
                listener, questionBox, buttonsPanel, buttonToFocus);
        buttonToF = getButton(current, buttonToF);

        HorizontalPanel imageAndText = new HorizontalPanel();
        imageAndText.add(new Image(QUESTION_IMAGE));
        imageAndText.add(textLabel);
        imageAndText.setSpacing(5);
        questionPanel.add(imageAndText);
        questionPanel.add(buttonsPanel);
        questionPanel.setCellHorizontalAlignment(buttonsPanel,
                HasHorizontalAlignment.ALIGN_CENTER);
        questionPanel.setWidth(StringUtil.pixelToSize(400));
        questionBox.setWidget(questionPanel);

        questionBox.show();
        questionBox.setPopupPosition(xPos - questionBox.getOffsetWidth() / 2,
                yPos - questionBox.getOffsetHeight() / 2);
        if(buttonToF != null) {
            buttonToF.setFocus(true);
        }

        ep = new EventPreview() {
            public boolean onEventPreview(
                    final com.google.gwt.user.client.Event e) {
                if(DOM.eventGetType(e) == com.google.gwt.user.client.Event
                        .ONKEYPRESS) {
                    char keyCode = (char) DOM.eventGetKeyCode(e);
                    int modifiers = KeyboardListenerCollection
                            .getKeyboardModifiers(e);
                    switch(Character.toUpperCase(keyCode)) {
                        case YES_HOTKEY:
                            if((answerSet & YES) != 0) {
                                proccessKeyPress(YES, questionBox, listener, e);
                                return false;
                            }
                            break;
                        case NO_HOTKEY:
                            if((answerSet & NO) != 0) {
                                proccessKeyPress(NO, questionBox, listener, e);
                                return false;
                            }
                            break;
                    }
                }
                return true;
            }
        };
        DOM.addEventPreview(ep);

        return questionBox;
    }

    private static void proccessKeyPress(int buttonCode, DialogBox questionBox,
                                         DialogAnswerListener listener,
                                         com.google.gwt.user.client.Event e) {
        DOM.removeEventPreview(ep);
        proccessButtonClick(buttonCode, questionBox, listener);
        DOM.eventPreventDefault(e);
    }

    private static Button getButton(Button newButton, Button previousButton) {
        if(newButton != null) {
            return newButton;
        } else {
            return previousButton;
        }
    }

    private static void proccessButtonClick(int buttonCode,
                                            DialogBox questionBox,
                                            DialogAnswerListener listener) {
        questionBox.hide();
        listener.anserIs(buttonCode);
    }

    private static Button addButton(int answerSet, final int buttonCode,
                                    String buttonCaption,
                                    final DialogAnswerListener listener,
                                    final DialogBox questionBox,
                                    HorizontalPanel buttonsPanel,
                                    int buttonToFocus) {
        if((answerSet & buttonCode) != 0) {
            Button button = new Button(buttonCaption);

            button.addStyleName(BUTTON_STYLE);
            button.addClickListener(new ClickListener() {
                public void onClick(Widget sender) {
                    proccessButtonClick(buttonCode, questionBox, listener);
                }
            });
            buttonsPanel.add(button);

            return buttonToFocus == buttonCode ? button:null;
        }
        return null;
    }

    public static DialogBox showQuestionDialog(String question, int answerSet,
                                               final DialogAnswerListener listener,
                                               int buttonToFocus) {
        return showQuestionDialog(question, answerSet,
                Window.getClientWidth() / 2,
                Window.getClientHeight() / 2,
                listener, buttonToFocus);
    }

    public static DialogBox showQuestionDialog(String question, int answerSet,
                                               final DialogAnswerListener listener) {
        return showQuestionDialog(question, answerSet,
                Window.getClientWidth() / 2,
                Window.getClientHeight() / 2,
                listener);
    }

    public static void showMessageDialog(String message, int xPos, int yPos) {
        showQuestionDialog(message, OK, xPos, yPos, new DialogAnswerListener() {
            public void anserIs(int answer) {
            }
        });
    }

    public static void showMessageDialog(String message) {
        showMessageDialog(message, Window.getClientWidth() / 2,
                Window.getClientHeight() / 2);
    }

    /**
     * Returns {@link #YES} if yes clicked, or {@link #NO} if no clicked.
     *
     * @param question question string.
     * @return user answer for the question.
     */
    public static int showModalQuestionDialog(String question) {
        boolean confirm = Window.confirm(question);
        if(confirm) {
            return YES;
        } else {
            return NO;
        }
    }

    public static void showModalMessageDialog(String message) {
        Window.alert(message);
    }

    public static void showDetailedModalDialog(String message,
                                               String stackTrace) {
        DetailedModalDialog dialog = new DetailedModalDialog(message,
                stackTrace);
        dialog.show();
    }

    public static void showModalErrorDialog(String message, Throwable e) {
        message += (e != null) ? e.getMessage():"";
        showModalMessageDialog(message);
    }

    public static void showModalErrorDialog(Throwable caught) {
        if(caught instanceof InvocationException) {
            showModalErrorDialog("Server call failed: ", caught);
        } else if(caught instanceof DisplayableStackTraceException) {
            showDetailedModalDialog(caught.getMessage(),
                    ((DisplayableStackTraceException) caught).getStringStackTrace());
        } else if(caught instanceof DisplayableException) {
            showModalMessageDialog(caught.getMessage());
        } else {
            showModalErrorDialog("Unexpected error: ", caught);
        }
    }
}
