/*
 * 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.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.KeyboardListener;
import com.google.gwt.user.client.ui.PopupListener;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.queplix.core.client.app.vo.uisettings.DialogUISettings;
import com.queplix.core.client.common.StringUtil;
import com.queplix.core.client.common.event.Event;
import com.queplix.core.client.common.event.EventListener;
import com.queplix.core.client.common.ui.resizable.Resizable;
import com.queplix.core.client.common.ui.resizable.ResizableDialogBox;
import com.queplix.core.client.controls.QButton;

/**
 * A popup dialog with OK/Cancel buttons.
 *
 * @author Sultan Tezadov
 * @since 24 Dec 2006
 */
public class OkayCancelPopup extends ButtonSet implements EventListener {

    // -------------------- public events ------------------------
    public static interface Events {
        Event OK = new Event();
        Event CANCEL = new Event();
        Event SEND = new Event();
    }
    // ----------------- end of public events --------------------

    private boolean doNotCloseOnEvent;

    private static final ButtonData OK_BUTTON =
            new ButtonData(null, null, "control/dialog_ok.gif", null,
                    "control/dialog_ok_bright.gif", ButtonData.OK);
    private static final ButtonData CANCEL_BUTTON =
            new ButtonData(null, null, "control/dialog_cancel.gif", null,
                    "control/dialog_cancel_bright.gif", ButtonData.CANCEL);
    /*private static final ButtonData SEND_BUTTON =
            new ButtonData(null, null, "control/dialog_send.gif", null, "control/dialog_send_bright.gif", ButtonData.SEND_MAIL);*/

    private static final class ResizableVerticalPanel extends VerticalPanel
            implements Resizable {
        public void setOffsetHeight(int height) {
            Resizable widget = (Resizable) getWidget(0);
            Widget buttonsPanel = getWidget(1);
            widget.setOffsetHeight(height - buttonsPanel.getOffsetHeight());
            setHeight(StringUtil.pixelToSize(height));
        }

        public void setOffsetWidth(int width) {
            Resizable widget = (Resizable) getWidget(0);
            widget.setOffsetWidth(width);
            setWidth(StringUtil.pixelToSize(width));
        }
    }

    private int minHeight;
    private int minWidth;

    private AnchoredDialogBox dialog;
    private VerticalPanel vp;
    private HorizontalPanel hp;
    private String caption;

    public OkayCancelPopup(String caption, boolean doNotCloseOnEvent) {
        super(true); // nowidget constructor
        this.doNotCloseOnEvent = doNotCloseOnEvent;
        this.caption = caption;
    }

    public OkayCancelPopup(String caption) {
        this(caption, false);
    }

    public void setWidget(Widget w) {
        boolean isResizable = w instanceof Resizable;
        createWidgets(isResizable, w, ButtonData.OK | ButtonData.CANCEL, false);
    }

    public void setWidget(Widget w, int buttons) {
        boolean isResizable = w instanceof Resizable;
        createWidgets(isResizable, w, buttons, false);
    }

    public void setWidget(Widget w, int buttons, boolean hideWhileResizing) {
        boolean isResizable = w instanceof Resizable;
        createWidgets(isResizable, w, buttons, hideWhileResizing);
    }

    private void createWidgets(boolean isResizable, Widget w, int buttons,
                               boolean hideWhileResizing) {
        if(isResizable) {
            dialog = new ResizableDialogBox(false, hideWhileResizing) {
                public boolean onKeyPressPreview(char key, int modifiers) {
                    return OkayCancelPopup.this.onKeyPressPreview(key,
                            modifiers);
                }
            };
            vp = new ResizableVerticalPanel();
        } else {
            dialog = new AnchoredDialogBox() {
                public boolean onKeyPressPreview(char key, int modifiers) {
                    return OkayCancelPopup.this.onKeyPressPreview(key,
                            modifiers);
                }
            };
            vp = new VerticalPanel();
        }
        vp.setStyleName("ocp_area");
        dialog.setText(caption);

        hp = createButtonPanel(buttons);

        vp.add(w);
        vp.add(hp);
        vp.setCellHorizontalAlignment(hp, HasHorizontalAlignment.ALIGN_RIGHT);

        dialog.setWidget(vp);

        getEventSource().addEventListener(this);
        dialog.addStyleName("ocp_border");
        dialog.addStyleName("ocp_area");
    }

    public int getDialogOffetWidth() {
        return dialog.getOffsetWidth();
    }

    private HorizontalPanel createButtonPanel(int buttons) {
        HorizontalPanel hp = new HorizontalPanel();
        if((buttons & ButtonData.SEND_MAIL) != 0) {
            QButton sendMail = new QButton("Send");
            hp.add(sendMail);
            addButton(Events.SEND, sendMail);
        }
        if((buttons & ButtonData.CANCEL_MAIL) != 0) {
            QButton cancelMail = new QButton("Cancel");
            hp.add(cancelMail);
            addButton(Events.CANCEL, cancelMail);
        }
        if((buttons & OK_BUTTON.getButtonId()) != 0) {
            IconButton ok = new IconButton(OK_BUTTON);
            ok.addStyleName("ocp_button");
            hp.add(ok);
            addButton(Events.OK, ok);
        }
        if((buttons & CANCEL_BUTTON.getButtonId()) != 0) {
            IconButton cancel = new IconButton(CANCEL_BUTTON);
            cancel.addStyleName("ocp_button");
            hp.add(cancel);
            addButton(Events.CANCEL, cancel);
        }
        return hp;
    }

    public void hide() {
        dialog.hide();
    }

    public void show() {
        dialog.show();
    }

    public void show(int left, int top) {
        dialog.setPopupPosition(left, top);
        dialog.show();
    }

    public void show(Widget nextTo) {
        setAnchor(nextTo);
        dialog.show();
    }

    public void setAnchor(Widget anchor) {
        dialog.setAnchor(anchor);
    }

    public void setCaption(String caption) {
        dialog.setText(caption);
    }

    public void onEvent(Event event, Widget sender) {
        if(!doNotCloseOnEvent) {
            dialog.hide();
        }
    }

    public void addPopupListener(PopupListener listener) {
        dialog.addPopupListener(listener);
    }

    public boolean isDialogShown() {
        return dialog.isDialogShown();
    }

    /**
     * Set minimum dialog size. If the method is not called,
     * default values are taken (see class definition).
     *
     * @param minWidth  minimum allowed width
     * @param minHeight minimum allowed height
     */
    public void setMinSize(int minWidth, int minHeight) {
        if(dialog instanceof ResizableDialogBox) {
            ((ResizableDialogBox) dialog).setMinSize(minWidth, minHeight);
        } else {
            throw new UnsupportedOperationException();
        }
    }

    public DialogUISettings getUISettings() {
        return dialog != null ? dialog.getUISettings():null;
    }

    public void setUISettings(DialogUISettings uiSettings) {
        dialog.setUISettings(uiSettings);
    }

    private boolean onKeyPressPreview(char key, int modifiers) {
        if(key == KeyboardListener.KEY_ESCAPE) {
            this.getEventSource().fireEvent(Events.CANCEL);
            return false;
        }
        return true;
    }
}
