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

import com.queplix.core.jxb.entity.ChainTable;
import com.queplix.core.jxb.entity.Dataset;
import com.queplix.core.jxb.entity.Efield;
import com.queplix.core.jxb.entity.Entity;
import com.queplix.core.modules.config.error.UnknownEfieldException;
import com.queplix.core.modules.config.jxb.Button;
import com.queplix.core.modules.config.jxb.Buttons;
import com.queplix.core.modules.config.jxb.Caption;
import com.queplix.core.modules.config.jxb.Captions;
import com.queplix.core.modules.config.jxb.Custom;
import com.queplix.core.modules.config.jxb.CustomField;
import com.queplix.core.modules.config.jxb.Filter;
import com.queplix.core.modules.config.jxb.Form;
import com.queplix.core.modules.config.jxb.Header;
import com.queplix.core.modules.config.jxb.Headers;
import com.queplix.core.modules.config.jxb.HiddenControl;
import com.queplix.core.modules.config.jxb.HiddenControls;
import com.queplix.core.modules.config.jxb.Htmlelement;
import com.queplix.core.modules.config.jxb.Layout;
import com.queplix.core.modules.config.jxb.Link;
import com.queplix.core.modules.config.jxb.Links;
import com.queplix.core.modules.config.jxb.Row;
import com.queplix.core.modules.config.jxb.SubFocus;
import com.queplix.core.modules.config.jxb.Tab;

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

/**
 * Helper class for working with configs.
 *
 * @author [ALB] Baranov Andrey
 * @author [ONZ] Oleg N. Zhovtanyuk
 * @version $Revision: 1.1.1.1 $ $Date: 2005/09/12 15:30:16 $
 */

public final class EntityHelper {

    // =============================================================== Constants

    /**
     * Entity tag name.
     */
    public static final String ENTITY_TAG = "entity";

    /**
     * Entity name attribute.
     */
    public static final String NAME_ATTRIBUTE = "name";

    /**
     * Name separator for nested entities (e.g. 'calls.attachment').
     */
    public static final String NAME_SEPARATOR = ".";

    /**
     * Name separator for the form names (e.g. 'admin__employee__skill.admin').
     */
    public static final String FORM_NAME_SEPARATOR = "__";

    // Class.
    private static final Class CLASS = EntityHelper.class;

    // Form names separator length.
    private static final int FORM_SEP_LENGTH = FORM_NAME_SEPARATOR.length();

    // ========================================================== Public methods

    /**
     * Get efield ID.
     *
     * @param entityName Entity name attribute
     * @param efieldName Efield name attribute
     * @return id of efield
     */
    public static String getFieldId(String entityName, String efieldName) {
        return entityName + NAME_SEPARATOR + efieldName;
    }

    /**
     * Get Efield object position in Entity object.
     *
     * @param entity Entity object
     * @param efield Efield object
     * @return Efield position
     */
    public static int getFieldPos(Entity entity, Efield efield) {
        return entity.getPos(efield.getName());
    }

    /**
     * Get dataset ID.
     *
     * @param entity  Entity object
     * @param dataset Dataset object
     * @return id of efield
     */
    public static String getDatasetId(Entity entity, Dataset dataset) {
        return entity.getName() + NAME_SEPARATOR + dataset.getName();
    }

    /**
     * Get efield full name.
     *
     * @param dbobjAlias alias of db object
     * @param srcName    the efield src attribute
     * @return name of efield
     */
    public static String getFieldFullName(String dbobjAlias, String srcName) {
        if(dbobjAlias != null) {
            return dbobjAlias.toUpperCase() + NAME_SEPARATOR + srcName
                    .toUpperCase();
        } else {
            return srcName.toUpperCase();
        }
    }

    /**
     * Get efield full name.
     *
     * @param field  the Efield object
     * @param entity the Entity object
     * @return source attribute of efield
     */
    public static String getFieldFullName(Efield field, Entity entity) {
        return getFieldFullName(entity.getDbobjAlias(), field.getName());
    }

    /**
     * Get parent entity name (the structure of name like: <parent>.<child>).
     *
     * @param entityName the entity name
     * @return name of parent or null
     */
    public static String getParentEntityName(String entityName) {
        int pos = entityName.lastIndexOf(NAME_SEPARATOR);
        if(pos < 0) {
            return null;
        } else {
            return entityName.substring(0, pos);
        }
    }

    /**
     * Get subfocus full name.
     *
     * @param focusName Focus name attribute
     * @param subFocus  SubFocus object
     * @return subfocus full name
     */
    public static String getSubFocusFullName(String focusName,
                                             SubFocus subFocus) {
        return focusName + FORM_NAME_SEPARATOR + subFocus.getName();
    }

    /**
     * Get tab full name.
     *
     * @param subFocusName SubFocus name attribute
     * @param tab          Tab object
     * @return tab full name
     */
    public static String getTabFullName(String subFocusName, Tab tab) {
        return subFocusName + FORM_NAME_SEPARATOR + tab.getName();
    }

