/*
 * 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.modules.config.ejb;

import com.queplix.core.integrator.security.PermissionObjectType;
import com.queplix.core.modules.config.jxb.Button;
import com.queplix.core.modules.config.jxb.ExternalField;
import com.queplix.core.modules.config.jxb.ExternalSet;
import com.queplix.core.modules.config.jxb.Focus;
import com.queplix.core.modules.config.jxb.Form;
import com.queplix.core.modules.config.jxb.Htmlelement;
import com.queplix.core.modules.config.jxb.Htmlelements;
import com.queplix.core.modules.config.jxb.SubFocus;
import com.queplix.core.modules.config.jxb.Tab;
import com.queplix.core.modules.config.utils.ConfigPropertyFactory;
import com.queplix.core.modules.config.utils.EntityHelper;
import com.queplix.core.modules.config.utils.ViewObject;
import com.queplix.core.modules.config.utils.ViewObjectsStructure;
import com.queplix.core.utils.JNDINames;
import com.queplix.core.utils.cache.Cache;
import com.queplix.core.utils.ejb.AbstractSessionEJB;
import com.queplix.core.utils.xml.XMLFactory;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Facade EJB for Focus management.
 *
 * @author [ALB] Baranov Andrey
 * @author Kozmin Sergey
 * @since 2007.01.24
 */

public class FocusConfigManagerEJB extends AbstractSessionEJB {
    /**
     * Initialize bean
     */
    public void ejbCreate() {
        INFO("FocusConfigManagerEJB create - " + hashCode());
    }


    /**
     * Fill array of Focus objects.
     *
     * @param focuses array of Focus objects
     */
    public void fillFocuses(List<Focus> focuses) {
        long time = System.currentTimeMillis();
        INFO("Try to fill All Focus objects");

        //clearing the cache
        Cache cache = ConfigPropertyFactory.getInstance().getViewObjectsCache();
        cache.clear();

        //retrieve all the view objects, stored in DB
        ViewObjectsStructure existingObjects = ConfigPropertyFactory
                .getInstance().getViewObjectsDAO().loadViewObjects();

        ViewObjectsStructure toUpdate = parseFocuses(focuses, existingObjects);

        //delete obsolete objects
        deleteObsoleteViewObjects(existingObjects);

        //create new and or update existing objects 
        updateViewObjects(toUpdate);

        //update form settings tables
        updateFormSettingsTables(toUpdate.getForms(), focuses);

        updateLocalizations(focuses);

        INFO("Fill all focus configs - ok. Count " + focuses.size()
                + ". Time (ms): " + (System.currentTimeMillis() - time));
    }

    private void updateLocalizations(List<Focus> focuses) {
        for(Focus focus : focuses) {
            // Insert captions.
            updateLocalization(focus);
        }
    }

    private void updateFormSettingsTables(Map<String, ViewObject> forms,
                                          List<Focus> focuses) {
        Map<ViewObject, Form> updatingStructure
                = new HashMap<ViewObject, Form>();
        List<Tab> tabs = new ArrayList<Tab>();
        //iterate all forms
        for(Focus focus : focuses) {
            for(SubFocus subFocus : focus.getSubFocus()) {
                for(Tab tab : subFocus.getTab()) {
                    tabs.add(tab);
                    for(Form form : tab.getForm()) {
                        String formName = form.getName();
                        if(forms.containsKey(
                                formName)) {//check if form exists in updating tables. It always should equals true
                            updatingStructure.put(forms.get(formName), form);
                        } else {
                            WARN("Form [" + formName
                                    + "] exists in xml, but wasn't added to DB.");
                        }
                    }
                }
            }
        }
        ConfigPropertyFactory.getInstance().getViewObjectsDAO()
                .updateExternalTabValues(tabs);
        ConfigPropertyFactory.getInstance().getViewObjectsDAO()
                .updateExternalFormValues(updatingStructure);
    }

