<commit_before>/*
 * Copyright 2003 - 2014 The eFaps Team
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * 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.
 *
 * Revision:        $Rev$
 * Last Changed:    $Date$
 * Last Changed By: $Author$
 */

package org.efaps.ui.wicket.models.objects;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import org.apache.wicket.RestartResponseException;
import org.apache.wicket.util.io.IClusterable;
import org.efaps.admin.datamodel.Attribute;
import org.efaps.admin.datamodel.AttributeSet;
import org.efaps.admin.datamodel.Classification;
import org.efaps.admin.datamodel.Type;
import org.efaps.admin.datamodel.ui.FieldValue;
import org.efaps.admin.datamodel.ui.TypeUI;
import org.efaps.admin.datamodel.ui.UIValue;
import org.efaps.admin.datamodel.ui.UserUI;
import org.efaps.admin.event.EventDefinition;
import org.efaps.admin.event.EventType;
import org.efaps.admin.event.Parameter.ParameterValues;
import org.efaps.admin.event.Return;
import org.efaps.admin.event.Return.ReturnValues;
import org.efaps.admin.ui.AbstractCommand;
import org.efaps.admin.ui.AbstractUserInterfaceObject.TargetMode;
import org.efaps.admin.ui.Form;
import org.efaps.admin.ui.Image;
import org.efaps.admin.ui.field.Field;
import org.efaps.admin.ui.field.FieldChart;
import org.efaps.admin.ui.field.FieldClassification;
import org.efaps.admin.ui.field.FieldCommand;
import org.efaps.admin.ui.field.FieldGroup;
import org.efaps.admin.ui.field.FieldHeading;
import org.efaps.admin.ui.field.FieldPicker;
import org.efaps.admin.ui.field.FieldSet;
import org.efaps.admin.ui.field.FieldTable;
import org.efaps.db.Context;
import org.efaps.db.Instance;
import org.efaps.db.PrintQuery;
import org.efaps.ui.wicket.models.AbstractInstanceObject;
import org.efaps.ui.wicket.models.cell.CellSetValue;
import org.efaps.ui.wicket.models.cell.UIFormCell;
import org.efaps.ui.wicket.models.cell.UIFormCellChart;
import org.efaps.ui.wicket.models.cell.UIFormCellCmd;
import org.efaps.ui.wicket.models.cell.UIFormCellSet;
import org.efaps.ui.wicket.models.cell.UIHiddenCell;
import org.efaps.ui.wicket.models.cell.UIPicker;
import org.efaps.ui.wicket.models.cell.UISetColumnHeader;
import org.efaps.ui.wicket.models.field.UIField;
import org.efaps.ui.wicket.pages.error.ErrorPage;
import org.efaps.util.EFapsException;
import org.efaps.util.cache.CacheReloadException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Class is used to instantiate a form from eFaps into a Form with all Values
 * for the wicket webapp.
 *
 * @author The eFaps Team
 * @version $Id$
 */
