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

import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Widget;
import com.queplix.core.client.app.vo.FieldData;
import com.queplix.core.client.app.vo.FieldDataRequest;
import com.queplix.core.client.app.vo.FieldMeta;
import com.queplix.core.client.app.vo.FieldOnDemandData;
import com.queplix.core.client.app.vo.TextboxFieldData;
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.FormControlListener;
import com.queplix.core.client.controls.QButton;
import com.queplix.core.client.controls.QFormElement;
import com.queplix.core.client.controls.QFormElementView;
import com.queplix.core.client.controls.form.event.FormStateChangedData;
import com.queplix.core.client.controls.form.event.ControlChangedData;
import com.queplix.core.client.controls.memo.QMemo;
import com.queplix.core.client.frames.mainframe.FormState;
import com.queplix.core.client.i18n.I18N;

import java.util.ArrayList;
import java.util.List;

/**
 * QueWeb QForm Controller Implementation
 *
 * @author Sergey Kozmin
 * @since 21 Sep 2006
 */
class QFormControllerImpl implements QFormController, QModelStateListener,
        FormControlListener {

    private static final String INCORRECT_STATE_CHANGE
            = "Internal error. Unit wants to change to uncknown QForm state. ";

    private QFormViewImpl view;
    private QFormModelImpl model;

    private QFormState searchState = new SearchFormState();
    private QFormState selectedState = new SelectedFormState();
    private QFormState newState = new NewFormState();
    private QFormState editState = new EditFormState();
    private QFormState reportDesignState = new ReportDesignFormState();
    private QFormState previousState = new PreviousFormState();

    private QFormState currentState;

    /**
     * list that holds units of chain. Class implements "Chain of Responsibility" pattern
     * to handle responses from server.
     */
    private ArrayList unitsList = new ArrayList();
    private ActionContext context = new ActionContext();

    // -------------------- public events ------------------------
    private EventSource eventSource;

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

    public QFormControllerImpl(QFormViewImpl view, final QFormModelImpl model) {
        this.view = view;
        this.model = model;
        currentState = searchState;
        currentState.enterToState(QFormState.UNKNOWN_STATE);
        view.setDataRequirementsListener(this);
        model.addStateListener(this);
        model.addDataListener(new QFormDataListener() {
            public void dataStructureChanged() {
                currentState.enterToState(previousState.getState());
            }

            public void dataChanged(String elementId) {
            }

            public void dataOnDemandCome(FieldOnDemandData data) {
            }
        });
        eventSource = new EventSource(view);
        if(view.hasAdditionalActions()){
            view.getContextMenuEventSource().addEventListener(new EventListener() {
                public void onEvent(Event event, Widget sender) {
                    onContextMenuEvent(event);
                }
            });
        }
        view.getFormElementsEventSource().addEventListener(new EventListener() {
            public void onEvent(Event event, Widget sender) {
                if(event == QFormElementView.Events
                        .FORM_ELEMENT_REPORT_DESIGN_EVENT) {
                    onFormElementReportDesignEvent(event);
                } else if(event == Events.FORM_NEW_BUTTON_EVENT ||
                        event == Events.FORM_UPDATE_BUTTON_EVENT ||
                        event == Events.FORM_CHANGE_BUTTON_EVENT ||
                        event == Events.FORM_CLEAR_BUTTON_EVENT ||
                        event == Events.FORM_SEARCH_BUTTON_EVENT) {
                    if(event == Events.FORM_CLEAR_BUTTON_EVENT) {
                        //select form before clean event, do not move from here
                        QFormController.Events.FORM_SELECTION_REQUESTED_EVENT
                                .setData(model.getIndex());
                        eventSource.fireEvent(
                                QFormController.Events.FORM_SELECTION_REQUESTED_EVENT);
                    }
                    performAction(event);
                } else if(event.getData() != null && event
                        .getData() instanceof QButton.CustomButtonEventData) {
                    Event customButtonEvent
                            = QFormController.Events.FORM_CUSTOM_BUTTON;
                    customButtonEvent.setData(event.getData());
                    customButtonEvent.setUserGenerated(true);
                    fireExternalEvent(customButtonEvent, true);
                    customButtonEvent.setUserGenerated(
                            false); // reset to a safe value
                } else {
                    fireExternalEvent(event, true);
                }
            }
        });
    }

    public int getCurrentState() {
        return currentState.getState();
    }

    public String getRecordEditingMessage() {
        return I18N.getMessages().formDiscardChanges(model.getFormTitle());
    }

    private void onContextMenuEvent(Event event) {
        QFormController.Events.FORM_MENU_ITEM.setData(event.getData());
        fireExternalEvent(QFormController.Events.FORM_MENU_ITEM, true);
    }

    private void onFormElementReportDesignEvent(Event event) {
        QFormController.Events.FORM_ELEMENT_REPORT_DESIGN_EVENT.setData(
                event.getData());
        fireExternalEvent(
                QFormController.Events.FORM_ELEMENT_REPORT_DESIGN_EVENT, true);
    }

    protected void fireExternalEvent(Event action, boolean selectForm) {
        if(selectForm &&
                !(view.isSelected() ||
                        QFormController.Events.FORM_SELECTION_REQUESTED_EVENT
                                .equals(action) ||
                        QFormController.Events.FORM_STATE_CHANGED_EVENT.equals(
                                action))) {//we do not want to send selection_request event if the event is already selection request, or form_state_changed
            QFormController.Events.FORM_SELECTION_REQUESTED_EVENT.setData(
                    model.getIndex());
            eventSource.fireEvent(
                    QFormController.Events.FORM_SELECTION_REQUESTED_EVENT);//select this form, and then send real event.
        }
        eventSource.fireEvent(action);
    }

    protected void fireFormStateChangedEvent(int newState) {
        FormStateChangedData data = new FormStateChangedData();
        data.newFormState = newState;
        QFormController.Events.FORM_STATE_CHANGED_EVENT.setData(data);
        fireExternalEvent(QFormController.Events.FORM_STATE_CHANGED_EVENT,
                true);
    }

    protected void fireDataRequest(FieldDataRequest request) {
        QFormController.Events.FORM_CONTROL_NEED_MORE_DATA_EVENT.setData(
                request);
        fireExternalEvent(
                QFormController.Events.FORM_CONTROL_NEED_MORE_DATA_EVENT, true);
    }

    protected void fireDataChangeEvent(String controlId) {
        fireDataChangeEvent(controlId, true);
    }

    protected void fireDataChangeEvent(String controlId, boolean selectForm) {
        ControlChangedData data = new ControlChangedData();
        data.index = model.getIndex();
        data.controlId = controlId;
        QFormController.Events.FORM_CONTROL_DATA_CHANGED.setData(data);
        fireExternalEvent(
                QFormController.Events.FORM_CONTROL_DATA_CHANGED, selectForm);
    }

    public void performAction(Event commonButtonIndex) {
        try {
            currentState.actionPerformed(commonButtonIndex);
        } catch (IncorrectFormActionPerformed incorrectFormActionPerformed) {
            DialogHelper.showModalErrorDialog(incorrectFormActionPerformed);
        }
    }

    protected boolean turnToState(QFormState newState) {
        boolean wasTurned;
        if(!currentState.equals(newState)) {
            wasTurned = currentState.canFromExitState();
            if(wasTurned) {
                view.setStateIcon(newState.getState());
                previousState = currentState;
                currentState.exitFromState();
                currentState = newState;
                currentState.enterToState(previousState.getState());
                model.setFormState(currentState.getState());
            }
        } else {
            wasTurned = true;
        }
        return wasTurned;
    }

    public void formStateChanged() {
        if(model.getFormState() != currentState.getState()) {
            switch(model.getFormState()) {
                case FormState.EDIT_STATE: {
                    turnToState(editState);
                    break;
                }
                case FormState.NEW_STATE: {
                    turnToState(newState);
                    break;
                }
                case FormState.SEARCH_STATE: {
                    turnToState(searchState);
                    break;
                }
                case FormState.SELECTED_STATE: {
                    turnToState(selectedState);
                    break;
                }
                case FormState.REPORT_DESIGN_STATE: {
                    turnToState(reportDesignState);
                    break;
                }
            }
        }
        fireFormStateChangedEvent(model.getFormState());
    }

    protected void addUnitToChain(ChainUnit newUnit) {
        unitsList.add(newUnit);
    }

    protected void fireInternalEvent(int eventId) {
        for(int i = 0; i < unitsList.size(); i++) {
            ChainUnit unit = (ChainUnit) unitsList.get(i);
            try {
                if(unit.isAccepted(eventId)) {
                    unit.removingFromChain();
                    unitsList.remove(unit);
                    unit.handleEvent(eventId);
                    break;
                }
            } catch (IncorrectFormActionPerformed incorrectFormActionPerformed) {
                DialogHelper.showModalErrorDialog(incorrectFormActionPerformed);
            }
        }
    }

    public void formDataUpdateStateChanged(int dataUpdatedState) {
        switch(dataUpdatedState) {
            case QFormModel.UPDATE_SUCCESSFUL: {
                fireInternalEvent(ChainUnit.UPDATE_SUCCESSFUL);
                break;
            }
            case QFormModel.UPDATE_FAILED: {
                fireInternalEvent(ChainUnit.UPDATE_FAILED);
                break;
            }
        }
    }

    public void formLockForEditStateChanged(int lockForEditState) {
        switch(lockForEditState) {
            case QFormModel.LOCK_FOR_EDIT_SUCCESSFUL: {
                fireInternalEvent(ChainUnit.LOCK_FOR_EDIT_SUCCESSFUL);
                break;
            }
            case QFormModel.LOCK_FOR_EDIT_FAILED: {
                fireInternalEvent(ChainUnit.LOCK_FOR_EDIT_FAILED);
                break;
            }
        }
    }

    public void formSearchStateChanged(int searchState) {
        switch(searchState) {
            case QFormModel.SEARCH_SUCCESSFUL_SINGLE: {
                fireInternalEvent(ChainUnit.SEARCH_SUCCESSFUL_SINGLE);
                break;
            }
            case QFormModel.SEARCH_FAILED: {
                fireInternalEvent(ChainUnit.SEARCH_FAILED);
                break;
            }
        }
    }

    public void formDeleteStateChanged(int deleteState) {
        switch(deleteState) {
            case QFormModel.DELETE_SUCCESSFUL: {
                fireInternalEvent(ChainUnit.DELETE_SUCCESSFUL);
                break;
            }
            case QFormModel.DELETE_FAILED: {
                fireInternalEvent(ChainUnit.DELETE_FAILED);
                break;
            }
        }
    }

    public void formNewStateChanged(int newState) {
        switch(newState) {
            case QFormModel.NEW_SUCCESSFUL: {
                fireInternalEvent(ChainUnit.NEW_SUCCESSFUL);
                break;
            }
            case QFormModel.NEW_FAILED: {
                fireInternalEvent(ChainUnit.NEW_FAILED);
                break;
            }
        }
    }

    public void uploadDataToModel() {
        ArrayList ids = model.elementsKeys();
        for(int i = 0, n = ids.size(); i < n; i++) {
            String key = (String) ids.get(i);
            uploadDataToModel(key);
        }
    }

    public void uploadDataToModel(String controlId) {
        QFormElement formElement = view.getControl(controlId);
        if(formElement != null) {
            uploadDataToElementModel(
                    formElement);//todo review, seems to be incorrect
            FieldData newModelElementData = view.getControl(controlId)
                    .getBaseModel().getBaseData();
            model.setDataForElement(newModelElementData);
        }
    }

    /**
     * @deprecated form logic shoudldn't know about the element types in it.
     */
    private void uploadDataToElementModel(QFormElement formElement) {
        int dataType = formElement.getBaseModel().getBaseMeta().getDataType();
        switch(dataType) {
            case FieldMeta.MEMO:
                //firefox workaround
                QMemo memo = (QMemo) formElement;
                if(memo.getModel().getMeta().isInline()) {
                    memo.getController().uploadDataToModel();
                }
                break;
        }
    }

    /**
     * Notifies form elements that form valid.
     * @deprecated form logic shoudldn't know about the element types in it.
     */
    private void formIsValid() {
        ArrayList ids = model.elementsKeys();
        for (int i = 0, n = ids.size(); i < n; i++) {
            String key = (String) ids.get(i);
            QFormElement formElement = view.getControl(key);
            if (formElement != null) {
                notifyElement(formElement, true);
            }
        }
    }

    /**
     * @deprecated form logic shoudldn't know about the element types in it.
     */
    private void notifyElement(QFormElement formElement, boolean isValid) {
        int dataType = formElement.getBaseModel().getBaseMeta().getDataType();
        switch (dataType) {
            case FieldMeta.MEMO:
                QMemo memo = (QMemo) formElement;
                if (memo.getModel().getMeta().isInline()) {
                    if (isValid) {
                        memo.getController().applyModification();
                    } else {
                        memo.getController().revertModification();
                    }
                }
            break;
        }
    }

    /**
     * Notifies form elements that form invalid.
     * @deprecated form logic shoudldn't know about the element types in it.
     */
    private void formIsInvalid() {
        ArrayList ids = model.elementsKeys();
        for (int i = 0, n = ids.size(); i < n; i++) {
            String key = (String) ids.get(i);
            QFormElement formElement = view.getControl(key);
            if (formElement != null) {
                notifyElement(formElement, false);
            }
        }
    }
    
    public void clearForm() {
        ArrayList ids = model.elementsKeys();
        model.clearActiveRowID();

        for(int i = 0, n = ids.size(); i < n; i++) {
            String elementID = (String) ids.get(i);
            model.clearElementData(elementID);
        }
    }

    public boolean setFormState(int formState)
            throws IncorrectFormStateSelected {
        try {
            return turnToState(getStateObject(formState));
        } catch (IncorrectFormActionPerformed incorrectFormActionPerformed) {
            throw new IncorrectFormStateSelected(incorrectFormActionPerformed,
                    formState);
        }
    }

    public void resetAndSetFormState(int formState)
            throws IncorrectFormStateSelected {
        unitsList.clear();//clear all waiting processes
        resetAllStates();//reset all form states
        setFormState(
                formState);//set form to state with no case to not do that.
    }

    private void resetAllStates() {
        searchState.resetState();
        selectedState.resetState();
        newState.resetState();
        editState.resetState();
        reportDesignState.resetState();
        previousState.resetState();
    }

    public boolean canFormChangeState() {
        return currentState.canFromExitState();
    }

    private QFormState getStateObject(int newQFormState)
            throws IncorrectFormActionPerformed {
        QFormState state;
        switch(newQFormState) {
            case FormState.NEW_STATE:
                state = newState;
                break;
            case FormState.EDIT_STATE:
                state = editState;
                break;
            case FormState.SEARCH_STATE:
                state = searchState;
                break;
            case FormState.SELECTED_STATE:
                state = selectedState;
                break;
            case FormState.REPORT_DESIGN_STATE:
                state = reportDesignState;
                break;
            case QFormState.PREVIOUS_STATE:
                state = previousState;
                break;
            default:
                throw new IncorrectFormActionPerformed(INCORRECT_STATE_CHANGE);
        }
        return state;
    }

    private boolean isEmptyRequired() {
        ArrayList ids = model.elementsKeys();
        String message = "The following required fields are empty: ";
        boolean noEmpty = true;
        for(int i = 0, n = ids.size(); i < n; i++) {
            String id = (String) ids.get(i);
            FieldData fieldData = model.getElementData(id);
            FieldMeta fieldMeta = model.getElementMeta(id);
            if(fieldData != null &&
                    fieldData.isEmpty() &&
                    fieldMeta.isRequired()) {
                message = message + "\n [" + fieldMeta.getCaption() + "]";
                noEmpty = false;
            }
        }
        if(!noEmpty) {
            DialogHelper.showModalMessageDialog(message + ". ");
        }
        return noEmpty;
    }

    public void needMoreData(FieldDataRequest request) {
        fireDataRequest(request);
    }

    public void controlDataChanged(String controlId) {
        fireDataChangeEvent(controlId, false);
    }

    private void search() {
        boolean searchSucc = setFormState(FormState.SEARCH_STATE);
        if(!searchSucc) {
            DialogHelper.showModalMessageDialog(
                    "Could not search, wasn't able to set 'search' form state. ");
        } else {
            performAction(QFormController.Events.FORM_SEARCH_BUTTON_EVENT);
        }
    }

    public void searchByPkey(Long pkey) {
        clearForm();
        FieldData fieldData = model.getElementData(model.getPkeyID());
        FieldMeta fieldMeta = model.getElementMeta(model.getPkeyID());
        if(fieldMeta.getDataType() == FieldMeta.TEXTBOX) {
            ((TextboxFieldData) fieldData).setText(String.valueOf(pkey));
        }
        this.search();
    }

    public void searchByData(FieldData[] fieldData) {
        for(int i = 0; i < fieldData.length; i++) {
            model.setDataForElement(fieldData[i]);
        }
        search();
    }

    public void whenScrolling() {
        view.hideContextMenu();
    }

    public void collectUISettings() {
        view.collectUISettings();
        model.getFormMeta().setUISettings(view.getUISettings());
    }

    public void onInit() {
        view.onInit();
    }

    private class SearchFormState extends QFormStateAdapter {
        public int getState() {
            return SEARCH_STATE;
        }

        public void enterToState(int previusState) {
            view.allowModificationsForSearch();
            view.showChangeButton();
            view.enableAllCommonButtons();
            view.disableCommonChangeButton();
            view.setCustomButtonsEnabled(true);
        }

        public void actionPerformed(Event action)
                throws IncorrectFormActionPerformed {
            if(QFormController.Events.FORM_NEW_BUTTON_EVENT.equals(action)) {
                addUnitToChain(new NewUnit(context));
                fireExternalEvent(QFormController.Events.FORM_NEW_BUTTON_EVENT,
                        true);
            } else if(QFormController.Events.FORM_CLEAR_BUTTON_EVENT.equals(
                    action)) {
                clearForm();
                fireExternalEvent(
                        QFormController.Events.FORM_CLEAR_BUTTON_EVENT, false);
            } else if(QFormController.Events.FORM_SEARCH_BUTTON_EVENT.equals(
                    action)) {
                uploadDataToModel();
                addUnitToChain(new SearchUnit(context));
                fireExternalEvent(
                        QFormController.Events.FORM_SEARCH_BUTTON_EVENT, true);
            } else {
                fireExternalEvent(action, true);
            }
        }
    }

    private class SelectedFormState extends QFormStateAdapter {
        public int getState() {
            return SELECTED_STATE;
        }

        public void enterToState(int previusState) {
            view.showChangeButton();
            view.denyModifications();
            view.enableAllCommonButtons();
            view.setCustomButtonsEnabled(true);
        }

        public void actionPerformed(Event action)
                throws IncorrectFormActionPerformed {
            if(QFormController.Events.FORM_NEW_BUTTON_EVENT.equals(action)) {
                addUnitToChain(new NewUnit(context));
                fireExternalEvent(QFormController.Events.FORM_NEW_BUTTON_EVENT,
                        true);
            } else if(QFormController.Events.FORM_CHANGE_BUTTON_EVENT.equals(
                    action)) {
                addUnitToChain(new LockForEditUnit(context));
                fireExternalEvent(
                        QFormController.Events.FORM_CHANGE_BUTTON_EVENT, true);
            } else if(QFormController.Events.FORM_CLEAR_BUTTON_EVENT.equals(
                    action)) {
                clearForm();
                turnToState(searchState);
                fireExternalEvent(
                        QFormController.Events.FORM_CLEAR_BUTTON_EVENT, false);
            } else if(QFormController.Events.FORM_SEARCH_BUTTON_EVENT.equals(
                    action)) {
                addUnitToChain(new SearchUnit(context));
                fireExternalEvent(
                        QFormController.Events.FORM_SEARCH_BUTTON_EVENT, true);
            } else {
                fireExternalEvent(action, true);
            }
        }
    }

    private class EditFormState extends QFormStateAdapter
            implements BaseChainUnit.ChainAcceptanceListener {
        private int criticalListenersCounter = 0;

        public int getState() {
            return EDIT_STATE;
        }

        public void enterToState(int previusState) {
            view.showUpdateButton();
            view.enableAllCommonButtons();
            view.disableCommonNewButton();
            view.disableCommonSearchButton();
            view.allowModificationsForEdit();
            view.setCustomButtonsEnabled(true);
        }
        
        public void actionPerformed(Event action)
                throws IncorrectFormActionPerformed {
            if(QFormController.Events.FORM_UPDATE_BUTTON_EVENT.equals(action)) {
                uploadDataToModel();
                if(isEmptyRequired()) {
                    formIsValid();
                    UpdateUnit updateUnit = new UpdateUnit(context);
                    updateUnit.addChainAcceptanceListener(this);
                    criticalListenersCounter++;
                    addUnitToChain(updateUnit);
                    fireExternalEvent(
                            QFormController.Events.FORM_UPDATE_BUTTON_EVENT,
                            true);
                } else {
                    formIsInvalid();
                }
            } else if(QFormController.Events.FORM_CLEAR_BUTTON_EVENT.equals(
                    action)) {
                if(DialogHelper.showModalQuestionDialog(
                        getRecordEditingMessage()) == DialogHelper.YES) {
                    clearForm();
                    turnToState(searchState);
                    fireExternalEvent(
                            QFormController.Events.FORM_CLEAR_BUTTON_EVENT,
                            false);
                }
            } else {
                fireExternalEvent(action, true);
            }
        }

        public boolean canFromExitState() {
            return criticalListenersCounter == 0;
        }

        public void resetState() {
            criticalListenersCounter = 0;
        }

        public void accepted() {
            criticalListenersCounter--;
        }
    }

    private class NewFormState extends QFormStateAdapter
            implements BaseChainUnit.ChainAcceptanceListener {
        private int criticalListenersCounter = 0;

        public int getState() {
            return NEW_STATE;
        }

        public void enterToState(int previusState) {
            view.showUpdateButton();
            view.enableAllCommonButtons();
            view.disableCommonNewButton();
            view.disableCommonSearchButton();
            view.setEnabledForNew();
            view.setCustomButtonsEnabled(true);
        }

        public void actionPerformed(Event action)
                throws IncorrectFormActionPerformed {
            if(QFormController.Events.FORM_UPDATE_BUTTON_EVENT.equals(action)) {
                uploadDataToModel();
                if(isEmptyRequired()) {
                    formIsValid();
                    UpdateUnit updateUnit = new UpdateUnit(context);
                    updateUnit.addChainAcceptanceListener(this);
                    criticalListenersCounter++;
                    addUnitToChain(updateUnit);
                    fireExternalEvent(
                            QFormController.Events.FORM_UPDATE_BUTTON_EVENT,
                            true);
                } else {
                    formIsInvalid();
                }
            } else if(QFormController.Events.FORM_CLEAR_BUTTON_EVENT.equals(
                    action)) {
                if(DialogHelper.showModalQuestionDialog(
                        getRecordEditingMessage()) == DialogHelper.YES) {
                    clearForm();
                    turnToState(searchState);
                    fireExternalEvent(
                            QFormController.Events.FORM_CLEAR_BUTTON_EVENT,
                            false);
                }
            } else {
                fireExternalEvent(action, true);
            }
        }

        public boolean canFromExitState() {
            return criticalListenersCounter == 0;
        }

        public void resetState() {
            criticalListenersCounter = 0;
        }

        public void accepted() {
            criticalListenersCounter--;
        }
    }

    private class ReportDesignFormState extends QFormStateAdapter {
        public int getState() {
            return REPORT_DESIGN_STATE;
        }

        public void enterToState(int previusState) {
            view.showChangeButton();
            view.disableCommonChangeButton();
            view.disableCommonNewButton();
            view.disableCommonSearchButton();
            view.disableCommonClearButton();
            view.allowModificationsForReportDesign();
            view.setCustomButtonsEnabled(false);
        }
    }

    /**
     * just return form to previous state
     */
    private class PreviousFormState extends QFormStateAdapter {
        public int getState() {
            return PREVIOUS_STATE;
        }

        public void enterToState(int previusState) {
            turnToState(previousState);
        }
    }

    private class ActionContext implements ChainUnitContext {
        public void changeState(int newQFormState)
                throws IncorrectFormActionPerformed {
            turnToState(getStateObject(newQFormState));
        }
    }

    public void onActivated() {
        if(model.getFormMeta().isAutoSearch()) {
            (new Timer() {
                public void run() {
                    fireExternalEvent(
                            QFormController.Events.FORM_SEARCH_BUTTON_EVENT,
                            true);
                }
            }).schedule(50);
        }
    }
}