    private ViewObjectsStructure parseFocuses(List<Focus> focuses,
                                              ViewObjectsStructure existingObjects) {
        //parse focuses
        ViewObjectsStructure toUpdate = new ViewObjectsStructure();
        int focusOrder = 0;
        for(Focus focus : focuses) {
            Map<String, ViewObject> existingFocuses = existingObjects
                    .getFocuses();
            if(existingFocuses.containsKey(focus.getName())) {
                ViewObject updatingObject = existingFocuses.get(
                        focus.getName());
                updatingObject.setOrderInGroup(focusOrder++);
                updatingObject.setIcon(focus.getIcon());
                toUpdate.add(updatingObject);
                mergeSubFocuses(focus.getSubFocus(), updatingObject.getId(),
                        updatingObject, existingObjects, toUpdate);
                existingObjects.remove(focus.getName());
            } else {//in existingObjects will finally lefts only obsolete objects
                ViewObject parentObject = new ViewObject(null, focus.getName(),
                        null, focusOrder++, PermissionObjectType.FOCUS,
                        ViewObject.ObjectStatus.TO_BE_INSERTED, null,
                        focus.getIcon());
                toUpdate.add(parentObject);
                mergeSubFocuses(focus.getSubFocus(), null, parentObject,
                        existingObjects, toUpdate);
            }
        }
        return toUpdate;
    }

    private void mergeSubFocuses(SubFocus[] subFocuses, Long parentId,
                                 ViewObject parentFocus,
                                 ViewObjectsStructure existingObjects,
                                 ViewObjectsStructure toUpdate) {
        int subFocusOrder = 0;
        for(SubFocus subFocus : subFocuses) {
            Map<String, ViewObject> existingSubFocuses = existingObjects
                    .getSubFocuses();
            if(existingSubFocuses.containsKey(subFocus.getName())) {
                ViewObject updatingObject = existingSubFocuses.get(
                        subFocus.getName());
                updatingObject.setOrderInGroup(subFocusOrder++);
                updatingObject.setIcon(subFocus.getIcon());
                toUpdate.add(updatingObject);
                mergeTabs(subFocus.getTab(), updatingObject.getId(),
                        updatingObject, existingObjects, toUpdate);
                existingObjects.remove(subFocus.getName());
            } else {//in existingObjects will finally lefts only obsolete objects
                ViewObject parentSubFocus = new ViewObject(null,
                        subFocus.getName(), parentId, subFocusOrder++,
                        PermissionObjectType.SUB_FOCUS,
                        ViewObject.ObjectStatus.TO_BE_INSERTED, parentFocus,
                        subFocus.getIcon());
                toUpdate.add(parentSubFocus);
                mergeTabs(subFocus.getTab(), null, parentSubFocus,
                        existingObjects, toUpdate);
            }
        }
    }

    private void mergeTabs(Tab[] tabs, Long parentId, ViewObject parentSubFocus,
                           ViewObjectsStructure existingObjects,
                           ViewObjectsStructure toUpdate) {
        int tabOrder = 0;
        for(Tab tab : tabs) {
            Map<String, ViewObject> existingTabes = existingObjects.getTabs();
            if(existingTabes.containsKey(tab.getName())) {
                ViewObject updatingObject = existingTabes.get(tab.getName());
                updatingObject.setOrderInGroup(tabOrder++);
                updatingObject.setInFrameLinks(tab.getInframelinks());
                updatingObject.setGrid(tab.getGrid());
                toUpdate.add(updatingObject);
                mergeForms(tab.getForm(), updatingObject.getId(),
                        updatingObject, existingObjects, toUpdate);
                existingObjects.remove(tab.getName());
            } else {//in existingObjects will finally lefts only obsolete objects
                ViewObject parentTab = new ViewObject(null, tab.getName(),
                        parentId, tabOrder++, PermissionObjectType.TAB,
                        ViewObject.ObjectStatus.TO_BE_INSERTED, parentSubFocus,
                        null, tab.getInframelinks(), tab.getGrid());
                toUpdate.add(parentTab);
                mergeForms(tab.getForm(), null, parentTab, existingObjects,
                        toUpdate);
            }
        }
    }

    private void mergeForms(Form[] forms, Long parentId, ViewObject parentTab,
                            ViewObjectsStructure existingObjects,
                            ViewObjectsStructure toUpdate) {
        int formOrder = 0;
        for(Form form : forms) {
            Map<String, ViewObject> existingFormes = existingObjects.getForms();
            if(existingFormes.containsKey(form.getName())) {
                ViewObject updatingObject = existingFormes.get(form.getName());
                updatingObject.setOrderInGroup(formOrder++);
                toUpdate.add(updatingObject);
//                mergeFields
                existingObjects.remove(form.getName());
            } else {//in existingObjects will finally lefts only obsolete objects
                toUpdate.add(new ViewObject(null, form.getName(), parentId,
                        formOrder++, PermissionObjectType.FORM,
                        ViewObject.ObjectStatus.TO_BE_INSERTED, parentTab,
                        null));
            }
        }
    }

