/*
 * 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.resizable;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
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.vo.uisettings.DialogUISettings;
import com.queplix.core.client.common.ui.AnchoredDialogBox;

/**
 * Extended DialogBox that supports resizing by mouse dragging.
 * The dialog box is resizable only when the widget it contains is
 * resizable (see {@link #setWidget(Widget)}).
 *
 * @author Sultan Tezadov
 * @since 18 Dec 2006
 */
public class ResizableDialogBox extends AnchoredDialogBox {
    private int minWidth = 30;
    private int minHeight = 30;

    private VerticalPanel panel;
    private Label resizer;
    private boolean dragging;
    private int dragStartX;
    private int dragStartY;
    private boolean isResizable;

    boolean hideWhileResizing;

    public ResizableDialogBox() {
        this(false);
    }

    public ResizableDialogBox(boolean autoHide) {
        super(autoHide);
    }

    /**
     * @param hideWhileResizing - indicates if to hide contents of popup while resizing.
     *                          FireFox workaround for popup containing iFrame (QMemo control)
     */
    public ResizableDialogBox(boolean autoHide, boolean hideWhileResizing) {
        super(autoHide);
        this.hideWhileResizing = hideWhileResizing;
    }

    /**
     * Sets the widget that will be displayed in the dialog box.
     *
     * @param w -- a Widget that should implement Resizable. If it does not
     *          do so, the dialog itself will not be resizable.
     */
    public void setWidget(Widget w) {
        isResizable = w instanceof Resizable;
        if(isResizable) {
            panel = new VerticalPanel();
            panel.setStyleName("ocp_area");
            panel.add(w);
            resizer = new Label(" ");
            resizer.setStyleName("resizableDialog_resizer");
            panel.add(resizer);
            panel.setCellHorizontalAlignment(resizer,
                    HasHorizontalAlignment.ALIGN_RIGHT);
            resizer.addMouseListener(this);
            super.setWidget(panel);
        } else {
            panel = null;
            resizer = null;
            super.setWidget(w);
        }
    }

    public void onMouseDown(Widget sender, int x, int y) {
        if(sender == resizer) {
            dragging = true;
            if(hideWhileResizing) {
                Widget widget = (Widget) panel.getWidget(0);
                Resizable res = (Resizable) widget;
                dragStartX = x + res.getOffsetWidth() + DOM.getAbsoluteLeft(
                        widget.getElement());
                dragStartY = y + res.getOffsetHeight() + 19 + DOM
                        .getAbsoluteTop(widget.getElement());
                getWidget().setVisible(false);
            } else {
                dragStartX = x;
                dragStartY = y;
            }
            DOM.setCapture(resizer.getElement());
        } else {
            super.onMouseDown(sender, x, y);
        }
    }

    public void onMouseMove(Widget sender, int x, int y) {
        if(!dragging) {
            super.onMouseMove(sender, x, y);
        }
    }

    public void onMouseUp(Widget sender, int x, int y) {
        if(sender == resizer) {
            dragging = false;
            if(hideWhileResizing) {
                getWidget().setVisible(true);
            }
            DOM.releaseCapture(resizer.getElement());
            int deltaX = x - dragStartX;
            int deltaY = y - dragStartY;
            resize(deltaX, deltaY);
        } else {
            super.onMouseUp(sender, x, y);
        }
    }

    public void resize(int deltaX, int deltaY) {
        Resizable widget = (Resizable) panel.getWidget(0);
        int width = widget.getOffsetWidth() + deltaX;
        width = (width > minWidth) ? width:minWidth;
        int height = widget.getOffsetHeight() + deltaY;
        height = (height > minHeight) ? height:minHeight;
        widget.setOffsetWidth(width);
        widget.setOffsetHeight(height);
        updateUISettings(width, height);
    }

    /**
     * Set minimum dialog size. If the method is not called,
     * default values are taken (see class definition).
     */
    public void setMinSize(int minWidth, int minHeight) {
        this.minWidth = minWidth;
        this.minHeight = minHeight;
    }

    public void show() {
        if(isResizable && (uiSettings != null) && uiSettings.isSizeSet()) {
            Resizable widget = (Resizable) panel.getWidget(0);
            widget.setOffsetWidth(uiSettings.getWidth());
            widget.setOffsetHeight(uiSettings.getHeight());
        }
        super.show();
    }

    private void updateUISettings(int width, int height) {
        if(uiSettings == null) {
            uiSettings = new DialogUISettings();
        }
        uiSettings.setWidth(width);
        uiSettings.setHeight(height);
    }

}
