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

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.FocusListener;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.KeyboardListener;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.PopupListener;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.queplix.core.client.app.vo.EntityReferenceData;
import com.queplix.core.client.app.vo.EntityReferenceOnDemandData;
import com.queplix.core.client.app.vo.GridData;
import com.queplix.core.client.app.vo.RowData;
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.ButtonData;
import com.queplix.core.client.common.ui.IconButton;
import com.queplix.core.client.common.ui.OkayCancelPopup;
import com.queplix.core.client.common.ui.grid.SelectedRecord;
import com.queplix.core.client.controls.grid.QGrid;
import com.queplix.core.client.controls.grid.QGridController;
import com.queplix.core.client.controls.grid.QGridModel;

import java.util.Map;

class QEntityReferenceViewImpl extends QEntityReferenceView
        implements ClickListener, QEntityReferenceModelImpl.EntityModelListener,
        FocusListener, PopupListener {

    private static final ButtonData EMPTY_STATE =
            new ButtonData(null, "Empty", "entityreference/button1.gif",
                    "entityreference/button1_dis.gif",
                    "entityreference/button1_bright.gif");
    private static final ButtonData FULL_STATE =
            new ButtonData(null, "Selected", "entityreference/button2.gif",
                    "entityreference/button2_dis.gif",
                    "entityreference/button2_bright.gif");

    private static final int MIN_HEIGHT = 150;
    private static final int MIN_WIDTH = 420;

    private QEntityReferenceModelImpl model;
    private EntityViewListener listener;

    private OkayCancelPopup dialog;

    private TextBox filterBox;
    private IconButton findButton;
    private QGrid qgrid;

    private boolean ignorePopupClose = true;
    private static final String FIND_BUTTON_STYLE = "entityreference_button";
    private static final String FIND_BUTTON_STYLE_ENABLED
            = "entityreference_button_enabled";
    private static final String FILTER_BOX_STYLE = "styled_input";

    public QEntityReferenceViewImpl(QEntityReferenceModelImpl model,
                                    int layout) {
        super(model, layout);
        this.model = model;
        initializeGUI();
        model.addEntityModelListener(this);
    }

    private void initializeGUI() {
        filterBox = new TextBox();
        filterBox.addStyleName(FILTER_BOX_STYLE);
        filterBox.addFocusListener(this);
        filterBox.addKeyboardListener(new KeyboardListener() {
            public void onKeyDown(Widget sender, char keyCode, int modifiers) {
                if(keyCode == KeyboardListener.KEY_ENTER) {
                    onLostFocus(sender);
                }
            }

            public void onKeyPress(Widget sender, char keyCode, int modifiers) {
            }

            public void onKeyUp(Widget sender, char keyCode, int modifiers) {
            }
        });

        findButton = new IconButton(EMPTY_STATE);
        findButton.setStyleName(FIND_BUTTON_STYLE);
        findButton.addClickListener(this);

        Panel internalPanel = new HorizontalPanel();
        internalPanel.add(filterBox);
        internalPanel.add(findButton);

        addToPanel(internalPanel);
        initPanel();
    }

    public void setSearchListener(EntityViewListener listener) {
        this.listener = listener;
    }

    public void onClick(Widget sender) {
        String filterString = getFilterBoxText();
        if(listener != null) {
            listener.searchButtonClicked(filterString);
        }
    }

    private void initializeEntityLookupDialog() {
        qgrid = new QGrid(model.getMetaData(), true);

        qgrid.getController().getEventSource().addEventListener(
                new EventListener() {
                    public void onEvent(Event event, Widget sender) {
                        if(QGridController.Events.GRID_NEED_DATA.equals(
                                event)) {
                            listener.needMoreData(getFilterBoxText());
                        } else if(QGridController.Events.RECORD_SELECTED.equals(
                                event)) {
                            Long recordID = ((SelectedRecord) 
                                         QGridController.Events.RECORD_SELECTED
                                         .getData()).getRecordId();
                            recordSelectedInGrid(recordID);
                        }
                    }
                });

        dialog = new OkayCancelPopup(getModel().getBaseMeta().getCaption());

        qgrid.getView().setOffsetHeight(MIN_HEIGHT);
        qgrid.getView().setOffsetWidth(MIN_WIDTH);

        dialog.setWidget(qgrid.getView());
        dialog.setUISettings(getModel().getBaseMeta().getUISettings());
        dialog.setMinSize(MIN_WIDTH, MIN_HEIGHT);

        dialog.setAnchor(filterBox);
        dialog.addPopupListener(this);
    }

    private void recordSelectedInGrid(Long recordID) {
        if(!isDisabled()) {
            if(listener != null) {
                Map listRefData = model.getEntityReferenceOnDemandData()
                        .getRenderingValues();
                String filter = (String) listRefData.get(recordID);
                listener.entitySelected(recordID, filter);
            }
        }
        dialog.hide();
    }

    public void gridColumnSelected(int column) {
    }

    /**
     * @return X position, where popup dialog should be shown.
     */
    public int getPopupLeftPosition() {
        return (filterBox.getAbsoluteLeft());
    }

    /**
     * @return Y position, where popup dialog should be shown.
     */
    public int getPopupTopPosition() {
        return (filterBox.getAbsoluteTop() + filterBox.getOffsetHeight());
    }

    protected void onModeChanged(int newMode) {
        int mode = getViewMode();
        if(mode == MODE_EDIT || mode == MODE_NEW) {
            if(model.getEntityReferenceData().getSelectedRowID() == null) {
                listener.entitySelected(null, "");
            }
        }
//        findButton.setEnabled(MODE_REPORT_DESIGN != mode);
    }

    protected void setEnabled(boolean isEnabled) {
        String readOnly = isEnabled ? null:"readonly";
        DOM.setAttribute(filterBox.getElement(), "readOnly", readOnly);
        if(!isEnabled && dialog != null) {
            dialog.hide();
        }
        findButton.setEnabled(isEnabled);
        if(isEnabled) {
            findButton.addStyleName(FIND_BUTTON_STYLE_ENABLED);
        } else {
            findButton.removeStyleName(FIND_BUTTON_STYLE_ENABLED);
        }
    }


    public void modelMetaChanged() {
        setupIndicatorState();
        if(!getCaption().equalsIgnoreCase(model.getMeta().getCaption())) {
            setCaption(model.getMeta().getCaption());
        }
    }

    protected boolean isValid() {
        return isSearchMode() || isDisabled() || isReportDesignMode() ||
                !(model.getMeta().isRequired() &&
                        model.getEntityReferenceData().getSelectedRowID()
                                == null);
    }

    public void selectedEntityChanged() {
        setupIndicatorState();
        EntityReferenceData modelData = model.getEntityReferenceData();
        String filter = modelData.getSelectedFilter();

        if(StringUtil.isStringEmpty(filter)) {
            filterBox.setText("");
        } else {
            filterBox.setText(filter);
        }

        if(modelData.getSelectedRowID() == null) {
            findButton.setButtonState(EMPTY_STATE);
        } else {
            findButton.setButtonState(FULL_STATE);
        }
    }

    public void onDemandDataCome() {
        EntityReferenceOnDemandData demandData = model
                .getEntityReferenceOnDemandData();
        if(demandData
                != null) {//some how this method was called, when came data is null
            if(model.isCanShowDialogOnDataCome()) {
                if(dialog == null) {
                    initializeEntityLookupDialog();
                }
                setQGridData(demandData.getData(), demandData.getCurrentPage(),
                        demandData.getTotalRecordsNumber());
                if(!dialog.isDialogShown()) {
                    dialog.show();
                }
            } else {
                int dataSize = demandData.getData().getRows().length;
                if(dataSize
                        == 1) {//if only one came, select it otherwise do nothing
                    RowData rowData = demandData.getData().getRows()[0];
                    String listRefData = (String) demandData
                            .getRenderingValues().get(rowData.getId());
                    if(listener != null) {
                        listener.entitySelected(rowData.getId(), listRefData);
                    }
                } else {
                    int mode = getViewMode();
                    if(dataSize
                            > 1) {//in edit mode we should always show dialog if there are more than 1 record.
                        if(mode == MODE_EDIT || mode == MODE_NEW) {
                            if(dialog == null) {
                                initializeEntityLookupDialog();
                            }
                            setQGridData(demandData.getData(),
                                    demandData.getCurrentPage(),
                                    demandData.getTotalRecordsNumber());
                            ignorePopupClose = false;
                            dialog.show();
                        }
                    } else if(dataSize
                            < 1) {//in edit mode we clear value in filter box, if nothing came
                        String textToSet =
                                (mode == MODE_EDIT || mode == MODE_NEW) ? ""
                                        :getFilterBoxText();
                        if(listener != null) {
                            listener.entitySelected(null, textToSet);
                        }
                    }
                }
            }
            if(ignorePopupClose && listener != null) {
                listener.onResolveEvent(false);
            }
        }
    }

    private void setQGridData(GridData data, long currentPage,
                              long totalRecordsCount) {
        qgrid.getModel().setGridData(data, totalRecordsCount, currentPage);
    }

    public void onFocus(Widget sender) {
        //do nothing
    }

    public void onLostFocus(Widget sender) {
        String filter = model.getEntityReferenceData().getSelectedFilter();
        if(filter == null) {
            filter = "";
        } else {
            filter = filter.trim();
        }
        String enteredText = getFilterBoxText();
        if(!enteredText.equalsIgnoreCase(filter)) {
            if(listener != null) {
                listener.entitySelected(null, enteredText);
                if(!enteredText.equals("")) {
                    listener.onResolveEvent(true);
                }
                listener.searchTabOut(enteredText);
            }
        }
    }

    private String getFilterBoxText() {
        return filterBox.getText().trim();
    }

    public void onPopupClosed(PopupPanel sender, boolean autoClosed) {
        if(listener != null) {
            listener.dialogWasHidden();
            if(!ignorePopupClose) {
                listener.onResolveEvent(false);
                ignorePopupClose = true;
            }
        }
        qgrid.getController().clearSelectedRecord();
        filterBox.setFocus(true);
    }

    public int getClientWidth() {
        return filterBox.getOffsetWidth();
    }

    protected void setClientWidth(String clientWidth) {
        filterBox.setWidth(clientWidth);
    }

    public QGridModel getGridModel() {
        return qgrid != null ? qgrid.getModel() : null;
    }

    public int getFilledWidth() {
        return super.getFilledWidth() + findButton.getOffsetWidth();
    }

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

    static interface EntityViewListener {
        public void needMoreData(String filterString);

        public void searchButtonClicked(String filterString);

        public void searchTabOut(String filterString);

        public void entitySelected(Long entityID, String filter);

        public void dialogWasHidden();

        public void onResolveEvent(boolean isStarted);
    }
}