    /**
     * Delete all the objects with the given view_object from the permissions table and view_objects table
     *
     * @param toBeDeleted view_objects to be deleted
     */
    public void deleteObsoleteViewObjects(ViewObjectsStructure toBeDeleted) {
        // Delete obsolete records.
        ConfigPropertyFactory.getInstance().getViewObjectsDAO().deleteObjects(
                toBeDeleted);
    }

    private void updateViewObjects(ViewObjectsStructure toUpdate) {
        ConfigPropertyFactory.getInstance().getViewObjectsDAO().updateObjects(
                toUpdate);
    }

    /**
     * Get the Focus object by it's name.
     *
     * @param focusName focus name attribute
     * @return Focus object or NULL
     */
    public Focus getFocus(String focusName) {
        return cloneFocus(getInitialFocus(focusName));
    }

    /**
     * Returns initial focus object.
     * WARN. Do not modify this object, if you need to return this object, or
     * child object use {@link #cloneFocus(com.queplix.core.modules.config.jxb.Focus)}
     * method.
     *
     * @param focusName focus name
     * @return initial focus object
     */
    private Focus getInitialFocus(String focusName) {
        Cache cache = ConfigPropertyFactory.getInstance().getViewObjectsCache();
        Focus focus = (Focus) cache.get(focusName);

        if(focus == null) {
            // Load record from database.
            focus = ConfigPropertyFactory.getInstance().getViewObjectsDAO()
                    .loadFocusVO(focusName);

            // Store in cache.
            cache.put(focusName, focus);
        }
        return focus;
    }

    /**
     * Returns initial subFocus object.
     * <p/>
     * WARN. Do not modify this object, if you need to return this object, or
     * child object use {@link #cloneFocus(com.queplix.core.modules.config.jxb.Focus)}
     * method.
     *
     * @param subFocusName subfocus name attribute
     * @return SubFocus object or NULL
     */
    private SubFocus getInitialSubFocus(String subFocusName) {
        String focusID = EntityHelper.getParentFocusName(subFocusName);
        Focus focus = getInitialFocus(focusID);
        if(focus != null) {
            return (SubFocus) focus.getObject(subFocusName);
        } else {
            return null;
        }
    }

    /**
     * Get initial Tab object by it's name.
     * <p/>
     * WARN. Do not modify this object, if you need to return this object, or
     * child object use {@link #cloneFocus(com.queplix.core.modules.config.jxb.Focus)}
     * method.
     *
     * @param tabName tab name attribute
     * @return Tab object or NULL
     */
    private Tab getInitialTab(String tabName) {
        String subFocusID = EntityHelper.getParentSubFocusName(tabName);
        SubFocus subFocus = getInitialSubFocus(subFocusID);
        if(subFocus != null) {
            return (Tab) subFocus.getObject(tabName);
        } else {
            return null;
        }
    }

    /**
     * Get initial Form object by it's name.
     * <p/>
     * WARN. Do not modify this object, if you need to return this object, or
     * child object use {@link #cloneFocus(com.queplix.core.modules.config.jxb.Focus)}
     * method.
     *
     * @param formName form name attribute
     * @return Form object or NULL
     */
    public Form getInitialForm(String formName) {
        if(formName == null) {
            throw new NullPointerException("Got NULL form");
        }

        Tab tab = null;
        String tabID = EntityHelper.getParentTabName(formName);
        if(tabID != null) {
            tab = getInitialTab(tabID);
        }
        if(tab != null) {
            return (Form) tab.getObject(formName);
        } else {
            return null;
        }
    }

