/*
 * 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.frames.mainframe.impl;

import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.queplix.core.client.app.Application;
import com.queplix.core.client.app.vo.FamgMeta;
import com.queplix.core.client.app.vo.FieldData;
import com.queplix.core.client.app.vo.FieldMeta;
import com.queplix.core.client.app.vo.FormMeta;
import com.queplix.core.client.app.vo.TabMeta;
import com.queplix.core.client.common.event.Event;
import com.queplix.core.client.common.event.EventListener;
import com.queplix.core.client.common.event.EventSource;
import com.queplix.core.client.common.ui.DialogHelper;
import com.queplix.core.client.controls.form.IncorrectFormStateSelected;
import com.queplix.core.client.controls.form.QForm;
import com.queplix.core.client.controls.form.QFormController;
import com.queplix.core.client.controls.form.QFormLayout;
import com.queplix.core.client.controls.form.QFormModel;
import com.queplix.core.client.controls.form.event.ControlChangedData;
import com.queplix.core.client.frames.mainframe.FormControlEventTypes;
import com.queplix.core.client.frames.mainframe.FormState;
import com.queplix.core.client.frames.mainframe.ViewPropertiesProvider;

import java.util.Set;

/**
 * Postfix FA - Form Area.
 * Class MainFrameFA contains array of FocusFA.
 * Class class FocusFA contains array of SubFocusFA.
 * Class SubFocusFA contains array of TabFA.
 * Class TabFA contains array of QForm.
 *
 * @author Aliaksandr Melnik
 * @since 19 Oct 2006
 */
class TabFA extends VerticalPanel implements EventListener {
    private ViewPropertiesProvider viewPropertiesProvider;

    // -------------------- public events ------------------------
    public static interface Events extends QFormController.Events {
        /**
         * Occures when the tab is lazily created
         */
        Event TAB_INITIALIZED = new Event();
        Event FORM_ACTIVATED = new Event();
    }

    private EventSource eventSource = new EventSource(this);
    private String helpLink;

    public EventSource getEventSource() {
        return eventSource;
    }
    // ----------------- end of public events --------------------

    private QForm[] forms;
    /**
     * row's ids, that is editing in form
     */
    private FamgMeta[] famgsMeta;

    private int activeForm = 0;
    private boolean firstLoad = true;

    public TabFA(TabMeta tabMeta, ViewPropertiesProvider viewPropertiesProvider) {
        this.viewPropertiesProvider = viewPropertiesProvider;
        famgsMeta = tabMeta.getFamgs();
        FormMeta[] formsMeta = new FormMeta[famgsMeta.length];
        for(int i = 0; i < famgsMeta.length; i++) {
            formsMeta[i] = famgsMeta[i].getForm();
        }
        helpLink = tabMeta.getHelpLink();
        forms = new QForm[famgsMeta.length];

        String status = Application.getStatus();

        //invisible forms must be in end of tab only!
        for(int i = 0; i < forms.length; i++) {
            Application.setStatus(
                    status + " -> form: " + formsMeta[i].getCaption());
            forms[i] = createForm(formsMeta[i]);
            forms[i].getFormController().getEventSource().addEventListener(
                    this); // retranslate events
            if (forms[i].getView().isVisible()) {
                add(forms[i].getView());
            }
            else {
                
            }
// @see #initialized() method
//            forms[i].getFormController().onInit();
        }

        activateFormByIndex(activeForm);
    }

    private QForm createForm(FormMeta form) {
        FieldMeta[] fieldMetas = form.getEntityMeta().getFields();
        int formWidth = 2;
        QForm qform;
        if(form.getLayoutMeta() == null) {
            qform = new QForm(form, formWidth, (int) Math.ceil(
                    fieldMetas.length / (float) formWidth),
                    QFormLayout.HORIZONTAL_FLOW_LAYOUT, true, true);
        } else {
            qform = new QForm(form);
        }
        return qform;
    }

    public void setFormsState(int formState) {
        for(int i = 0; i < forms.length; i++) {
            try {
                forms[i].getFormController().setFormState(formState);
            } catch (IncorrectFormStateSelected ex) {
                ex.printStackTrace();
            }
        }
    }

    public FamgMeta.Index getSelectedFormIndex() {
        return famgsMeta[activeForm].getIndex();
    }

    public QForm getForm(FamgMeta.Index index) {
        return forms[index.famg];
    }

    public QForm getActiveForm() {
        return forms[activeForm];
    }

    public void activateForm(FamgMeta.Index index) {
        activateFormByIndex(index.famg);
    }

    private void activateFormByIndex(int index) {
        selectForm(index);
        getEventSource().fireEvent(Events.FORM_ACTIVATED);
    }

    private void selectForm(int index) {
        if((index != activeForm) || firstLoad) {
            forms[activeForm].getView().setSelected(false);
            forms[index].getView().setSelected(true);
            activeForm = index;

            firstLoad = false;
        }
    }