    /**
     * Get focus name of subfocus
     *
     * @param subFocusName Subfocus name
     * @return focus name
     */
    public static String getParentFocusName(String subFocusName) {
        int pos = subFocusName.lastIndexOf(FORM_NAME_SEPARATOR);
        if(pos < 0) {
            return null;
        } else {
            return subFocusName.substring(0, pos);
        }
    }

    /**
     * Get subfocus name of tab
     *
     * @param tabName tab name
     * @return subfocus name
     */
    public static String getParentSubFocusName(String tabName) {
        int pos = tabName.lastIndexOf(FORM_NAME_SEPARATOR);
        if(pos < 0) {
            return null;
        } else {
            return tabName.substring(0, pos);
        }
    }

    /**
     * Get form full name.
     *
     * @param tabName Tab name attribute
     * @param form    Form object
     * @return form full name
     */
    public static String getFormFullName(String tabName, Form form) {
        return tabName + FORM_NAME_SEPARATOR + form.getEntity();
    }

    /**
     * Get base entity name for the given form.
     *
     * @param formName Form name attribute
     * @return entity name
     */
    public static String getFormEntityName(String formName) {
        int pos = formName.lastIndexOf(FORM_NAME_SEPARATOR);
        if(pos < 0) {
            return null;
        } else {
            return formName.substring(pos + FORM_SEP_LENGTH);
        }
    }

    /**
     * Get tab name of from
     *
     * @param formName form name
     * @return form tab
     */
    public static String getParentTabName(String formName) {
        int pos = formName.lastIndexOf(FORM_NAME_SEPARATOR);
        if(pos < 0) {
            return null;
        } else {
            return formName.substring(0, pos);
        }
    }

    /**
     * Get focus name
     *
     * @param objectName Name of any object from focus structure (focus -> subfocus -> tab -> form)
     * @return form tab
     */
    public static String getFocusName(String objectName) {
        int pos = objectName.indexOf(FORM_NAME_SEPARATOR);
        return pos == -1 ? objectName:objectName.substring(0, pos);
    }

    public static boolean isParentObject(String parentObjectName,
                                         String childObjectName) {
        return childObjectName.startsWith(parentObjectName);
    }

    /**
     * Check if entity <code>childEntityName</code> is a parent or itself for
     * entity <code>parentEntityName</code>.
     *
     * @param childEntityName  child entity name
     * @param parentEntityName parent entity name
     * @return true or false
     */
    public static boolean isChild(String childEntityName,
                                  String parentEntityName) {
        do {
            if(childEntityName != null && parentEntityName != null
                    && childEntityName.equals(parentEntityName)) {
                return true;
            }

            childEntityName = getParentEntityName(childEntityName);

        } while(childEntityName != null);

        return false;
    }

    /**
     * Get Efield object by the efield name attribute.
     *
     * @param efieldName the efield name attribute
     * @param entity     Entity object
     * @return Efield object
     * @throws UnknownEfieldException
     */
    public static Efield getEfield(String efieldName, Entity entity)
            throws UnknownEfieldException {
        Object o = entity.getObject(efieldName);
        if(o == null || !(o instanceof Efield)) {
            throw new UnknownEfieldException(entity.getName(), efieldName);
        }
        return (Efield) o;
    }

    /**
     * Get Efield object by the src (database column name).
     *
     * @param src    the database column name
     * @param entity Entity object
     * @return Efield object
     * @throws UnknownEfieldException
     */
    public static Efield getEfieldBySrc(String src, Entity entity) {
        Object o = entity.getObject(src.toLowerCase());
        if(o == null || !(o instanceof Efield)) {
            throw new UnknownEfieldException(entity.getName(), src);
        }

        return (Efield) o;
    }

    /**
     * Get Dataset object by the dataset name attribute.
     *
     * @param datasetName the dataset name attribute
     * @param entity      Entity object
     * @return Dataset object
     * @throws UnknownEfieldException
     */
    public static Dataset getDataset(String datasetName, Entity entity)
            throws UnknownEfieldException {
        Object o = entity.getObject(datasetName);
        if(o == null || !(o instanceof Dataset)) {
            throw new UnknownEfieldException(entity.getName(), datasetName);
        }

        return (Dataset) o;
    }

    /**
     * Get CustomField object by the efield name attribute.
     *
     * @param fieldName the efield name attribute
     * @param custom    Custom object
     * @return CustomField object
     */
    public static CustomField getCustomField(String fieldName, Custom custom) {
        Object o = custom.getObject(fieldName);
        return (o == null) ? null:(CustomField) o;
    }

    /**
     * Get ChainTable contains dataschemas for linking two entities.
     *
     * @param e2     the Entity 2 name attribute
     * @param entity the Entity 1 object
     * @return ChainTable object
     */
    public static ChainTable getChainTable(String e2, Entity entity) {
        int chtable_count = entity.getChainTableCount();

        for(int i = 0; i < chtable_count; i++) {
            ChainTable chtab = entity.getChainTable(i);
            if(chtab.getEntity().equals(e2)) {
                return chtab;
            }
        }
        return null;
    }