public class UIForm
    extends AbstractUIPageObject
{

    /**
     * Enum is used to differ the different elements a form can contain.
     */
    public enum ElementType
    {
        /** ELement is a Classification. */
        CLASSIFICATION,
        /** Element is a Form. */
        FORM,
        /** Element is a Heading. */
        HEADING,
        /** Element is a StructurBrowser. */
        STRUCBRWS,
        /** Element is SubForm. e.g. for classification */
        SUBFORM,
        /** Element is a table. */
        TABLE
    }

    /**
     * Logging instance used in this class.
     */
    private static final Logger LOG = LoggerFactory.getLogger(UIForm.class);

    /**
     * Used for serialization.
     */
    private static final long serialVersionUID = 3026168649146801622L;

    /**
     * The instance variable stores the different elements of the Form.
     *
     * @see #getElements
     */
    private final List<Element> elements = new ArrayList<Element>();

    /**
     * The instance variable stores the form which must be shown.
     *
     * @see #getForm
     */
    private UUID formUUID;

    /**
     * Used to set if the form is used to upload a file.
     */
    private boolean fileUpload = false;

    /**
     * Map is used to store the new values passed during the creation process
     * from the webapp.
     */
    private final Map<String, String[]> newValues = new HashMap<String, String[]>();

    /**
     * Is this form classified by classification.
     */
    private boolean classified = false;

    /**
     * Constructor.
     *
     * @param _commandUUID UUID of the command
     * @param _instanceKey oid for this model
     * @throws CacheReloadException on error
     */
    public UIForm(final UUID _commandUUID,
                  final String _instanceKey)
        throws CacheReloadException
    {
        this(_commandUUID, _instanceKey, null);
    }

    /**
     * Constructor.
     *
     * @param _commandUUID UUID of the command
     * @param _instanceKey oid for this model
     * @param _openerId id of the opener
     * @throws CacheReloadException on error
     */
    public UIForm(final UUID _commandUUID,
                  final String _instanceKey,
                  final String _openerId)
        throws CacheReloadException
    {
        super(_commandUUID, _instanceKey, _openerId);
        final AbstractCommand command = super.getCommand();
        if (command == null) {
            this.formUUID = null;
        } else if (command.getTargetForm() != null) {
            this.formUUID = command.getTargetForm().getUUID();
        }
    }

    /**
     * Method used to reset this UIForm.
     */
    @Override
    public void resetModel()
    {
        setInitialized(false);
        this.elements.clear();
        getHidden().clear();
    }

    /**
     * Method is used to execute the UIForm. (Fill it with data).
     */
    @Override
    public void execute()
    {
        try {
            // evaluate now to give the chance to change the mode
            if (evaluate4Instance()) {
                if (isCreateMode() || isSearchMode()) {
                    execute4NoInstance();
                } else {
                    if (getInstance() == null) {
                        execute4NoInstance();
                    } else {
                        execute4Instance();
                    }
                }
            }
        } catch (final EFapsException e) {
            throw new RestartResponseException(new ErrorPage(e));
        }
        super.setInitialized(true);
    }

    /**
     * This is a possibility to replace the current Instance for the form with
     * another one using an table evaluate esjp.
     *
     * @throws EFapsException on error
     */
    protected boolean evaluate4Instance()
        throws EFapsException
    {
        boolean ret = true;
        if (!isSearchMode()) {
            final List<Return> returns = getCommand().executeEvents(EventType.UI_TABLE_EVALUATE,
                            ParameterValues.INSTANCE, getInstance(),
                            ParameterValues.PARAMETERS, Context.getThreadContext().getParameters(),
                            ParameterValues.CLASS, this);
            for (final Return retu : returns) {
                if (retu.contains(ReturnValues.INSTANCE)) {
                    final Object object = retu.get(ReturnValues.INSTANCE);
                    if (object != null && object instanceof Instance && ((Instance) object).isValid()) {
                        setInstanceKey(((Instance) object).getOid());
                    } else {
                        UIForm.LOG.error("The esjp called by Command '{}' must return a valid instance",
                                        getCommand().getName());
                    }
                } else {
                    ret = false;
                }
            }
        }
        return ret;
    }

    /**
     * Method to execute the form in case that a instance is existing.
     *
     * @throws EFapsException
     *
     * @throws EFapsException on error
     */
    private void execute4Instance()
        throws EFapsException
    {
        int rowgroupcount = 1;
        int rowspan = 1;
        FormRow row = new FormRow();
        final Set<String> altOIDSel = new HashSet<String>();
        final Form form = Form.get(this.formUUID);
        // evaluate the Form to make the query
        final PrintQuery print = new PrintQuery(getInstance());
        for (final Field field : form.getFields()) {
            if (field.hasAccess(getMode(), getInstance(), getCommand(), getInstance())
                            && !field.isNoneDisplay(getMode())) {
                if (field.getSelect() != null) {
                    print.addSelect(field.getSelect());
                } else if (field.getAttribute() != null) {
                    print.addAttribute(field.getAttribute());
                } else if (field.getPhrase() != null) {
                    print.addPhrase(field.getName(), field.getPhrase());
                }
                if (field.getSelectAlternateOID() != null) {
                    print.addSelect(field.getSelectAlternateOID());
                    altOIDSel.add(field.getSelectAlternateOID());
                }
            }
        }
        if (print.execute()) {
            if (!altOIDSel.isEmpty()) {
                final List<Instance> inst = new ArrayList<Instance>();
                for (final String sel : altOIDSel) {
                    inst.addAll(print.getInstances4Select(sel));
                }
                checkAccessToInstances(inst);
            }
            FormElement formElement = null;
            boolean addNew = true;
            UIClassification uiclass = null;
            boolean firstTable = true;
            for (final Field field : form.getFields()) {
                if (field.hasAccess(getMode(), getInstance(), getCommand(), getInstance())
                                && !field.isNoneDisplay(getMode())) {
                    if (field instanceof FieldGroup) {
                        final FieldGroup group = (FieldGroup) field;
                        // in case that the first field is a group the element
                        // must be initiated
                        if (formElement == null) {
                            formElement = new FormElement();
                            this.elements.add(new Element(UIForm.ElementType.FORM, formElement));
                            addNew = false;
                        }
                        if (formElement.getMaxGroupCount() < group.getGroupCount()) {
                            formElement.setMaxGroupCount(group.getGroupCount());
                        }
                        rowgroupcount = group.getGroupCount();
                    } else if (field instanceof FieldTable) {
                        if (((FieldTable) field).getTargetStructurBrowserField() == null) {
                            final UIFieldTable uiFieldTable = new UIFieldTable(getCommandUUID(), getInstanceKey(),
                                            (FieldTable) field);
                            uiFieldTable.setMode(getMode());
                            this.elements.add(new Element(UIForm.ElementType.TABLE, uiFieldTable));
                            if (firstTable) {
                                firstTable = false;
                            } else {
                                uiFieldTable.setFirstTable(false);
                            }
                        } else {
                            final UIFieldStructurBrowser uiFieldStrucBrws = new UIFieldStructurBrowser(
                                            getCommandUUID(),
                                            getInstanceKey(), (FieldTable) field);
                            uiFieldStrucBrws.setMode(getMode());
                            this.elements.add(new Element(UIForm.ElementType.STRUCBRWS, uiFieldStrucBrws));
                        }
                        addNew = true;
                    } else if (field instanceof FieldHeading) {
                        this.elements.add(new Element(UIForm.ElementType.HEADING,
                                        new UIHeading((FieldHeading) field)));
                        addNew = true;
                    } else if (field instanceof FieldClassification) {
                        uiclass = UIClassification.getUIClassification(field, this);
                        this.elements.add(new Element(UIForm.ElementType.CLASSIFICATION, uiclass));
                        addNew = true;
                        this.classified = true;
                    } else {
                        if (addNew) {
                            formElement = new FormElement();
                            this.elements.add(new Element(UIForm.ElementType.FORM, formElement));
                            addNew = false;
                        }
                        if (addCell2FormRow(row, print, field)) {
                            if (field.getRowSpan() > 0) {
                                rowspan = field.getRowSpan();
                            }
                            rowgroupcount--;
                            if (rowgroupcount < 1) {
                                rowgroupcount = 1;
                                if (row.getGroupCount() > 0) {
                                    formElement.addRowModel(row);
                                    row = new FormRow();
                                    if (rowspan > 1) {
                                        rowspan--;
                                        row.setRowSpan(true);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (uiclass != null) {
                final Map<UUID, String> instanceKeys = uiclass.getClassInstanceKeys(getInstance());
                if (instanceKeys.size() > 0) {
                    if (!uiclass.isInitialized()) {
                        uiclass.execute(getInstance());
                    }
                    addClassElements(uiclass, instanceKeys);
                }
            }
        }
    }

    /**
     * Method that adds the classification forms as elements to the form by
     * walking down the tree.
     *
     * @param _uiclass the classification to be added
     * @param _instanceKeys map from uuid to instance keys
     * @throws EFapsException on error
     */
    public void addClassElements(final UIClassification _uiclass,
                                 final Map<UUID, String> _instanceKeys)
        throws EFapsException
    {
        this.elements.addAll(getClassElements(_uiclass, _instanceKeys));
    }

    /**
     * Method that removes all classifcations and afterwards adds the
     * classification forms as elements to the form by walking down the tree.
     *
     * @param _uiclass the classification to be added
     * @throws EFapsException on error
     */
    public void updateClassElements(final UIClassification _uiclass)
        throws EFapsException
    {
        // remove previous added classification forms
        final Iterator<Element> iter2 = this.elements.iterator();
        final Map<UUID, String> uuid2InstanceKey = new HashMap<UUID, String>();
        while (iter2.hasNext()) {
            final IFormElement element = iter2.next().getElement();
            if (element instanceof UIFieldForm) {
                final String instanceKey = ((UIFieldForm) element).getInstanceKey();
                if (instanceKey != null) {
                    final UUID classUUID = ((UIFieldForm) element).getClassificationUUID();
                    uuid2InstanceKey.put(classUUID, instanceKey);
                }
                iter2.remove();
            }
        }
        addClassElements(_uiclass, uuid2InstanceKey);
    }

    /**
     * Method to add a Cell to the given Row.
     *
     * @param _row FormRow to add the cell to
     * @param _query query containing the values
     * @param _field field the cell belongs to
     * @throws EFapsException on error
     * @return true if the cell was actually added, else false
     */
    private boolean addCell2FormRow(final FormRow _row,
                                    final PrintQuery _query,
                                    final Field _field)
        throws EFapsException
    {
        boolean ret = true;
        Attribute attr = null;
        if (_field.getAttribute() != null) {
            attr = _query.getAttribute4Attribute(_field.getAttribute());
        } else if (_field.getSelect() != null) {
            attr = _query.getAttribute4Select(_field.getSelect());
        }

        // evaluate the label of the field
        String label;
        if (_field.getLabel() != null) {
            label = _field.getLabel();
        } else if (attr != null) {
            label = attr.getParent().getName() + "/" + attr.getName() + ".Label";
        } else {
            label = "Unknown";
        }

        Instance fieldInstance;
        if (_field.getSelectAlternateOID() != null
                        && _query.getSelect(_field.getSelectAlternateOID()) instanceof String) {
            fieldInstance = Instance.get(_query.<String>getSelect(_field.getSelectAlternateOID()));
        } else {
            fieldInstance = getInstance();
        }
        if (_field.isHiddenDisplay(getMode())) {
            Object value = null;
            if (_field.getAttribute() != null) {
                value = _query.getAttribute(_field.getAttribute());
            } else if (_field.getSelect() != null) {
                value = _query.getSelect(_field.getSelect());
            } else if (_field.getPhrase() != null) {
                value = _query.getPhrase(_field.getName());
            }
            // temp to decide what to do TODO remove in future
            if (_field.getClassUI() == null && _field.getUIProvider() != null
                            || attr != null && attr.getAttributeType().getUI() == null
                            || attr == null && _field.getClassUI() == null && _field.getUIProvider() == null
                            || attr != null && attr.getAttributeType().getUI() != null
                            && (attr.getAttributeType().getUI() instanceof TypeUI
                            || attr.getAttributeType().getUI() instanceof UserUI)) {
                addHidden(evaluateUIProvider(_row, _query, _field, fieldInstance, label, attr));
            } else {

                final FieldValue fieldvalue = new FieldValue(_field, attr, value, fieldInstance, getInstance(), null,
                                this);
                final String strValue = fieldvalue.getHiddenHtml(getMode());
                addHidden(new UIHiddenCell(this, fieldvalue, null, strValue));
            }
            ret = false;
        } else {
            // fieldset
            if (_field instanceof FieldSet) {
                evaluateFieldSet(_row, _query, _field, fieldInstance, label);
            } else if (_field instanceof FieldCommand) {
                final UIFormCellCmd fieldCmd = new UIFormCellCmd(this, (FieldCommand) _field, fieldInstance, label);
                _row.add(fieldCmd);
            } else if (_field instanceof FieldChart) {
                final UIFormCellChart fieldChart = new UIFormCellChart(this, (FieldChart) _field, fieldInstance, label);
                _row.add(fieldChart);
            } else {
                // temp to decide what to do TODO remove in future
                if (_field.getClassUI() == null && _field.getUIProvider() != null
                                || attr != null && attr.getAttributeType().getUI() == null
                                || attr == null && _field.getClassUI() == null && _field.getUIProvider() == null
                                || attr != null && attr.getAttributeType().getUI() != null
                                  && (attr.getAttributeType().getUI() instanceof TypeUI
                                    || attr.getAttributeType().getUI() instanceof UserUI)) {
                    _row.add(evaluateUIProvider(_row, _query, _field, fieldInstance, label, attr));
                } else {
                    evaluateField(_row, _query, _field, fieldInstance, label, attr);
                }
            }
        }
        return ret;
    }

    /**
     * Method evaluates a Field and adds it to the row.
     *
     * @param _row FormRow to add the cell to
     * @param _print query containing the values
     * @param _field field the cell belongs to
     * @param _fieldInstance instance of the Field
     * @param _label label for the Field
     * @param _attr attribute for the Field
     * @throws EFapsException on error
     */
    private UIField evaluateUIProvider(final FormRow _row,
                                       final PrintQuery _print,
                                       final Field _field,
                                       final Instance _fieldInstance,
                                       final String _label,
                                       final Attribute _attr)
        throws EFapsException
    {
        Object value = null;
        if (_field.getAttribute() != null) {
            value = _print.<Object>getAttribute(_field.getAttribute());
        } else if (_field.getSelect() != null) {
            value = _print.<Object>getSelect(_field.getSelect());
        } else if (_field.getPhrase() != null) {
            value = _print.getPhrase(_field.getName());
        }
        final UIField uiField = new UIField(_fieldInstance.getKey(), this, UIValue.get(_field, _attr, value)
                        .setInstance(_fieldInstance).setClassObject(this));
        return uiField;
    }

    /**
     * Method evaluates a Field and adds it to the row.
     *
     * @param _row FormRow to add the cell to
     * @param _query query containing the values
     * @param _field field the cell belongs to
     * @param _fieldInstance instance of the Field
     * @param _label label for the Field
     * @param _attr attribute for the Field
     * @throws EFapsException on error
     */
    private void evaluateField(final FormRow _row,
                               final PrintQuery _query,
                               final Field _field,
                               final Instance _fieldInstance,
                               final String _label,
                               final Attribute _attr)
        throws EFapsException
    {
        Object value = null;
        if (_field.getAttribute() != null) {
            value = _query.<Object>getAttribute(_field.getAttribute());
        } else if (_field.getSelect() != null) {
            value = _query.<Object>getSelect(_field.getSelect());
        } else if (_field.getPhrase() != null) {
            value = _query.getPhrase(_field.getName());
        }

        final FieldValue fieldvalue = new FieldValue(_field, _attr, value, _fieldInstance, getInstance(), null, this,
                        getCallingCommandUUID() == null ? getCommand() : getCallingCommand());

        String strValue = null;
        if (isPrintMode()) {
            strValue = fieldvalue.getStringValue(getMode());
        } else {
            if (isEditMode() && _field.isEditableDisplay(getMode())) {
                if (_field.hasEvents(EventType.UI_FIELD_AUTOCOMPLETE)) {
                    strValue = fieldvalue.getStringValue(getMode());
                } else {
                    strValue = fieldvalue.getEditHtml(getMode());
                }
            } else if (_field.isReadonlyDisplay(getMode())) {
                strValue = fieldvalue.getReadOnlyHtml(getMode());
            }
        }
        if (strValue != null && !this.fileUpload) {
            final String tmp = strValue.replaceAll(" ", "");
            if (tmp.toLowerCase().contains("type=\"file\"")) {
                this.fileUpload = true;
            }
        }
        String icon = _field.getIcon();
        if (_fieldInstance != null) {
            if (_field.isShowTypeIcon() && _fieldInstance.getType() != null) {<commit_msg>- webapp: adding possiblity to use MsgPhrase in a  form<commit_after>/*
 * Copyright 2003 - 2014 The eFaps Team
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * 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.
 *
 * Revision:        $Rev$
 * Last Changed:    $Date$
 * Last Changed By: $Author$
 */

package org.efaps.ui.wicket.models.objects;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.util.io.IClusterable;
import org.efaps.admin.datamodel.Attribute;
import org.efaps.admin.datamodel.AttributeSet;
import org.efaps.admin.datamodel.Classification;
import org.efaps.admin.datamodel.Type;
import org.efaps.admin.datamodel.ui.FieldValue;
import org.efaps.admin.datamodel.ui.TypeUI;
import org.efaps.admin.datamodel.ui.UIValue;
import org.efaps.admin.datamodel.ui.UserUI;
import org.efaps.admin.event.EventDefinition;
import org.efaps.admin.event.EventType;
import org.efaps.admin.event.Parameter.ParameterValues;
import org.efaps.admin.event.Return;
import org.efaps.admin.event.Return.ReturnValues;
import org.efaps.admin.ui.AbstractCommand;
import org.efaps.admin.ui.AbstractUserInterfaceObject.TargetMode;
import org.efaps.admin.ui.Form;
import org.efaps.admin.ui.Image;
import org.efaps.admin.ui.field.Field;
import org.efaps.admin.ui.field.FieldChart;
import org.efaps.admin.ui.field.FieldClassification;
import org.efaps.admin.ui.field.FieldCommand;
import org.efaps.admin.ui.field.FieldGroup;
import org.efaps.admin.ui.field.FieldHeading;
import org.efaps.admin.ui.field.FieldPicker;
import org.efaps.admin.ui.field.FieldSet;
import org.efaps.admin.ui.field.FieldTable;
import org.efaps.db.Context;
import org.efaps.db.Instance;
import org.efaps.db.PrintQuery;
import org.efaps.db.SelectBuilder;
import org.efaps.ui.wicket.models.AbstractInstanceObject;
import org.efaps.ui.wicket.models.cell.CellSetValue;
import org.efaps.ui.wicket.models.cell.UIFormCell;
import org.efaps.ui.wicket.models.cell.UIFormCellChart;
import org.efaps.ui.wicket.models.cell.UIFormCellCmd;
import org.efaps.ui.wicket.models.cell.UIFormCellSet;
import org.efaps.ui.wicket.models.cell.UIHiddenCell;
import org.efaps.ui.wicket.models.cell.UIPicker;
import org.efaps.ui.wicket.models.cell.UISetColumnHeader;
import org.efaps.ui.wicket.models.field.UIField;
import org.efaps.ui.wicket.pages.error.ErrorPage;
import org.efaps.util.EFapsException;
import org.efaps.util.cache.CacheReloadException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Class is used to instantiate a form from eFaps into a Form with all Values
 * for the wicket webapp.
 *
 * @author The eFaps Team
 * @version $Id$
 */
public class UIForm
    extends AbstractUIPageObject
{

    /**
     * Enum is used to differ the different elements a form can contain.
     */
    public enum ElementType
    {
        /** ELement is a Classification. */
        CLASSIFICATION,
        /** Element is a Form. */
        FORM,
        /** Element is a Heading. */
        HEADING,
        /** Element is a StructurBrowser. */
        STRUCBRWS,
        /** Element is SubForm. e.g. for classification */
        SUBFORM,
        /** Element is a table. */
        TABLE
    }

    /**
     * Logging instance used in this class.
     */
    private static final Logger LOG = LoggerFactory.getLogger(UIForm.class);

    /**
     * Used for serialization.
     */
    private static final long serialVersionUID = 3026168649146801622L;

    /**
     * The instance variable stores the different elements of the Form.
     *
     * @see #getElements
     */
    private final List<Element> elements = new ArrayList<Element>();

    /**
     * The instance variable stores the form which must be shown.
     *
     * @see #getForm
     */
    private UUID formUUID;

    /**
     * Used to set if the form is used to upload a file.
     */
    private boolean fileUpload = false;

    /**
     * Map is used to store the new values passed during the creation process
     * from the webapp.
     */
    private final Map<String, String[]> newValues = new HashMap<String, String[]>();

    /**
     * Is this form classified by classification.
     */
    private boolean classified = false;

    /**
     * Constructor.
     *
     * @param _commandUUID UUID of the command
     * @param _instanceKey oid for this model
     * @throws CacheReloadException on error
     */
    public UIForm(final UUID _commandUUID,
                  final String _instanceKey)
        throws CacheReloadException
    {
        this(_commandUUID, _instanceKey, null);
    }

    /**
     * Constructor.
     *
     * @param _commandUUID UUID of the command
     * @param _instanceKey oid for this model
     * @param _openerId id of the opener
     * @throws CacheReloadException on error
     */
    public UIForm(final UUID _commandUUID,
                  final String _instanceKey,
                  final String _openerId)
        throws CacheReloadException
    {
        super(_commandUUID, _instanceKey, _openerId);
        final AbstractCommand command = super.getCommand();
        if (command == null) {
            this.formUUID = null;
        } else if (command.getTargetForm() != null) {
            this.formUUID = command.getTargetForm().getUUID();
        }
    }

    /**
     * Method used to reset this UIForm.
     */
    @Override
    public void resetModel()
    {
        setInitialized(false);
        this.elements.clear();
        getHidden().clear();
    }

    /**
     * Method is used to execute the UIForm. (Fill it with data).
     */
    @Override
    public void execute()
    {
        try {
            // evaluate now to give the chance to change the mode
            if (evaluate4Instance()) {
                if (isCreateMode() || isSearchMode()) {
                    execute4NoInstance();
                } else {
                    if (getInstance() == null) {
                        execute4NoInstance();
                    } else {
                        execute4Instance();
                    }
                }
            }
        } catch (final EFapsException e) {
            throw new RestartResponseException(new ErrorPage(e));
        }
        super.setInitialized(true);
    }

    /**
     * This is a possibility to replace the current Instance for the form with
     * another one using an table evaluate esjp.
     *
     * @throws EFapsException on error
     */
    protected boolean evaluate4Instance()
        throws EFapsException
    {
        boolean ret = true;
        if (!isSearchMode()) {
            final List<Return> returns = getCommand().executeEvents(EventType.UI_TABLE_EVALUATE,
                            ParameterValues.INSTANCE, getInstance(),
                            ParameterValues.PARAMETERS, Context.getThreadContext().getParameters(),
                            ParameterValues.CLASS, this);
            for (final Return retu : returns) {
                if (retu.contains(ReturnValues.INSTANCE)) {
                    final Object object = retu.get(ReturnValues.INSTANCE);
                    if (object != null && object instanceof Instance && ((Instance) object).isValid()) {
                        setInstanceKey(((Instance) object).getOid());
                    } else {
                        UIForm.LOG.error("The esjp called by Command '{}' must return a valid instance",
                                        getCommand().getName());
                    }
                } else {
                    ret = false;
                }
            }
        }
        return ret;
    }

    private String getBaseSelect4MsgPhrase(final Field _field)
    {
        String ret = "";
        if (_field.getSelectAlternateOID() != null) {
            ret = StringUtils.removeEnd(_field.getSelectAlternateOID(), ".oid");
        }
        return ret;
    }


    /**
     * Method to execute the form in case that a instance is existing.
     *
     * @throws EFapsException
     *
     * @throws EFapsException on error
     */
    private void execute4Instance()
        throws EFapsException
    {
        int rowgroupcount = 1;
        int rowspan = 1;
        FormRow row = new FormRow();
        final Set<String> altOIDSel = new HashSet<String>();
        final Form form = Form.get(this.formUUID);
        // evaluate the Form to make the query
        final PrintQuery print = new PrintQuery(getInstance());
        for (final Field field : form.getFields()) {
            if (field.hasAccess(getMode(), getInstance(), getCommand(), getInstance())
                            && !field.isNoneDisplay(getMode())) {
                if (field.getSelect() != null) {
                    print.addSelect(field.getSelect());
                } else if (field.getAttribute() != null) {
                    print.addAttribute(field.getAttribute());
                } else if (field.getPhrase() != null) {
                    print.addPhrase(field.getName(), field.getPhrase());
                }  else if (field.getMsgPhrase() != null) {
                    print.addMsgPhrase(new SelectBuilder(getBaseSelect4MsgPhrase(field)), field.getMsgPhrase());
                }
                if (field.getSelectAlternateOID() != null) {
                    print.addSelect(field.getSelectAlternateOID());
                    altOIDSel.add(field.getSelectAlternateOID());
                }
            }
        }
        if (print.execute()) {
            if (!altOIDSel.isEmpty()) {
                final List<Instance> inst = new ArrayList<Instance>();
                for (final String sel : altOIDSel) {
                    inst.addAll(print.getInstances4Select(sel));
                }
                checkAccessToInstances(inst);
            }
            FormElement formElement = null;
            boolean addNew = true;
            UIClassification uiclass = null;
            boolean firstTable = true;
            for (final Field field : form.getFields()) {
                if (field.hasAccess(getMode(), getInstance(), getCommand(), getInstance())
                                && !field.isNoneDisplay(getMode())) {
                    if (field instanceof FieldGroup) {
                        final FieldGroup group = (FieldGroup) field;
                        // in case that the first field is a group the element
                        // must be initiated
                        if (formElement == null) {
                            formElement = new FormElement();
                            this.elements.add(new Element(UIForm.ElementType.FORM, formElement));
                            addNew = false;
                        }
                        if (formElement.getMaxGroupCount() < group.getGroupCount()) {
                            formElement.setMaxGroupCount(group.getGroupCount());
                        }
                        rowgroupcount = group.getGroupCount();
                    } else if (field instanceof FieldTable) {
                        if (((FieldTable) field).getTargetStructurBrowserField() == null) {
                            final UIFieldTable uiFieldTable = new UIFieldTable(getCommandUUID(), getInstanceKey(),
                                            (FieldTable) field);
                            uiFieldTable.setMode(getMode());
                            this.elements.add(new Element(UIForm.ElementType.TABLE, uiFieldTable));
                            if (firstTable) {
                                firstTable = false;
                            } else {
                                uiFieldTable.setFirstTable(false);
                            }
                        } else {
                            final UIFieldStructurBrowser uiFieldStrucBrws = new UIFieldStructurBrowser(
                                            getCommandUUID(),
                                            getInstanceKey(), (FieldTable) field);
                            uiFieldStrucBrws.setMode(getMode());
                            this.elements.add(new Element(UIForm.ElementType.STRUCBRWS, uiFieldStrucBrws));
                        }
                        addNew = true;
                    } else if (field instanceof FieldHeading) {
                        this.elements.add(new Element(UIForm.ElementType.HEADING,
                                        new UIHeading((FieldHeading) field)));
                        addNew = true;
                    } else if (field instanceof FieldClassification) {
                        uiclass = UIClassification.getUIClassification(field, this);
                        this.elements.add(new Element(UIForm.ElementType.CLASSIFICATION, uiclass));
                        addNew = true;
                        this.classified = true;
                    } else {
                        if (addNew) {
                            formElement = new FormElement();
                            this.elements.add(new Element(UIForm.ElementType.FORM, formElement));
                            addNew = false;
                        }
                        if (addCell2FormRow(row, print, field)) {
                            if (field.getRowSpan() > 0) {
                                rowspan = field.getRowSpan();
                            }
                            rowgroupcount--;
                            if (rowgroupcount < 1) {
                                rowgroupcount = 1;
                                if (row.getGroupCount() > 0) {
                                    formElement.addRowModel(row);
                                    row = new FormRow();
                                    if (rowspan > 1) {
                                        rowspan--;
                                        row.setRowSpan(true);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (uiclass != null) {
                final Map<UUID, String> instanceKeys = uiclass.getClassInstanceKeys(getInstance());
                if (instanceKeys.size() > 0) {
                    if (!uiclass.isInitialized()) {
                        uiclass.execute(getInstance());
                    }
                    addClassElements(uiclass, instanceKeys);
                }
            }
        }
    }

    /**
     * Method that adds the classification forms as elements to the form by
     * walking down the tree.
     *
     * @param _uiclass the classification to be added
     * @param _instanceKeys map from uuid to instance keys
     * @throws EFapsException on error
     */
    public void addClassElements(final UIClassification _uiclass,
                                 final Map<UUID, String> _instanceKeys)
        throws EFapsException
    {
        this.elements.addAll(getClassElements(_uiclass, _instanceKeys));
    }

    /**
     * Method that removes all classifcations and afterwards adds the
     * classification forms as elements to the form by walking down the tree.
     *
     * @param _uiclass the classification to be added
     * @throws EFapsException on error
     */
    public void updateClassElements(final UIClassification _uiclass)
        throws EFapsException
    {
        // remove previous added classification forms
        final Iterator<Element> iter2 = this.elements.iterator();
        final Map<UUID, String> uuid2InstanceKey = new HashMap<UUID, String>();
        while (iter2.hasNext()) {
            final IFormElement element = iter2.next().getElement();
            if (element instanceof UIFieldForm) {
                final String instanceKey = ((UIFieldForm) element).getInstanceKey();
                if (instanceKey != null) {
                    final UUID classUUID = ((UIFieldForm) element).getClassificationUUID();
                    uuid2InstanceKey.put(classUUID, instanceKey);
                }
                iter2.remove();
            }
        }
        addClassElements(_uiclass, uuid2InstanceKey);
    }

    /**
     * Method to add a Cell to the given Row.
     *
     * @param _row FormRow to add the cell to
     * @param _query query containing the values
     * @param _field field the cell belongs to
     * @throws EFapsException on error
     * @return true if the cell was actually added, else false
     */
    private boolean addCell2FormRow(final FormRow _row,
                                    final PrintQuery _query,
                                    final Field _field)
        throws EFapsException
    {
        boolean ret = true;
        Attribute attr = null;
        if (_field.getAttribute() != null) {
            attr = _query.getAttribute4Attribute(_field.getAttribute());
        } else if (_field.getSelect() != null) {
            attr = _query.getAttribute4Select(_field.getSelect());
        }

        // evaluate the label of the field
        String label;
        if (_field.getLabel() != null) {
            label = _field.getLabel();
        } else if (attr != null) {
            label = attr.getParent().getName() + "/" + attr.getName() + ".Label";
        } else {
            label = "Unknown";
        }

        Instance fieldInstance;
        if (_field.getSelectAlternateOID() != null
                        && _query.getSelect(_field.getSelectAlternateOID()) instanceof String) {
            fieldInstance = Instance.get(_query.<String>getSelect(_field.getSelectAlternateOID()));
        } else {
            fieldInstance = getInstance();
        }
        if (_field.isHiddenDisplay(getMode())) {
            Object value = null;
            if (_field.getAttribute() != null) {
                value = _query.getAttribute(_field.getAttribute());
            } else if (_field.getSelect() != null) {
                value = _query.getSelect(_field.getSelect());
            } else if (_field.getPhrase() != null) {
                value = _query.getPhrase(_field.getName());
            }
            // temp to decide what to do TODO remove in future
            if (_field.getClassUI() == null && _field.getUIProvider() != null
                            || attr != null && attr.getAttributeType().getUI() == null
                            || attr == null && _field.getClassUI() == null && _field.getUIProvider() == null
                            || attr != null && attr.getAttributeType().getUI() != null
                            && (attr.getAttributeType().getUI() instanceof TypeUI
                            || attr.getAttributeType().getUI() instanceof UserUI)) {
                addHidden(evaluateUIProvider(_row, _query, _field, fieldInstance, label, attr));
            } else {

                final FieldValue fieldvalue = new FieldValue(_field, attr, value, fieldInstance, getInstance(), null,
                                this);
                final String strValue = fieldvalue.getHiddenHtml(getMode());
                addHidden(new UIHiddenCell(this, fieldvalue, null, strValue));
            }
            ret = false;
        } else {
            // fieldset
            if (_field instanceof FieldSet) {
                evaluateFieldSet(_row, _query, _field, fieldInstance, label);
            } else if (_field instanceof FieldCommand) {
                final UIFormCellCmd fieldCmd = new UIFormCellCmd(this, (FieldCommand) _field, fieldInstance, label);
                _row.add(fieldCmd);
            } else if (_field instanceof FieldChart) {
                final UIFormCellChart fieldChart = new UIFormCellChart(this, (FieldChart) _field, fieldInstance, label);
                _row.add(fieldChart);
            } else {
                // temp to decide what to do TODO remove in future
                if (_field.getClassUI() == null && _field.getUIProvider() != null
                                || attr != null && attr.getAttributeType().getUI() == null
                                || attr == null && _field.getClassUI() == null && _field.getUIProvider() == null
                                || attr != null && attr.getAttributeType().getUI() != null
                                  && (attr.getAttributeType().getUI() instanceof TypeUI
                                    || attr.getAttributeType().getUI() instanceof UserUI)) {
                    _row.add(evaluateUIProvider(_row, _query, _field, fieldInstance, label, attr));
                } else {
                    evaluateField(_row, _query, _field, fieldInstance, label, attr);
                }
            }
        }
        return ret;
    }

    /**
     * Method evaluates a Field and adds it to the row.
     *
     * @param _row FormRow to add the cell to
     * @param _print query containing the values
     * @param _field field the cell belongs to
     * @param _fieldInstance instance of the Field
     * @param _label label for the Field
     * @param _attr attribute for the Field
     * @throws EFapsException on error
     */
    private UIField evaluateUIProvider(final FormRow _row,
                                       final PrintQuery _print,
                                       final Field _field,
                                       final Instance _fieldInstance,
                                       final String _label,
                                       final Attribute _attr)
        throws EFapsException
    {
        Object value = null;
        if (_field.getAttribute() != null) {
            value = _print.<Object>getAttribute(_field.getAttribute());
        } else if (_field.getSelect() != null) {
            value = _print.<Object>getSelect(_field.getSelect());
        } else if (_field.getPhrase() != null) {
            value = _print.getPhrase(_field.getName());
        } else if (_field.getMsgPhrase() != null) {
            value = _print.getMsgPhrase(new SelectBuilder(getBaseSelect4MsgPhrase(_field)), _field.getMsgPhrase());
        }
        final UIField uiField = new UIField(_fieldInstance.getKey(), this, UIValue.get(_field, _attr, value)
                        .setInstance(_fieldInstance).setClassObject(this));
        return uiField;
    }

    /**
     * Method evaluates a Field and adds it to the row.
     *
     * @param _row FormRow to add the cell to
     * @param _query query containing the values
     * @param _field field the cell belongs to
     * @param _fieldInstance instance of the Field
     * @param _label label for the Field
     * @param _attr attribute for the Field
     * @throws EFapsException on error
     */
    private void evaluateField(final FormRow _row,
                               final PrintQuery _query,
                               final Field _field,
                               final Instance _fieldInstance,
                               final String _label,
                               final Attribute _attr)
        throws EFapsException
    {
        Object value = null;
        if (_field.getAttribute() != null) {
            value = _query.<Object>getAttribute(_field.getAttribute());
        } else if (_field.getSelect() != null) {
            value = _query.<Object>getSelect(_field.getSelect());
        } else if (_field.getPhrase() != null) {
            value = _query.getPhrase(_field.getName());
        } else if (_field.getMsgPhrase() != null) {
            value = _query.getMsgPhrase(new SelectBuilder(getBaseSelect4MsgPhrase(_field)), _field.getMsgPhrase());
        }

        final FieldValue fieldvalue = new FieldValue(_field, _attr, value, _fieldInstance, getInstance(), null, this,
                        getCallingCommandUUID() == null ? getCommand() : getCallingCommand());

        String strValue = null;
        if (isPrintMode()) {
            strValue = fieldvalue.getStringValue(getMode());
        } else {
            if (isEditMode() && _field.isEditableDisplay(getMode())) {
                if (_field.hasEvents(EventType.UI_FIELD_AUTOCOMPLETE)) {
                    strValue = fieldvalue.getStringValue(getMode());
                } else {
                    strValue = fieldvalue.getEditHtml(getMode());
                }
            } else if (_field.isReadonlyDisplay(getMode())) {
                strValue = fieldvalue.getReadOnlyHtml(getMode());
            }
        }
        if (strValue != null && !this.fileUpload) {
            final String tmp = strValue.replaceAll(" ", "");
            if (tmp.toLowerCase().contains("type=\"file\"")) {
                this.fileUpload = true;
            }
        }
        String icon = _field.getIcon();
        if (_fieldInstance != null) {
            if (_field.isShowTypeIcon() && _fieldInstance.getType() != null) {
{'fraction_non_alphanumeric': 0.09541938845028654, 'fraction_numerical': 0.0024646335110006814, 'mean_word_length': 1.676839733962669, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 60, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '530329', 'n_tokens_mistral': 12755, 'n_tokens_neox': 12469, 'n_words': 3219}