    /**
     * Get All Focus objects.
     *
     * @return collection of Focus object
     */
    public Collection<Focus> getFocuses() {

        Collection<Focus> focuses;
        long time = System.currentTimeMillis();

        if(getLogger().isDebugEnabled()) {
            DEBUG("Try to get All focuses");
        }

        Cache cache = ConfigPropertyFactory.getInstance().getViewObjectsCache();
        if(cache.isOpen()) {
            // Load focuses.
            focuses = ConfigPropertyFactory.getInstance().getViewObjectsDAO()
                    .loadAllFocusVO();

            synchronized(cache) {
                // Clear cache.
                cache.clear();

                // Store focuses in cache.
                if(focuses != null) {
                    for(Object focuse : focuses) {
                        Focus focus = (Focus) focuse;
                        cache.put(focus.getName(), focus);
                    }
                }

                // Close cache.
                cache.close();
            }

        } else {
            // Take entire cache.
            focuses = cache.values();
            if(focuses != null) {
                List<Focus> sortedFocuses = new ArrayList<Focus>(focuses);
                Collections.sort(sortedFocuses, new Comparator<Focus>() {
                    public int compare(Focus f1, Focus f2) {
                        if(f1.getOrder() == f2.getOrder()) {
                            return 0;
                        }

                        return f1.getOrder() > f2.getOrder() ? 1:-1;
                    }
                });
                focuses = sortedFocuses;
            }
        }

        if(getLogger().isDebugEnabled()) {
            DEBUG("Get All focus configs - ok. Time (ms): " + (
                    System.currentTimeMillis() - time));
        }

        if(focuses == null) {
            return null;
        }

        // Return cloned collection.
        Collection<Focus> clonedFocuses = new ArrayList<Focus>(focuses.size());
        for(Focus focus : focuses) {
            clonedFocuses.add(cloneFocus(focus));
        }

        return clonedFocuses;
    }

    /**
     * Get the SubFocus object by it's name.
     *
     * @param subFocusName subfocus name attribute
     * @return SubFocus object or NULL
     */
    public SubFocus getSubFocus(String subFocusName) {
        String focusID = EntityHelper.getParentFocusName(subFocusName);
        Focus focus = getFocus(focusID);
        if(focus != null) {
            return (SubFocus) focus.getObject(subFocusName);
        } else {
            return null;
        }
    }

    /**
     * Get the Tab object by it's name.
     *
     * @param tabName tab name attribute
     * @return Tab object or NULL
     */
    public Tab getTab(String tabName) {
        String subFocusID = EntityHelper.getParentSubFocusName(tabName);
        SubFocus subFocus = getSubFocus(subFocusID);
        if(subFocus != null) {
            return (Tab) subFocus.getObject(tabName);
        } else {
            return null;
        }
    }

    /**
     * Get the Form object by it's name.
     *
     * @param formName form name attribute
     * @return Form object or NULL
     */
    public Form getForm(String formName) {

        if(formName == null) {
            throw new NullPointerException("Got NULL form");
        }

        Tab tab = null;
        String tabID = EntityHelper.getParentTabName(formName);
        if(tabID != null) {
            tab = getTab(tabID);
        }
        if(tab != null) {
            return (Form) tab.getObject(formName);
        } else {
            return null;
        }
    }

    // ---------------------------------------------------------------
    // Localize Focus mamagement.
    // ---------------------------------------------------------------

    /**
     * Get all focuses with localized captions.
     *
     * @param langID Language ID
     * @return Collection of Focus objects
     */
    public Collection<Focus> getLocalizedFocuses(String langID) {

        // Get all focuses.
        Collection<Focus> focuses = getFocuses();
        if(focuses == null) {
            return null;
        }

        // Localize focus.
        for(Focus focus : focuses) {
            localizeFocus(langID, focus);
        }

        return focuses;
    }

    /**
     * Get the Focus object by name with localized caption.
     * Returns <b>null</b> if the focus not found.
     *
     * @param langID    Language ID
     * @param focusName focus name attribute
     * @return Focus object
     */
    public Focus getLocalizedFocus(String langID, String focusName) {

        if(getLogger().isDebugEnabled()) {
            DEBUG("Try to get focus '" + focusName + "' lang=[" + langID + "]");
        }

        // Get Focus object.
        Focus focus = getFocus(focusName);
        if(focus == null) {
            return null;
        }

        // Localize focus.
        localizeFocus(langID, focus);

        return focus;
    }

    /**
     * Get the SubFocus object by name with localized caption.
     * Returns <b>null</b> if the focus not found.
     *
     * @param langID       Language ID
     * @param subFocusName Subfocus name attribute
     * @return Focus object
     */
    public SubFocus getLocalizedSubFocus(String langID, String subFocusName) {

        if(getLogger().isDebugEnabled()) {
            DEBUG("Try to get subfocus '" + subFocusName + "' lang=[" + langID
                    + "]");
        }

        // Get SubFocus object.
        SubFocus subFocus = getSubFocus(subFocusName);
        if(subFocus == null) {
            return null;
        }

        // Localize focus.
        localizeSubFocus(langID, subFocus);

        return subFocus;
    }

