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

import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HorizontalPanel;
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.google.gwt.user.client.ui.SimplePanel;
import com.queplix.core.client.app.vo.FieldDataRequest;
import com.queplix.core.client.app.vo.FormMeta;
import com.queplix.core.client.app.vo.GetControlInformOnDemandData;
import com.queplix.core.client.app.vo.GetRecordsInformOnDemandData;
import com.queplix.core.client.app.vo.GridMeta;
import com.queplix.core.client.app.vo.GridSearchProperties;
import com.queplix.core.client.app.vo.InFormGridFieldMeta;
import com.queplix.core.client.app.vo.InFormGridOnDemandData;
import com.queplix.core.client.app.vo.InFormGridType;
import com.queplix.core.client.app.vo.RecordFilter;
import com.queplix.core.client.app.vo.SearchInformOnDemandData;
import com.queplix.core.client.app.vo.SortedInformOnDemandData;
import com.queplix.core.client.app.vo.uisettings.DialogUISettings;
import com.queplix.core.client.common.event.Event;
import com.queplix.core.client.common.event.EventListener;
import com.queplix.core.client.common.ui.grid.DataGrid;
import com.queplix.core.client.common.ui.grid.DefaultGridView;
import com.queplix.core.client.common.ui.grid.GridSortListener;
import com.queplix.core.client.common.ui.WindowHelper;
import com.queplix.core.client.controls.QButton;
import com.queplix.core.client.controls.QFormElement;
import com.queplix.core.client.i18n.I18N;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * In form grid view
 *
 * @author Sergey Kozmin
 * @author Vasily Mikhailitchenko
 * @since 04.04.2007
 */