    public boolean performCommand(FormCommand command,
                                  FamgMeta.Index formIndex) {
        boolean performedSuccessfully = true;
        switch(command.getCommandID()) {
            case FormCommand.SET_DATA: {
                SetDataForFormCommand formCommand
                        = (SetDataForFormCommand) command;
                setData(formCommand.getData(), formCommand.getRowID(),
                        formIndex, formCommand.isClearOtherFields());
                break;
            }
            case FormCommand.CLEAR_DATA: {
                break;
            }
            case FormCommand.SET_SEARCH_STATUS: {
                SetSearchStatusFormCommand searchStatusCommand
                        = (SetSearchStatusFormCommand) command;
                QFormModel qFormModel = forms[formIndex.famg].getModel();
                qFormModel.setSearchState(searchStatusCommand.getSearchState());
                break;
            }
            case FormCommand.SET_UPDATE_STATUS: {
                SetUpdateStatusFormCommand theCommand
                        = (SetUpdateStatusFormCommand) command;
                QFormModel qFormModel = forms[formIndex.famg].getModel();
                qFormModel.setDataUpdatedState(theCommand.getUpdateState());
                break;
            }
            case FormCommand.SET_DELETE_STATUS: {
                SetDeleteStatusFormCommand theCommand
                        = (SetDeleteStatusFormCommand) command;
                QFormModel qFormModel = forms[formIndex.famg].getModel();
                qFormModel.setDeleteState(theCommand.getDeleteStatus());
                break;
            }
            case FormCommand.SET_CREATE_STATUS: {
                SetNewEntityStatusFormCommand theCommand
                        = (SetNewEntityStatusFormCommand) command;
                QFormModel qFormModel = forms[formIndex.famg].getModel();
                qFormModel.setCreateState(theCommand.getNewState());
                break;
            }
            case FormCommand.SET_LOCK_FOR_EDIT_STATUS: {
                SetLockForEditStatusFormCommand theCommand
                        = (SetLockForEditStatusFormCommand) command;
                QFormModel qFormModel = forms[formIndex.famg].getModel();
                qFormModel.setLockForEditState(
                        theCommand.getLockForEditState());
                break;
            }
            case FormCommand.GET_CAN_FORM_BE_TURNED: {
                performedSuccessfully = forms[formIndex.famg]
                        .getFormController().canFormChangeState();
                break;
            }
            case FormCommand.SET_ON_DEMAND_CONTROL_DATA: {
                SetOnDemandDataForControlCommand theCommand
                        = (SetOnDemandDataForControlCommand) command;
                forms[formIndex.famg].getModel().setOnDemandDataForElement(
                        theCommand.getData());
                break;
            }
            case FormCommand.TURN_FORM_TO_STATE: {
                TurnFormToStateCommand turnCommand
                        = (TurnFormToStateCommand) command;
                try {
                    performedSuccessfully = forms[formIndex.famg]
                            .getFormController().setFormState(
                            turnCommand.getFormState());
                } catch (IncorrectFormStateSelected incorrectFormStateSelected) {
                    performedSuccessfully = false;
                    DialogHelper.showModalErrorDialog(
                            incorrectFormStateSelected);
                }
                break;
            }
            default: {
                performedSuccessfully = false;
            }
        }
        return performedSuccessfully;
    }

    private void setData(FieldData[] data, Long rowID, FamgMeta.Index formIndex,
                         boolean clearOtherFields) {
        QFormModel model = forms[formIndex.famg].getModel();
        if(rowID != null) {
            model.setActiveRowID(rowID);
        }
        model.setDataForElements(data, clearOtherFields);
    }

    public void onEvent(Event event, Widget sender) {
        if(QFormController.Events.FORM_CONTROL_DATA_CHANGED == event) {
            ControlChangedData eventData = (ControlChangedData) event.getData();
            QForm form = getForm(eventData.index);
            if(form != null) {
                FamgMeta.Index formIndex = form.getModel().getIndex();
                FamgMeta meta = famgsMeta[formIndex.famg];
                Set events = viewPropertiesProvider
                        .getFormControlListeningEvents(meta.getFormID(),
                                eventData.controlId);
                if(events.contains(FormControlEventTypes.ON_CHANGE)) {
                    eventSource.fireEvent(event);
                }
            }
        } else {
            eventSource.fireEvent(event);
        }
    }

    void initialized() {
        // new {{{
        for(int i = 0; i < forms.length; i++) {
            forms[i].getFormController().onInit();
        }
        // new }}}
        eventSource.fireEvent(Events.TAB_INITIALIZED);
    }

    void whenScrolling() {
        forms[activeForm].getFormController().whenScrolling();
    }

    boolean isInEditMode() {
        for(int i = 0; i < forms.length; i++) {
            if(forms[i] != null) {
                int state = forms[i].getModel().getFormState();
                if((state == FormState.EDIT_STATE) || (state == FormState
                        .NEW_STATE)) {
                    return true;
                }
            }
        }
        return false;
    }

    void collectUISettings() {
        for(int i = 0; i < forms.length; i++) {
            forms[i].getFormController().collectUISettings();
        }
    }

    void onActivated() {
        getEventSource().fireEvent(Events.FORM_ACTIVATED);
        for(int i = 0; i < forms.length; i++) {
            forms[i].getFormController().onActivated();
        }
    }

    public FamgMeta.Index getNextExistingFormIndex(int famg) {
        FamgMeta.Index ret = null;
        for(int i = famg + 1; i < forms.length; i++) {//take next index
            if(forms[i] != null) {
                ret = famgsMeta[i].getIndex();
                break;
            }
        }
        return ret;
    }

    public String getHelpLink() {
        return helpLink;
    }
}