    /**
     * Get the Tab object by name with localized caption.
     * Returns <b>null</b> if the tab not found.
     *
     * @param langID  Language ID
     * @param tabName tab name attribute
     * @return Tab object
     */
    public Tab getLocalizedTab(String langID, String tabName) {

        if(getLogger().isDebugEnabled()) {
            DEBUG("Try to get tab '" + tabName + "' lang=[" + langID + "]");
        }

        // Get Tab object.
        Tab tab = getTab(tabName);
        if(tab == null) {
            return null;
        }

        // Localize tab.
        localizeTab(langID, tab);

        return tab;
    }

    /**
     * Get the Form object by name with localized caption.
     * Returns <b>null</b> if the form not found.
     *
     * @param langID   Language ID
     * @param formName form name attribute
     * @return Form object
     */
    public Form getLocalizedForm(String langID, String formName) {

        if(getLogger().isDebugEnabled()) {
            DEBUG("Try to get form '" + formName + "' lang=[" + langID + "]");
        }

        // Get Form object.
        Form form = getForm(formName);
        if(form == null) {
            return null;
        }

        // Localize form.
        localizeForm(langID, form);

        return form;
    }

    private static class UnmodifableExternalSet extends ExternalSet {
        public UnmodifableExternalSet(ExternalSet set) {
            super.setName(set.getName());
        }

        public void setName(String name) {
            throw new IllegalStateException("You cannot modify this object, "
                    + "get modifable version of focus. ");
        }
    }

    public List<ExternalSet> getUnmodifiableExternalSet(String formId) {
        Form initialForm = getInitialForm(formId);
        List<ExternalSet> list = null;
        if(initialForm != null) {
            ExternalSet[] sets = initialForm.getExternalSet();
            list = new ArrayList<ExternalSet>(sets.length);
            for(ExternalSet set : sets) {
                list.add(new UnmodifableExternalSet(set));
            }
        }
        return list;
    }

    private static class UnmodifableExternalField extends ExternalField {
        public UnmodifableExternalField(ExternalField field) {
            super.setName(field.getName());
            super.setForm(field.getForm());
            super.setSourceField(field.getSourceField());
        }

        public void setName(String name) {
            throw new IllegalStateException("You cannot modify this object, "
                    + "get modifable version of focus. ");
        }

        public void setForm(String form) {
            throw new IllegalStateException("You cannot modify this object, "
                    + "get modifable version of focus. ");
        }

        public void setSourceField(String sourceField) {
            throw new IllegalStateException("You cannot modify this object, "
                    + "get modifable version of focus. ");
        }
    }

    public List<ExternalField> getUnmodifiableExternalFields(String formId) {
        Form initialForm = getInitialForm(formId);
        List<ExternalField> list = null;
        if(initialForm != null) {
            ExternalField[] fields = initialForm.getExternalField();
            list = new ArrayList<ExternalField>(fields.length);
            for(ExternalField field : fields) {
                list.add(new UnmodifableExternalField(field));
            }
        }
        return list;
    }

    //
    // Initialize focus localization.
    //