    /**
     * Get array of pkeys for given <code>entity</code>.
     *
     * @param entity Entity object
     * @return array of Efield object or NULL
     */
    public static Efield[] getPkeys(Entity entity) {

        List pkeyFields = new ArrayList();

        int fields = entity.getEfieldCount();
        for(int i = 0; i < fields; i++) {
            Efield field = entity.getEfield(i);
            if(field.getPkey().booleanValue()) {
                pkeyFields.add(field);
            }
        }

        return (pkeyFields.size() == 0) ? null:
                (Efield[]) pkeyFields.toArray(new Efield[0]);
    }

    public static class FormHelper {
        //NullObjects for Layout and Form
        private static final Row[] NULL_ROWS = new Row[0];
        private static final Header[] NULL_HEADERS = new Header[0];
        private static final HiddenControl[] NULL_HIDDEN_CONTROLS
                = new HiddenControl[0];
        private static final Button[] NULL_BUTTONS = new Button[0];
        private static final Link[] NULL_LINKS = new Link[0];
        private static final Filter[] NULL_FILTERS = new Filter[0];

        private static final Button[] DEFAULT_BUTTONS = new Button[]{
                createButton("FORM_SEARCH_BUTTON"),
                createButton("FORM_CLEAR_BUTTON"),
                createButton("FORM_NEW_BUTTON"),
                createButton("FORM_CHANGE_OR_UPDATE_BUTTON")
        };

        private static Button createButton(String buttonName) {
            Button button = new Button();
            button.setName(buttonName);
            Captions caps = new Captions();
            Caption cap = new Caption();
//            cap.setContent();
            caps.addCaption(cap);
            button.setCaptions(caps);
            return button;
        }

        private static void checkAndCreateLayout(Form form) {
            if(form.getLayout() == null) {
                form.setLayout(new Layout());
            }
        }

        public static Row[] getLayoutRows(Form form) {
            if(form.getLayout() == null) {
                return NULL_ROWS;
            } else {
                return form.getLayout().getRow();
            }
        }

        public static void addLayoutRow(Form form, Row row) {
            checkAndCreateLayout(form);
            form.getLayout().addRow(row);
        }

        public static Header[] getLayoutHeaders(Form form) {
            if(form.getLayout() == null
                    || form.getLayout().getHeaders() == null) {
                return NULL_HEADERS;
            } else {
                return form.getLayout().getHeaders().getHeader();
            }
        }

        public static void addHeaderIntoLayout(Form form, Header header) {
            checkAndCreateLayout(form);
            if(form.getLayout().getHeaders() == null) {
                form.getLayout().setHeaders(new Headers());
            }
            form.getLayout().getHeaders().addHeader(header);
        }

        public static Filter[] getFormFilters(Form form) {
            if(form.getFilters() == null
                    || form.getFilters().getFilterCount() == 0) {
                return NULL_FILTERS;
            } else {
                return form.getFilters().getFilter();
            }
        }

        public static HiddenControl[] getHiddenControls(Form form) {
            if(form.getLayout() == null
                    || form.getLayout().getHiddenControls() == null) {
                return NULL_HIDDEN_CONTROLS;
            } else {
                return form.getLayout().getHiddenControls().getHiddenControl();
            }
        }

        public static void addHiddenControl(Form form,
                                            HiddenControl hiddenControl) {
            checkAndCreateLayout(form);
            if(form.getLayout().getHiddenControls() == null) {
                form.getLayout().setHiddenControls(new HiddenControls());
            }
            form.getLayout().getHiddenControls().addHiddenControl(
                    hiddenControl);
        }

        public static Button[] getFormButtons(Form form) {
            Button[] buttons;
            if(form.getDefaultactions() || form.getButtons() == null) {
                buttons = DEFAULT_BUTTONS;
            } else {
                buttons = form.getButtons().getButton();
            }
            return buttons;
        }

        public static Button getButtonById(Form form, String buttonId) {
            Button[] buttons = getFormButtons(form);
            for(Button button : buttons) {
                if(buttonId.equalsIgnoreCase(button.getName())) {
                    return button;
                }
            }
            return null;
        }

        public static void addFormButton(Form form, Button button) {
            if(form.getButtons() == null) {
                form.setButtons(new Buttons());
            }
            form.getButtons().addButton(button);
        }

        public static Link[] getFormLinks(Form form) {
            if(form.getLinks() == null) {
                return NULL_LINKS;
            } else {
                return form.getLinks().getLink();
            }
        }

        public static void addFormLink(Form form, Link link) {
            if(form.getLinks() == null) {
                form.setLinks(new Links());
            }
            form.getLinks().addLink(link);
        }


        public static boolean getFormDefaultActions(Form form) {
            return form.getButtons() == null || form.getButtons()
                    .getDefaultactions();
        }


        public static String getButtonName(Form form, Button button) {
            return form.getName() + "__button__" + button.getName();
        }

        public static String getHtmlElementName(Form form,
                                                Htmlelement htmlElement) {
            return form.getName() + "__htmlelement__" + htmlElement.getName();
        }

    }

}
