/*
 * 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.SourcesTabEvents;
import com.google.gwt.user.client.ui.TabListener;
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.SubFocusMeta;
import com.queplix.core.client.app.vo.TabMeta;
import com.queplix.core.client.common.event.Event;
import com.queplix.core.client.common.event.EventSource;
import com.queplix.core.client.common.ui.QTabPanel;
import com.queplix.core.client.common.ui.WindowHelper;
import com.queplix.core.client.common.ui.resizable.ResizableLazyDeckPanel;
import com.queplix.core.client.controls.form.QForm;
import com.queplix.core.client.frames.mainframe.ViewPropertiesProvider;

/**
 * Postfix FA - Form Area.
 * On tab(Focus->Sub Focus->Tab not QTabPanel tab) change you should select
 * corresponding TabFA in this class to show correct contents.
 * On tab(of QTabPanel) change you should do
 * tabsFA[selected Tab].activateTab(selected QTabPanel);
 * Class MainFrameFA contains array of FocusFA.
 * Class class FocusFA contains array of SubFocusFA.
 * This SubFocusFA contains array of TabFA.
 * Class TabFA contains array of QForm.
 *
 * @author Aliaksandr Melnik
 * @since 19 Oct 2006
 */
class SubFocusFA extends QTabPanel {
    private ViewPropertiesProvider viewPropertiesProvider;

    // -------------------- public events ------------------------
    public static interface Events extends TabFA.Events {
        Event TAB_SELECTED_EVENT = new Event();
    }

    private EventSource eventSource = new EventSource(this);

    private boolean isSelectedByCode = false;

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

    private TabFA[] tabsFA;
    private TabMeta[] tabsMeta;

    private int activeTab = -1;

    private String status;

    private boolean fireInitialization;

    private FamgMeta.Index indexToActivate;

    public SubFocusFA(final SubFocusMeta subFocusMeta,
                      ViewPropertiesProvider viewPropertiesProvider,
                      boolean fireInitialization,
                      FamgMeta.Index indexToActivate) {
        super(TAB_LAYOUT_VERTICAL);
        this.viewPropertiesProvider = viewPropertiesProvider;
        this.indexToActivate = indexToActivate == null
                ? ResizableLazyDeckPanel.DEFAULT_INDEX_TO_ACTIVATE
                :indexToActivate;
        WindowHelper.disableSelection(getTabBar().getElement());
        this.fireInitialization = fireInitialization;
        this.addStyleName("white_bg");

        status = Application.getStatus();

        tabsMeta = subFocusMeta.getTabs();
        tabsFA = new TabFA[tabsMeta.length];

        for(int i = 0; i < tabsMeta.length; i++) {
            addCard(tabsMeta[i].getCaption());
        }
        if(tabsMeta.length > 0) {
            selectTab(indexToActivate.tab);
        }

        addTabListener(new TabListener() {
            public boolean onBeforeTabSelected(SourcesTabEvents sender,
                                               int index) {
                if(!isSelectedByCode) { // user click
                    TabMeta.Index tabIndex = new TabMeta.Index();
                    tabIndex.init(subFocusMeta.getIndex(), index);
                    Events.TAB_SELECTED_EVENT.setData(tabIndex);
                    eventSource.fireEventGeneratedByUser(
                            Events.TAB_SELECTED_EVENT);
                    return false; // postpone switching tab
                } else {
                    return true; // switch tab
                }
            }

            public void onTabSelected(SourcesTabEvents sender, int index) {
            }
        });
    }

    public void setFormsState(int formState) {
        for(int i = 0; i < tabsFA.length; i++) {
            if(tabsFA[i] != null) {
                tabsFA[i].setFormsState(formState);
            }
        }
    }

    public QForm getForm(FamgMeta.Index index) {
        QForm ret = null;
        TabFA tabFA = tabsFA[index.tab];
        if(tabFA != null) {
            ret = tabFA.getForm(index);
        }
        return ret;
    }

    public TabFA getTab(TabMeta.Index index) {
        return tabsFA[index.tab];
    }

    public QForm getActiveForm() {
        return tabsFA[activeTab].getActiveForm();
    }

    public void activateForm(FamgMeta.Index index) {
        activateTab(index);
        tabsFA[activeTab].activateForm(index);
    }

    public void activateTab(TabMeta.Index index) {
        if(index.tab != activeTab) {
            selectTab(index.tab);
        }
    }

    public void selectTab(int index) {
        activateTab(index);
        isSelectedByCode = true;
        super.selectTab(index);
        isSelectedByCode = false;
    }

    private void activateTab(int index) {
        if(activeTab != index) {
            activeTab = index;
            init(index);
        }
    }

    private void init(int index) {
        TabFA tabFA = tabsFA[index];
        if(tabFA == null) {
            if(index == 0) {
                Application.setStatus(
                        status + " -> tab: " + tabsMeta[index].getCaption());
            }
            tabFA = new TabFA(tabsMeta[index], viewPropertiesProvider);
            tabsFA[index] = tabFA;
            tabFA.getEventSource().addEventListener(
                    eventSource); // retranslate events

            remove(index);
            insert(tabFA, tabsMeta[index].getCaption(), index);
            if(fireInitialization) {
                initialized();
            }
            fireInitialization = true;
        }
        tabFA.onActivated();
    }

    public TabMeta.Index getSelectedTabIndex() {
        return tabsMeta[activeTab].getIndex();
    }

    public FamgMeta.Index getSelectedFormIndex() {
        return tabsFA[activeTab].getSelectedFormIndex();
    }

    public boolean performCommand(FormCommand command,
                                  FamgMeta.Index formIndex) {
        return tabsFA[formIndex.tab].performCommand(command, formIndex);
    }

    void initialized() {
        tabsFA[activeTab].initialized();
    }

    public void onScroll(Widget widget, int scrollLeft, int scrollTop) {
        tabsFA[activeTab].whenScrolling();
    }

    public void ensureVisibility(FamgMeta.Index index) {
        getResizableScrollPanel(index.tab).ensureVisible(
                getActiveForm().getView());
    }

    boolean isInEditMode() {
        for(int i = 0; i < tabsFA.length; i++) {
            if(tabsFA[i] != null) {
                if(tabsFA[i].isInEditMode()) {
                    return true;
                }
            }
        }
        return false;
    }

    void collectUISettings() {
        for(int i = 0; i < tabsFA.length; i++) {
            if(tabsFA[i] != null) {
                tabsFA[i].collectUISettings();
            }
        }
    }

    public FamgMeta.Index getNextExistingFormIndex(int tab, int famg) {
        FamgMeta.Index ret = null;
        for(int i = tab; i < tabsFA.length; i++) {
            if(tabsFA[i] != null) {
                FamgMeta.Index nextIndex = tabsFA[i].getNextExistingFormIndex(
                        famg);
                if(nextIndex != null) {
                    ret = nextIndex;
                    break;
                }
            }
            famg = -1;//it will be incremented on tab level
        }
        return ret;
    }
}