    private void updateLocalization(Focus focus) {
        LocalizationManagerLocal localization = getLocalizationManagerLocal();

        if(focus.getCaptions() != null) {
            localization.fillFocusCaptions(focus.getName(),
                    focus.getCaptions());
        }

        for(int m = 0; m < focus.getSubFocusCount(); m++) {
            SubFocus subFocus = focus.getSubFocus(m);
            if(subFocus.getCaptions() != null) {
                localization.fillSubFocusCaptions(subFocus.getName(),
                        subFocus.getCaptions());
            }

            for(int i = 0; i < subFocus.getTabCount(); i++) {
                Tab tab = subFocus.getTab(i);
                if(tab.getCaptions() != null) {
                    localization.fillTabCaptions(tab.getName(),
                            tab.getCaptions());
                }

                for(int j = 0; j < tab.getFormCount(); j++) {
                    Form form = tab.getForm(j);
                    if(form.getCaptions() != null) {
                        localization.fillFormCaptions(form.getName(),
                                form.getCaptions());
                        Button[] buttons = EntityHelper.FormHelper
                                .getFormButtons(form);
                        for(Button button : buttons) {
                            localization.fillButtonCaptions(
                                    EntityHelper.FormHelper.getButtonName(
                                            form, button),
                                    button.getCaptions());
                        }
                        // Save localization for form's html elements
                        Htmlelements htmlElements = form.getHtmlelements();
                        if(htmlElements != null) {
                            for(Htmlelement htmlElement : htmlElements
                                    .getHtmlelement()) {
                                localization.fillHtmlElementContents(
                                        EntityHelper.FormHelper.getHtmlElementName(
                                                form, htmlElement),
                                        htmlElement.getHtmlcontents());
                            }
                        }
                    }
                    if(form.getDescriptions() != null) {
                        localization.fillFormDescriptions(form.getName(),
                                form.getDescriptions());
                    }
                }
            }
        }
    }

    //
    // Localize focus.
    //
    private void localizeFocus(String langID, Focus focus) {
        LocalizationManagerLocal localization = getLocalizationManagerLocal();

        // set Focus caption
        focus.setCaption(localization.getFocusCaption(langID, focus.getName()));

        // set SubFocus captions
        for(int i = 0; i < focus.getSubFocusCount(); i++) {
            localizeSubFocus(langID, focus.getSubFocus(i));
        }
    }

    //
    // Localize subfocus.
    //
    private void localizeSubFocus(String langID, SubFocus subFocus) {
        LocalizationManagerLocal localization = getLocalizationManagerLocal();

        // set SubFocus caption
        subFocus.setCaption(localization.getSubFocusCaption(langID,
                subFocus.getName()));

        // set Tab captions
        for(int i = 0; i < subFocus.getTabCount(); i++) {
            localizeTab(langID, subFocus.getTab(i));
        }
    }

    //
    // Localize tab.
    //
    private void localizeTab(String langID, Tab tab) {
        LocalizationManagerLocal localization = getLocalizationManagerLocal();

        // set Tab caption
        tab.setCaption(localization.getTabCaption(langID, tab.getName()));

        // set Form captions
        for(int i = 0; i < tab.getFormCount(); i++) {
            localizeForm(langID, tab.getForm(i));
        }
    }

    //
    // Localize form.
    //
    private void localizeForm(String langID, Form form) {
        LocalizationManagerLocal localization = getLocalizationManagerLocal();
        // caption
        form.setCaption(localization.getFormCaption(langID, form.getName()));
        // buttons
        Button[] buttons = EntityHelper.FormHelper.getFormButtons(form);
        for(Button button : buttons) {
            button.setCaption(localization.getButtonCaption(
                    langID, EntityHelper.FormHelper.getButtonName(form,
                    button)));
        }
        // htmlelements
        Htmlelements htmlElements = form.getHtmlelements();
        if(htmlElements != null) {
            for(Htmlelement htmlElement : htmlElements.getHtmlelement()) {
                htmlElement.setHtmlcontent(localization.getHtmlElementContent(
                        langID, EntityHelper.FormHelper.getHtmlElementName(form,
                        htmlElement)));

            }
        }
        // description
        form.setDescription(localization.getFormDescription(langID,
                form.getName()));
    }

    //
    // Get LocalizationManager.
    //
    private LocalizationManagerLocal getLocalizationManagerLocal() {
        return (LocalizationManagerLocal) getLocalObject(
                JNDINames.LocalizationManager,
                LocalizationManagerLocalHome.class);
    }

    //
    // Clone focus
    //
    private Focus cloneFocus(Focus f) {
        Focus clone = (Focus) XMLFactory.getXMLBinding().clone(f, Focus.class);

        // indexing
        for(int m = 0; m < clone.getSubFocusCount(); m++) {
            SubFocus subFocus = clone.getSubFocus(m);
            clone.putObject(subFocus.getName(), subFocus);

            for(int i = 0; i < subFocus.getTabCount(); i++) {
                Tab tab = subFocus.getTab(i);
                subFocus.putObject(tab.getName(), tab);

                for(int j = 0; j < tab.getFormCount(); j++) {
                    Form form = tab.getForm(j);
                    tab.putObject(form.getName(), form);
                }
            }
        }

        return clone;
    }
}