class QInformGridViewImpl extends QInformGridView implements ClickListener,
        EventListener {

    private static final String CSS_STYLE = "inFormGrid_offset";
    private static final String CSS_ALIGN = "inFormGrid_align";

    private static final String DEFAULT_WIDTH = "560px";
    private static final String DEFAULT_GRID_HEIGHT = "72px";

    private QInformGridModelImpl model;

    private ArrayList actionsListeners = new ArrayList();

    //view related
    private Grid mainPanel;

    private VerticalPanel gridPanel;
    private DataGrid informGrid;

    private HorizontalPanel btnPanel;
    private QButton linkBtn;
    private QButton unlinkBtn;
    private QButton filtersBtn;
    private FilteringDialog filteringDialog;
    private Label leftSide;
    private Label rightSide;

    public QInformGridViewImpl(QInformGridModelImpl model) {
        super(model, QFormElement.HORIZONTAL);
        this.model = model;
        setupWidgets();
        initListeners();
    }

    private void initListeners() {
        linkBtn.addClickListener(this);
        unlinkBtn.addClickListener(this);
        filtersBtn.addClickListener(this);
        informGrid.getEventSource().addEventListener(this);
    }

    protected void onAttach() {
        super.onAttach();
        captionLabel.setWidth("10px"); // todo: eliminate this work-around
    }

    private void setupWidgets() {
        mainPanel = new Grid(3, 3);
        mainPanel.setCellPadding(0);
        mainPanel.setCellSpacing(0);

        mainPanel.addStyleName(CSS_STYLE);

        SimplePanel formHeader = new SimplePanel();
        formHeader.setWidth("100%");
        formHeader.setStyleName("form_topSide");
        captionLabel.setStyleName("form_topSide");
        formHeader.setWidget(captionLabel);

        Label leftTop = new Label(" ");
        leftTop.setStyleName("form_leftTop");

        Label rightTop = new Label(" ");
        rightTop.setStyleName("form_rightTop");

        leftSide = new Label(" ");
        leftSide.setStyleName("form_leftSide");

        Label leftBottom = new Label(" ");
        leftBottom.setStyleName("form_leftBottom");

        Label topSide = new Label(" ");
        topSide.setStyleName("form_topSide");

        Label bottomSide = new Label(" ");
        bottomSide.setStyleName("form_bottomSide");

        rightSide = new Label(" ");
        rightSide.setStyleName("form_rightSide");

        Label rightBottom = new Label(" ");
        rightBottom.setStyleName("form_rightBottom");

        gridPanel = new VerticalPanel();
        gridPanel.setSpacing(0);

        informGrid = new DataGrid(model.getGridModel(),
                DefaultGridView.INSTANCE, false, false);

        linkBtn = new QButton(I18N.getMessages().link());
        unlinkBtn = new QButton(I18N.getMessages().unLink());
        filtersBtn = new QButton(I18N.getMessages().setFilter());

        btnPanel = new HorizontalPanel();
        btnPanel.setHorizontalAlignment(HorizontalPanel.ALIGN_RIGHT);

        Label empLablel = new Label();
        btnPanel.add(empLablel);
        btnPanel.add(linkBtn);
        btnPanel.add(unlinkBtn);
        btnPanel.add(filtersBtn);

        btnPanel.setCellWidth(empLablel, "100%");

        gridPanel.add(informGrid);
        gridPanel.add(btnPanel);

        mainPanel.setWidget(0, 0, leftTop);
        mainPanel.setWidget(0, 1, formHeader);
        mainPanel.setWidget(0, 2, rightTop);
        mainPanel.setWidget(1, 0, leftSide);
        mainPanel.setWidget(1, 1, gridPanel);
        mainPanel.setWidget(1, 2, rightSide);
        mainPanel.setWidget(2, 0, leftBottom);
        mainPanel.setWidget(2, 1, bottomSide);
        mainPanel.setWidget(2, 2, rightBottom);

        initWidget(mainPanel);
        addStyleName(CSS_ALIGN);
        WindowHelper.disableSelection(gridPanel.getElement());
        // assuming that the form is in search state by default
        setSortingEnabled(false);
    }

    public void setButtonsEnabled(int buttonIndex, boolean isEnabled) {
        getButton(buttonIndex).setEnabled(isEnabled);
    }

    /**
     * Can be performed for single button.
     *
     * @param buttonIndex index of single button.
     * @param isVisible   visible state
     */
    public void setButtonVisible(int buttonIndex, boolean isVisible) {
        getButton(buttonIndex).setVisible(isVisible);
    }

    private QButton getButton(int buttonIndex) {
        QButton ret = null;
        if((buttonIndex & QInformGrid.LINK_BUTTON_INDEX) != 0) {
            ret = linkBtn;
        }
        if((buttonIndex & QInformGrid.UNLINK_BUTTON_INDEX) != 0) {
            ret = unlinkBtn;
        }
        if((buttonIndex & QInformGrid.FILTERS_BUTTON_INDEX) != 0) {
            ret = filtersBtn;
        }
        return ret;
    }

    public void onClick(Widget sender) {
        if(sender.equals(linkBtn)) {
            fireAction(QInformGrid.LINK_BUTTON_INDEX);
        } else if(sender.equals(unlinkBtn)) {
            fireAction(QInformGrid.UNLINK_BUTTON_INDEX);
        } else if(sender.equals(filtersBtn)) {
            fireAction(QInformGrid.FILTERS_BUTTON_INDEX);
        }
    }

    protected void onModeChanged(int newMode) {
        fireAction(QInformGrid.CONTROL_STATE_CHANGED_INDEX);
        if(filteringDialog != null &&
                (MODE_DISABLED == newMode || MODE_SEARCH == newMode)) {
            filteringDialog.reset();
        }
    }

    protected void setEnabled(boolean isEnabled) {
        //do nothing, do all in method onModeChanged
    }

    protected void setClientWidth(String clientWidth) {
        // Don't accept the usual sizing policy
        mainPanel.setWidth(DEFAULT_WIDTH);
        btnPanel.setWidth(DEFAULT_WIDTH);

        informGrid.setWidth(DEFAULT_WIDTH);
        informGrid.setHeight(DEFAULT_GRID_HEIGHT);
        gridPanel.setWidth(DEFAULT_WIDTH);
        gridPanel.setHeight(DEFAULT_GRID_HEIGHT);
        
        rightSide.setHeight(gridPanel.getOffsetHeight()+ "px");
        leftSide.setHeight(gridPanel.getOffsetHeight() + "px");
    }

    public void onDemandModelChanged() {
        super.onDemandModelChanged();

        InFormGridOnDemandData gridOnDemandData = model.getOnDemandData();
        int type = gridOnDemandData.getInformGridRequestType();
        switch(type) {
            case InFormGridType.SEARCH_TYPE: {
                SearchInformOnDemandData data
                        = (SearchInformOnDemandData) gridOnDemandData;
                filteringDialog.setGridData(data.getData(),
                        data.getCurrentPage(),
                        data.getTotalRecordsCount());
                break;
            }
            case InFormGridType.GET_SORTED_DATA: {
                SortedInformOnDemandData data
                        = (SortedInformOnDemandData) gridOnDemandData;
                fireSetRowsInModel(data.getData());
                break;
            }
            case InFormGridType.GET_CONTROL_DATA_TYPE: {
                GetControlInformOnDemandData data
                        = (GetControlInformOnDemandData) gridOnDemandData;
                filteringDialog.setFieldOnDemandData(data.getData());
                break;
            }
            case InFormGridType.GET_RECORDS_DATA_TYPE: {
                GetRecordsInformOnDemandData data
                        = (GetRecordsInformOnDemandData) gridOnDemandData;
                fireAddRowsToModel(data.getData(), data.getFilters());
                break;
            }
        }
    }

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

    public void addActionListener(ViewActionsListener listener) {
        actionsListeners.add(listener);
    }

    public void removeActionListener(ViewActionsListener listener) {
        actionsListeners.remove(listener);
    }

    private void fireAction(int action) {
        for(int i = 0; i < actionsListeners.size(); i++) {
            ViewActionsListener listener = (ViewActionsListener)
                    actionsListeners.get(i);
            listener.onAction(action);
        }
    }

    protected void setOkCaptionStyle() {
        captionLabel.setStyleName("form_topSide");
    }

    protected void setErrorCaptionStyle() {
        captionLabel.setStyleName("form_formElementRequiredColor");
    }

    private void fireOnSearch(RecordFilter filter,
                              GridSearchProperties gridProperties) {
        for(int i = 0; i < actionsListeners.size(); i++) {
            ViewActionsListener listener = (ViewActionsListener)
                    actionsListeners.get(i);
            listener.onSearchRequest(filter, gridProperties);
        }
    }

    private void fireOnMoreData(FieldDataRequest filter) {
        for(int i = 0; i < actionsListeners.size(); i++) {
            ViewActionsListener listener = (ViewActionsListener)
                    actionsListeners.get(i);
            listener.onMoreDataRequest(filter);
        }
    }

    private void fireAddRowsToModel(List rows, Collection filters) {
        for(int i = 0; i < actionsListeners.size(); i++) {
            ViewActionsListener listener = (ViewActionsListener)
                    actionsListeners.get(i);
            listener.addRecordsToModel(rows, filters);
        }
    }

    private void fireSetRowsInModel(List rows){
        for(int i = 0; i < actionsListeners.size(); i++){
            ViewActionsListener listener = (ViewActionsListener)
                    actionsListeners.get(i);
            listener.setRecordsInModel(rows);
        }
    }

    public void showFilteringDialog() {
        FilteringDialog dialog = getFilteringDialog();
        dialog.show();
    }

    private FilteringDialog getFilteringDialog() {
        if(filteringDialog == null) {
            InFormGridFieldMeta fieldMeta = model.getMeta();
            String caption = "Select filters for [" + fieldMeta.getCaption()
                    + "]";
            GridMeta gridMeta = fieldMeta.getFilteringGridMeta();
            FormMeta formMeta = fieldMeta.getFilteringFormMeta();
            filteringDialog = new FilteringDialog(caption, gridMeta, formMeta);
            filteringDialog.getFilteringEventSource().addEventListener(this);
            filteringDialog.setUISettings(model.getMeta().getUISettings());
        }
        return filteringDialog;
    }


    protected DialogUISettings getUISettings() {
        return filteringDialog.getUISettings();
    }

    public void onEvent(Event event, Widget sender) {
        if(FilteringDialog.Events.OK == event) {
            fireAction(QInformGrid.FILTERS_WERE_SET_INDEX);
        } else
        if(FilteringDialog.Events.FORM_CONTROL_NEED_MORE_DATA_EVENT == event) {
            fireOnMoreData((FieldDataRequest) event.getData());
        } else if(FilteringDialog.Events.GRID_NEED_DATA == event ||
                FilteringDialog.Events.FORM_SEARCH_BUTTON_EVENT == event) {
            fireOnSearch(filteringDialog.getDialogFilter(),
                    filteringDialog.getGridProperties());
        } else if(DataGrid.Events.GRID_ROW_SELECTED == event) {
            fireAction(QInformGrid.RECORD_SELECTION_CHANGED_INDEX);
        } else if(DataGrid.Events.DELETE_KEY_PRESSED == event) {
            fireAction(QInformGrid.UNLINK_BUTTON_INDEX);
        }
    }

    /**
     * @return List<Integer> of selected indexes
     */
    public List getSelectedRecords() {
        return informGrid.getSelectionController().getSelectedRows();
    }

    public RecordFilter getDialogFilter() {
        return getFilteringDialog().getDialogFilter();
    }

    public void formStateChanged(QInformGridState newState) {
       setSortingEnabled(newState.getState() == QInformGridState.EDIT_STATE ||
               newState.getState() == QInformGridState.SELECTED_STATE);
    }

    private void setSortingEnabled(boolean enabled) {
        informGrid.setSortingEnabled(enabled);
    }

    public void addSortListener(
            GridSortListener listener) {
        informGrid.addGridSortListener(listener);
    }
}
