/*
 * Copyright 2003 - 2016 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.
 *
 */

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

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
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.collections4.IteratorUtils;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.util.io.IClusterable;
import org.apache.wicket.util.string.StringValue;
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.UIValue;
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.field.Field;
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.api.ci.UIFormProperty;
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.field.AbstractUIField;
import org.efaps.ui.wicket.models.field.IUIElement;
import org.efaps.ui.wicket.models.field.UICmdField;
import org.efaps.ui.wicket.models.field.UIField;
import org.efaps.ui.wicket.models.field.UIGroup;
import org.efaps.ui.wicket.models.field.UIPicker;
import org.efaps.ui.wicket.models.field.set.UIFieldSet;
import org.efaps.ui.wicket.models.field.set.UIFieldSetColHeader;
import org.efaps.ui.wicket.models.field.set.UIFieldSetValue;
import org.efaps.ui.wicket.models.objects.grid.UIFieldGrid;
import org.efaps.ui.wicket.pages.error.ErrorPage;
import org.efaps.ui.wicket.util.Configuration;
import org.efaps.ui.wicket.util.Configuration.ConfigAttribute;
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
 */
public class UIForm
    extends AbstractUIPageObject
    implements ISelectedRowObject, IPageObject, IWizardElement
{

    /**
     * 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,
        /** Element is a grid. */
        GRID;
    }

    /**
     * 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<>();

    /**
     * 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 multiPart = 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<>();

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

    /** The selected. */
    private List<StringValue> selected;

    /** The pageposition. */
    private PagePosition pagePosition;

    /** The ui wizard object. */
    private UIWizardObject uiWizardObject;

    /**
     * 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);
        if (_commandUUID != null) {
            final AbstractCommand command = super.getCommand();
            if (command == null) {
                setFormUUID(null);
            } else if (command.getTargetForm() != null) {
                setFormUUID(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.
     *
     * @return true, if successful
     * @throws EFapsException on error
     */
    protected boolean evaluate4Instance()
        throws EFapsException
    {
        boolean ret = true;
        if (!isSearchMode()) {
            final List<Return> returns = this.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",
                                        this.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
    {
        final Set<String> altOIDSel = new HashSet<>();
        final Form form = getForm();
        // evaluate the Form to make the query
        final PrintQuery print = new PrintQuery(getInstance());
        for (final Field field : form.getFields()) {
            if (field.hasAccess(getMode(), getInstance(), this.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<>();
                for (final String sel : altOIDSel) {
                    inst.addAll(print.getInstances4Select(sel));
                }
                checkAccessToInstances(inst);
            }
            FormElement currentFormElement = null;
            boolean addNew = true;
            UIClassification uiclass = null;
            boolean firstTable = true;
            for (final Field field : form.getFields()) {
                final Instance instance = evaluateFieldInstance(print, field);
                if (field.hasAccess(getMode(), instance, this.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 (currentFormElement == null) {
                            currentFormElement = new FormElement();
                            this.elements.add(new Element(UIForm.ElementType.FORM, currentFormElement));
                            addNew = false;
                        }
                        currentFormElement.setGroupCount(group.getGroupCount());
                    } else if (field instanceof FieldTable) {
                        if (((FieldTable) field).getTargetStructurBrowserField() == null) {
                            if (isViewMode() && "GridX".equals(Configuration.getAttribute(
                                            ConfigAttribute.TABLE_DEFAULTTYPEFORM))) {
                                final UIFieldGrid grid = UIFieldGrid.get(getCommandUUID(), getPagePosition(),
                                                getInstance(), (FieldTable) field);
                                this.elements.add(new Element(UIForm.ElementType.GRID, grid));
                            } else {
                                final UIFieldTable uiFieldTable = new UIFieldTable(getCommandUUID(),
                                                getInstanceKey(), (FieldTable) field);
                                uiFieldTable.setPagePosition(getPagePosition());
                                uiFieldTable.setMode(getMode());
                                this.elements.add(new Element(UIForm.ElementType.TABLE, uiFieldTable));
                                if (firstTable) {
                                    firstTable = false;
                                } else {
                                    uiFieldTable.setFirstTable(false);
                                }
                            }
                        } else {
                            if (isViewMode() && "GridX".equals(Configuration.getAttribute(
                                            ConfigAttribute.STRUCBRWSR_DEFAULTTYPEFORM))) {
                                final UIFieldGrid grid = UIFieldGrid.get(getCommandUUID(), getPagePosition(),
                                                getInstance(), (FieldTable) field);
                                this.elements.add(new Element(UIForm.ElementType.GRID, grid));
                            } 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) {
                            final FormElement formElement = new FormElement().setGroupCount(currentFormElement == null
                                            ? 0 : currentFormElement.getGroupCount());
                            currentFormElement = formElement;
                            this.elements.add(new Element(UIForm.ElementType.FORM, currentFormElement));
                            addNew = false;
                        }
                        addCell2FormRow(currentFormElement, print, field);
                    }
                }
            }
            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<>();
        while (iter2.hasNext()) {
            final IFormElement element = iter2.next().getElement();
            if (element instanceof UIFieldForm) {
                final String instanceKey = ((UIFieldForm) element).getInstanceKey();
                final TargetMode mode = ((UIFieldForm) element).getMode();
                if (instanceKey != null && !TargetMode.CREATE.equals(mode)) {
                    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 _formElement the form element
     * @param _query query containing the values
     * @param _field field the cell belongs to
     * @return true if the cell was actually added, else false
     * @throws EFapsException on error
     */
    private boolean addCell2FormRow(final FormElement _formElement,
                                    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());
        }

        final Instance fieldInstance = evaluateFieldInstance(_query, _field);
        if (_field.isHiddenDisplay(getMode())) {
            if (_field.getAttribute() != null) {
                _query.getAttribute(_field.getAttribute());
            } else if (_field.getSelect() != null) {
                _query.getSelect(_field.getSelect());
            } else if (_field.getPhrase() != null) {
                _query.getPhrase(_field.getName());
            }
            addHidden(evaluateUIProvider(_query, _field, fieldInstance, attr));
            ret = false;
        } else {
            // fieldset
            if (_field instanceof FieldSet) {
                _formElement.addValue(evaluateFieldSet(_query, _field, fieldInstance));
            } else if (_field instanceof FieldCommand) {
                final UICmdField cell = new UICmdField(this, (FieldCommand) _field, getInstance());
                _formElement.addValue(cell);
            } else if (_field instanceof FieldPicker) {
                final UIField cell = new UIField(this, getInstance().getKey(),
                                UIValue.get(_field, attr, null).setClassObject(this).setInstance(getInstance())
                                    .setCallInstance(getInstance()));
                final UIPicker picker = new UIPicker((FieldPicker) _field, cell);
                cell.setPicker(picker);
                _formElement.addValue(cell);
            } else {
                _formElement.addValue(evaluateUIProvider(_query, _field, fieldInstance, attr));
            }
        }
        return ret;
    }

    /**
     * Method evaluates a Field and adds it to the row.
     *
     * @param _print query containing the values
     * @param _field field the cell belongs to
     * @param _fieldInstance instance of the Field
     * @param _attr attribute for the Field
     * @return the UI field
     * @throws EFapsException on error
     */
    private UIField evaluateUIProvider(final PrintQuery _print,
                                       final Field _field,
                                       final Instance _fieldInstance,
                                       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(this, _fieldInstance.getKey(), UIValue.get(_field, _attr, value)
                        .setInstance(_fieldInstance)
                        .setCallInstance(getInstance())
                        .setClassObject(this));
        return uiField;
    }

    /**
     * Method evaluates a FieldSet and adds it to the row.
     *
     * @param _query query containing the values
     * @param _field field the cell belongs to
     * @param _fieldInstance instance of the FieldSet
     * @return the UI field set
     * @throws EFapsException on error
     */
    private UIFieldSet evaluateFieldSet(final PrintQuery _query,
                                        final Field _field,
                                        final Instance _fieldInstance)
        throws EFapsException
    {
        final AttributeSet attrSet = AttributeSet.find(getInstance().getType().getName(), _field.getAttribute());

        final Map<?, ?> tmp = (Map<?, ?>) _query.getAttributeSet(_field.getAttribute());

        final List<Instance> fieldins = new ArrayList<>();

        if (tmp != null) {
            fieldins.addAll(_query.getInstances4Attribute(_field.getAttribute()));
        }
        final UIFieldSet ret = new UIFieldSet(this, _fieldInstance,
                        UIValue.get(_field, getInstance().getType().getAttribute(_field.getAttribute()), null));
        ret.setMode(getMode());

        for (final String attrName : ((FieldSet) _field).getOrder()) {
            final Attribute child = attrSet.getAttribute(attrName);
            final UIFieldSetColHeader column = new UIFieldSetColHeader(_field.getLabel(), child, _field);
            ret.addHeader(column);
        }

        final Iterator<Instance> iter = fieldins.iterator();
        final Map<String, Iterator<?>> values = new HashMap<>();
        while (iter.hasNext()) {
            final Instance rowInstance = iter.next();
            ret.addRow(rowInstance);
            for (final String attrName : ((FieldSet) _field).getOrder()) {
                final Attribute child = attrSet.getAttribute(attrName);
                Iterator<?> valIter = values.get(attrName);
                if (valIter == null) {
                    final List<?> tmplist = (List<?>) tmp.get(attrName);
                    valIter = tmplist.iterator();
                    values.put(attrName, valIter);
                }
                final UIValue uiValue = UIValue.get(_field, child, valIter.hasNext() ? valIter.next() : null);
                ret.addValue(rowInstance,
                                new UIFieldSetValue(this, rowInstance.getKey(), ret, uiValue));
            }
        }
        return ret;
    }

    /**
     * Recursive method to add the children classification forms.
     *
     * @param _uiclass parent classification form
     * @param _uuid2InstanceKey mapping of instancekeys
     * @return List of elements to be added
     * @throws EFapsException on error
     */
    private List<Element> getClassElements(final UIClassification _uiclass,
                                           final Map<UUID, String> _uuid2InstanceKey)
        throws EFapsException
    {
        final List<Element> ret = new ArrayList<>();
        if (_uiclass.isSelected() && !_uiclass.isRoot()) {
            final UIFieldForm fieldform;
            if (_uuid2InstanceKey.containsKey(_uiclass.getClassificationUUID())) {
                fieldform = new UIFieldForm(getCommandUUID(),
                                _uuid2InstanceKey.get(_uiclass.getClassificationUUID()));
            } else {
                fieldform = new UIFieldForm(getCommandUUID(), _uiclass);
                if (isEditMode()) {
                    // in edit mode, if there is no classification yet, create
                    // mode must be forced
                    fieldform.setMode(TargetMode.CREATE);
                }
            }
            ret.add(new Element(ElementType.SUBFORM, fieldform));
        }
        for (final UIClassification child : _uiclass.getChildren()) {
            ret.addAll(getClassElements(child, _uuid2InstanceKey));
        }
        Collections.sort(ret, (_o1,
         _o2) -> ((UIFieldForm) _o1.getElement()).getWeight().compareTo(
                        ((UIFieldForm) _o2.getElement()).getWeight()));
        return ret;
    }

    /**
     * Method to execute the form in case of create or search.
     *
     * @throws EFapsException on error
     */
    private void execute4NoInstance()
        throws EFapsException
    {
        final Form form = getForm();
        Type type = null;
        if (isCreateMode() || isEditMode()) {
            type = getCreateTargetType();
        } else {
            final List<EventDefinition> events = this.getCommand().getEvents(EventType.UI_TABLE_EVALUATE);
            if (events != null) {
                for (final EventDefinition eventDef : events) {
                    String tmp = eventDef.getProperty("Type");
                    if (tmp == null) {
                        tmp = eventDef.getProperty("Types");
                        if (tmp != null) {
                            UIForm.LOG.warn("Event '{}' uses deprecated API for type.", eventDef.getName());
                        } else {
                            UIForm.LOG.error("Event '{}' is not type property", eventDef.getName());
                        }
                    }
                    if (tmp != null) {
                        type = Type.get(tmp);
                        break;
                    }
                }
            }
        }

        FormElement currentFormElement = null;
        boolean addNew = true;
        UIClassification uiclass = null;
        boolean firstTable = true;
        for (final Field field : form.getFields()) {
            if (field.hasAccess(getMode(), AbstractInstanceObject.getInstance4Create(type), this.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 (currentFormElement == null) {
                        currentFormElement = new FormElement();
                        this.elements.add(new Element(UIForm.ElementType.FORM, currentFormElement));
                        addNew = false;
                    }
                    currentFormElement.setGroupCount(group.getGroupCount());
                } 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));
                    this.classified = true;
                    addNew = true;
                } else if (field instanceof FieldTable) {
                    if (((FieldTable) field).getTargetStructurBrowserField() == null) {
                        final UIFieldTable uiFieldTable = new UIFieldTable(getCommandUUID(), getInstanceKey(),
                                                                           (FieldTable) field);
                        this.elements.add(new Element(UIForm.ElementType.TABLE, uiFieldTable));
                        if (firstTable) {
                            firstTable = false;
                        } else {
                            uiFieldTable.setFirstTable(false);
                        }
                    } else {
                        if ("GridX".equals(Configuration.getAttribute(ConfigAttribute.STRUCBRWSR_DEFAULTTYPEFORM))) {
                            final UIFieldGrid grid = UIFieldGrid.get(getCommandUUID(), getPagePosition(),
                                            getInstance(), (FieldTable) field);
                            this.elements.add(new Element(UIForm.ElementType.GRID, grid));
                        } else {
                            final UIFieldStructurBrowser uiFieldStrucBrws = new UIFieldStructurBrowser(getCommandUUID(),
                                        getInstanceKey(), (FieldTable) field);
                            this.elements.add(new Element(UIForm.ElementType.STRUCBRWS, uiFieldStrucBrws));
                        }
                    }
                    addNew = true;
                } else {
                    if (addNew) {
                        final FormElement formElement = new FormElement().setGroupCount(currentFormElement == null ? 0
                                        : currentFormElement.getGroupCount());
                        currentFormElement = formElement;
                        this.elements.add(new Element(UIForm.ElementType.FORM, currentFormElement));
                        addNew = false;
                    }
                    final Attribute attr;
                    if (field.getAttribute() == null && field.getSelect() != null && type != null) {
                        final PrintQuery print = new PrintQuery(AbstractInstanceObject.getInstance4Create(type));
                        print.addSelect(field.getSelect());
                        print.dryRun();
                        attr = print.getAttribute4Select(field.getSelect());
                    } else {
                        attr = type != null ? type.getAttribute(field.getAttribute()) : null;
                    }

                    if (field.isHiddenDisplay(getMode())) {
                        final UIField uiField = new UIField(this, null, UIValue.get(field, attr, null)
                                        .setClassObject(this)
                                        .setInstance(getInstance()).setCallInstance(getInstance()));
                        addHidden(uiField);
                    } else {
                        final IUIElement cell;
                        if (field instanceof FieldSet) {
                            cell = new UIFieldSet(this, getInstance(), UIValue.get(field, attr, null)
                                                .setClassObject(this)
                                                .setInstance(getInstance())
                                                .setCallInstance(getInstance()));
                            if (type == null) {
                                ((UIFieldSet) cell).addHeader(new UIFieldSetColHeader(field.getLabel(), null, field));
                            } else {
                                final AttributeSet set = AttributeSet.find(type.getName(), field.getAttribute());
                                for (final String attrName : ((FieldSet) field).getOrder()) {
                                    final Attribute child = set.getAttribute(attrName);
                                    final UIFieldSetColHeader column = new UIFieldSetColHeader(field.getLabel(), child,
                                                    field);
                                    ((UIFieldSet) cell).addHeader(column);
                                }
                            }
                        } else if (field instanceof FieldCommand) {
                            cell = new UICmdField(this, (FieldCommand) field, getInstance());
                        } else if (field instanceof FieldPicker) {
                            cell = new UIField(this, null, UIValue.get(field, attr, null).setClassObject(this)
                                            .setInstance(getInstance()).setCallInstance(getInstance()));
                            final UIPicker picker = new UIPicker((FieldPicker) field, (AbstractInstanceObject) cell);
                            ((UIField) cell).setPicker(picker);
                        } else {
                            cell = new UIField(this, null, UIValue.get(field, attr,
                                                super.isPartOfWizardCall() ? getValue4Wizard(field.getName()) : null)
                                                .setClassObject(this)
                                                .setInstance(AbstractInstanceObject.getInstance4Create(type))
                                                .setCallInstance(getInstance()));
                        }
                        currentFormElement.addValue(cell);
                    }
                }
            }
        }
        if (uiclass != null) {
            final Set<Classification> clazzes = this.getCommand().getTargetCreateClassification();
            for (final Classification clazz : clazzes) {
                uiclass.addSelectedUUID(clazz.getUUID());
                Classification parent = clazz.getParentClassification();
                while (parent != null) {
                    uiclass.addSelectedUUID(parent.getUUID());
                    parent = parent.getParentClassification();
                }
            }
            if (!uiclass.isInitialized()) {
                uiclass.execute(null);
            }
            this.elements.addAll(getClassElements(uiclass, new HashMap<UUID, String>()));
        }
    }

    /**
     * Method to get the type that will be created by a form. A method must be
     * used so it can be overwritten.
     *
     * @return Type to be created
     * @throws CacheReloadException on error
     */
    protected Type getCreateTargetType()
        throws CacheReloadException
    {
        return this.getCommand().getTargetCreateType();
    }

    /**
     * Method to get the Form from eFaps using the instance variable
     * {@link #formUUID}.
     *
     * @return Form from eFaps
     * @throws CacheReloadException on error
     */
    public Form getForm()
        throws CacheReloadException
    {
        return Form.get(this.formUUID);
    }

    /**
     * This is the getter method for the instance variable {@link #formUUID}.
     *
     * @return value of instance variable {@link #formUUID}
     */
    public UUID getUUID()
    {
        return this.formUUID;
    }

    /**
     * This is the getter method for the instance variable {@link #formUUID}.
     *
     * @return value of instance variable {@link #formUUID}
     */
    public UUID getFormUUID()
    {
        return this.formUUID;
    }

    /**
     * This is the setter method for the instance variable {@link #formUUID}.
     *
     * @param _formUUID the formUUID to set
     * @throws CacheReloadException on error
     */
    public void setFormUUID(final UUID _formUUID)
        throws CacheReloadException
    {
        this.formUUID = _formUUID;
        if (_formUUID != null) {
            this.multiPart = "true".equalsIgnoreCase(getForm().getProperty(UIFormProperty.MULTI_PART));
        }
    }

    /**
     * This is the getter method for the instance variable {@link #elements}.
     *
     * @return value of instance variable {@link #elements}
     */
    public final List<Element> getElements()
    {
        return Collections.unmodifiableList(this.elements);
    }

    /**
     * This is the getter method for the instance variable {@link #fileUpload}.
     *
     * @return value of instance variable {@link #fileUpload}
     */
    public boolean isMultiPart()
    {
        return this.multiPart;
    }

    /**
     * This is the setter method for the instance variable {@link #fileUpload}.
     *
     * @param _fileUpload the fileUpload to set
     */
    public void setMultiPart(final boolean _fileUpload)
    {
        this.multiPart = _fileUpload;
    }

    /**
     * This is the getter method for the instance variable {@link #newValues}.
     *
     * @return value of instance variable {@link #newValues}
     */
    public Map<String, String[]> getNewValues()
    {
        return this.newValues;
    }

    /**
     * Getter method for instance variable {@link #classified}.
     *
     * @return value of instance variable {@link #classified}
     */
    public boolean isClassified()
    {
        return this.classified;
    }

    /**
     * Getter method for the instance variable {@link #selected}.
     *
     * @return value of instance variable {@link #selected}
     */
    @Override
    public List<StringValue> getSelected()
    {
        return this.selected;
    }

    /**
     * Setter method for instance variable {@link #selected}.
     *
     * @param _selected value for instance variable {@link #selected}
     */
    public void setSelected(final List<StringValue> _selected)
    {
        this.selected = _selected;
    }

    @Override
    public PagePosition getPagePosition()
    {
        final PagePosition ret;
        if (this.pagePosition == null) {
            //TODO remove
            UIForm.LOG.error("MISSING PAGEPOSITION!!!");
            ret = PagePosition.CONTENT;
        } else {
            ret = this.pagePosition;
        }
        return ret;
    }

    /**
     * Setter method for instance variable {@link #pagePosition}.
     *
     * @param _pagePosition value for instance variable {@link #pagePosition}
     * @return the UI form
     */
    public UIForm setPagePosition(final PagePosition _pagePosition)
    {
        this.pagePosition = _pagePosition;
        return this;
    }

    @Override
    public boolean isWizardCall()
    {
        return getUIWizardObject() != null;
    }

    @Override
    public UIWizardObject getUIWizardObject()
    {
        return this.uiWizardObject;
    }

    @Override
    public IWizardElement setUIWizardObject(final UIWizardObject _uiWizardObject)
    {
        this.uiWizardObject = _uiWizardObject;
        return this;
    }

    /**
     * Class is used as store for one Row in the UIForm.
     */
    public static class FormRow
        implements IClusterable
    {

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

        /**
         * Stores the UIFormCell contained in this FormRow.
         */
        private final ArrayDeque<IUIElement> values = new ArrayDeque<>();

        /**
         * Stores if the row must be spanned.
         */
        private int rowSpan = 0;

        /**
         * Add a UIFormCell to this FormRow.
         *
         * @param _uiElement the ui element
         */
        public void add(final IUIElement _uiElement)
        {
            if (_uiElement instanceof AbstractUIField
                            && ((AbstractUIField) _uiElement).getFieldConfiguration().getRowSpan() > 1) {
                this.rowSpan = ((AbstractUIField) _uiElement).getFieldConfiguration().getRowSpan();
                this.values.add(_uiElement);
            } else if (isRowSpan()) {
                this.rowSpan--;
                final IUIElement current = this.values.getLast();
                final UIGroup group;
                if (current instanceof UIGroup) {
                    group = (UIGroup) current;
                } else {
                    group = new UIGroup();
                    this.values.addLast(group);
                }
                group.add((AbstractUIField) _uiElement);
            } else {
                this.values.add(_uiElement);
            }
        }

        /**
         * Getter method for the instance variable {@link #rowSpan}.
         *
         * @return value of instance variable {@link #rowSpan}
         */
        public boolean isRowSpan()
        {
            return this.rowSpan > 0;
        }

        /**
         * Getter method for the instance variable {@link #values}.
         *
         * @return value of instance variable {@link #values}
         */
        public List<IUIElement> getValues()
        {
            return IteratorUtils.toList(this.values.iterator());
        }

        /**
         * Method to get the group count of this row.
         *
         * @return size of the values
         */
        public int getGroupCount()
        {
            return this.values.size();
        }

        /**
         * Getter method for the instance variable {@link #rowSpan}.
         *
         * @return value of instance variable {@link #rowSpan}
         */
        public int getRowSpan()
        {
            return this.rowSpan;
        }

        /**
         * Setter method for instance variable {@link #rowSpan}.
         *
         * @param _rowSpan value for instance variable {@link #rowSpan}
         * @return the form row
         */
        public FormRow setRowSpan(final int _rowSpan)
        {
            this.rowSpan = _rowSpan;
            return this;
        }
    }

    /**
     * Class represents a Element of Type Form used in a Form.
     */
    public static class FormElement
        implements IFormElement, IClusterable
    {

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

        /**
         * Stores the FormRows for this FormElement.
         */
        private final ArrayDeque<FormRow> rowModels = new ArrayDeque<>();

        /** The group count. */
        private int groupCount = 0;

        /**
         * This is the getter method for the instance variable
         * {@link #rowModels}.
         *
         * @return value of instance variable {@link #rowModels}
         */
        public Iterator<FormRow> getRowModels()
        {
            return this.rowModels.iterator();
        }

        /**
         * Adds the value.
         *
         * @param _uiElement the ui element
         * @return the form element
         */
        public FormElement addValue(final IUIElement _uiElement)
        {
            if (this.groupCount < 1 && !this.rowModels.isEmpty() && !this.rowModels.getLast().isRowSpan()) {
                this.rowModels.addLast(new FormRow());
            } else {
                this.groupCount--;
            }
            if (this.rowModels.isEmpty()) {
                this.rowModels.addLast(new FormRow());
            }
            this.rowModels.getLast().add(_uiElement);
            return this;
        }

        /**
         * Sets the group count.
         *
         * @param _groupCount the new group count
         * @return the form element
         */
        public FormElement setGroupCount(final int _groupCount)
        {
            if (_groupCount > 1) {
                this.rowModels.addLast(new FormRow());
            }
            this.groupCount = _groupCount;
            return this;
        }

        /**
         * Gets the group count.
         *
         * @return the group count
         */
        public int getGroupCount()
        {
            return this.groupCount;
        }
    }

    /**
     * Class represent one Element in a UIForm.
     */
    public static class Element
        implements IClusterable
    {

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

        /**
         * ElementType of this Element.
         */
        private final ElementType type;

        /**
         * Model of this Element.
         */
        private final IFormElement element;

        /**
         * Constructor setting the instance variables.
         *
         * @param _type ElementType of this Element
         * @param _formElement Model of this Element
         */
        public Element(final ElementType _type,
                       final IFormElement _formElement)
        {
            this.type = _type;
            this.element = _formElement;
        }

        /**
         * Getter method for the instance variable {@link #type}.
         *
         * @return value of instance variable {@link #type}
         */
        public ElementType getType()
        {
            return this.type;
        }

        /**
         * Getter method for the instance variable {@link #element}.
         *
         * @return value of instance variable {@link #element}
         */
        public IFormElement getElement()
        {
            return this.element;
        }
    }
}


/*
 * Copyright 2003 - 2016 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.
 *
 */

package org.efaps.ui.wicket.behaviors.dojo;

import org.apache.wicket.Component;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.efaps.ui.wicket.util.DojoClasses;

/**
 * This class turns a Component into a Dojo-ContentPane.
 *
 * @author The eFaps Team
 */
public class ContentPaneBehavior
    extends AbstractDojoBehavior
{

    /**
     * Enum is used when this ContentPaneBehavior is used as a child inside a
     * BorderContainer. The BorderContainer is widget is partitioned into up to
     * five regions: left (or leading), right (or trailing), top, and bottom
     * with a mandatory center to fill in any remaining space. Each edge region
     * may have an optional splitter user interface for manual resizing.
     */
    public enum Region
    {
        /** center region. */
        CENTER("center"),
        /** top region. */
        TOP("top"),
        /** bottom region. */
        BOTTOM("bottom"),
        /** leading region. */
        LEADING("leading"),
        /** trailing region. */
        TRAILING("trailing"),
        /** left region. */
        LEFT("left"),
        /** right region. */
        RIGHT("right");

        /**
         * Stores the key of the Region.
         */
        private final String key;

        /**
         * Private Constructor.
         *
         * @param _key Key
         */
        Region(final String _key)
        {
            this.key = _key;
        }

        /**
         * Getter method for instance variable {@link #key}.
         *
         * @return value of instance variable {@link #key}
         */
        public String getKey()
        {
            return this.key;
        }
    }

    /**
     * Needed for serialization.
     */
    private static final long serialVersionUID = 1L;

    /**
     * Region of this ContenPane.
     */
    private final Region region;

    /**
     * Width of this ContenPane.
     */
    private String width;

    /**
     * Height of this ContenPane.
     */
    private final String height;

    /**
     * Sould a splitter be added.
     */
    private final boolean splitter;

    /** The splitter state. */
    private final String splitterState;

    /** The js executeable. */
    private boolean jsExecuteable;

    /** The layout container. */
    private boolean layoutContainer;

    /**
     * Constructor.
     *
     * @param _region region of this ContentPaneBehavior
     * @param _splitter should a splitter be rendered
     *
     */
    public ContentPaneBehavior(final Region _region,
                               final boolean _splitter)
    {
        this(_region, _splitter, null, null, null);
    }

    /**
     * Constructor.
     *
     * @param _region region of this ContentPaneBehavior
     * @param _splitter should a splitter be rendered
     * @param _width width of this ContentPaneBehavior
     * @param _height height of this ContentPaneBehavior
     * @param _splitterState the splitter state
     */
    public ContentPaneBehavior(final Region _region,
                               final boolean _splitter,
                               final String _width,
                               final String _height,
                               final String _splitterState)
    {
        super();
        this.region = _region;
        this.width = _width;
        this.height = _height;
        this.splitter = _splitter;
        this.splitterState = _splitterState;
    }

    /**
     * The tag of the related component must be set, so that a dojo
     * BorderContainer will be rendered.
     *
     * @param _component component this Behavior belongs to
     * @param _tag Tag to write to
     */
    @Override
    public void onComponentTag(final Component _component,
                               final ComponentTag _tag)
    {
        super.onComponentTag(_component, _tag);
        if (isLayoutContainer()) {
            _tag.put("data-dojo-type", "dijit/layout/LayoutContainer");
        } else {
            _tag.put("data-dojo-type", isJsExecuteable() ? "dojox/layout/ContentPane" : "dijit/layout/ContentPane");

            if (isJsExecuteable()) {
                _tag.put("scriptHasHooks", "true");
            }
        }
        if (this.region != null) {
            _tag.append("data-dojo-props", "region: '" + this.region.getKey() + "'", ",");
        }

        if (this.splitter) {
            _tag.append("data-dojo-props", "splitter: true", ",");
        }
        if (this.splitterState != null) {
            _tag.append("data-dojo-props", "toggleSplitterState: \"" + this.splitterState + "\"", ",");
        }

        if (this.width != null) {
            _tag.append("style", "width: " + this.width, ";");
        }
        if (this.height != null) {
            _tag.append("style", "height: " + this.height, ";");
        }
    }

    /**
     * Getter method for instance variable {@link #width}.
     *
     * @return value of instance variable {@link #width}
     */
    public String getWidth()
    {
        return this.width;
    }

    /**
     * Setter method for instance variable {@link #width}.
     *
     * @param _width value for instance variable {@link #width}
     * @return the content pane behavior
     */
    public ContentPaneBehavior setWidth(final String _width)
    {
        this.width = _width;
        return this;
    }

    /**
     * Render the links for the head.
     *
     * @param _component component the header will be rendered for
     * @param _response resonse to add
     */
    @Override
    public void renderHead(final Component _component,
                           final IHeaderResponse _response)
    {
        super.renderHead(_component, _response);
        _response.render(RequireHeaderItem.forClasses(
                        isJsExecuteable() ? DojoClasses.ContentPaneX : DojoClasses.ContentPane,
                                        DojoClasses.LayoutContainer, DojoClasses.parser));
    }

    /**
     * Getter method for the instance variable {@link #jsExecuteable}.
     *
     * @return value of instance variable {@link #jsExecuteable}
     */
    public boolean isJsExecuteable()
    {
        return this.jsExecuteable;
    }

    /**
     * Setter method for instance variable {@link #jsExecuteable}.
     *
     * @param _jsExecuteable value for instance variable {@link #jsExecuteable}
     * @return the content pane behavior
     */
    public ContentPaneBehavior setJsExecuteable(final boolean _jsExecuteable)
    {
        this.jsExecuteable = _jsExecuteable;
        return this;
    }

    /**
     * Getter method for the instance variable {@link #layoutContainer}.
     *
     * @return value of instance variable {@link #layoutContainer}
     */
    public boolean isLayoutContainer()
    {
        return this.layoutContainer;
    }

    /**
     * Setter method for instance variable {@link #layoutContainer}.
     *
     * @param _layoutContainer value for instance variable {@link #layoutContainer}
     * @return the content pane behavior
     */
    public ContentPaneBehavior setLayoutContainer(final boolean _layoutContainer)
    {
        this.layoutContainer = _layoutContainer;
        return this;
    }
}


/*
 * Copyright 2003 - 2017 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.
 *
 */
package org.efaps.ui.wicket.components.menu;

import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.wicket.IRequestListener;
import org.apache.wicket.ajax.AjaxEventBehavior;
import org.apache.wicket.ajax.attributes.CallbackParameter;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.MarkupStream;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.html.WebComponent;
import org.apache.wicket.markup.html.link.PopupSettings;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.util.string.StringValue;
import org.efaps.admin.ui.AbstractCommand;
import org.efaps.admin.ui.AbstractCommand.Target;
import org.efaps.ci.CIAdminUserInterface;
import org.efaps.db.Checkout;
import org.efaps.db.InstanceQuery;
import org.efaps.db.QueryBuilder;
import org.efaps.ui.wicket.components.menu.behaviors.AjaxMenuItem;
import org.efaps.ui.wicket.components.menu.behaviors.ExecBehavior;
import org.efaps.ui.wicket.components.menu.behaviors.OpenModalBehavior;
import org.efaps.ui.wicket.models.objects.PagePosition;
import org.efaps.ui.wicket.models.objects.UIForm;
import org.efaps.ui.wicket.models.objects.UIMenuItem;
import org.efaps.ui.wicket.models.objects.UIStructurBrowser;
import org.efaps.ui.wicket.models.objects.UITable;
import org.efaps.ui.wicket.models.objects.grid.UIGrid;
import org.efaps.ui.wicket.pages.connection.ConnectionPage;
import org.efaps.ui.wicket.pages.content.form.FormPage;
import org.efaps.ui.wicket.pages.content.grid.GridPage;
import org.efaps.ui.wicket.pages.content.structurbrowser.StructurBrowserPage;
import org.efaps.ui.wicket.pages.content.table.TablePage;
import org.efaps.ui.wicket.pages.dashboard.DashboardPage;
import org.efaps.ui.wicket.pages.main.MainPage;
import org.efaps.ui.wicket.resources.AbstractEFapsHeaderItem;
import org.efaps.ui.wicket.resources.EFapsContentReference;
import org.efaps.ui.wicket.util.Configuration;
import org.efaps.ui.wicket.util.Configuration.ConfigAttribute;
import org.efaps.ui.wicket.util.DojoClass;
import org.efaps.ui.wicket.util.DojoClasses;
import org.efaps.ui.wicket.util.DojoWrapper;
import org.efaps.util.EFapsException;
import org.efaps.util.RandomUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The Class SlideIn.
 *
 * @author The eFaps Team
 */
public class SlideIn
    extends WebComponent
    implements IRequestListener
{

    /** The Constant serialVersionUID. */
    private static final long serialVersionUID = 1L;
    /**
     * Logger for this class.
     */
    private static final Logger LOG = LoggerFactory.getLogger(SlideIn.class);

    /**
     * Reference to the style sheet.
     */
    private static final EFapsContentReference CSS = new EFapsContentReference(SlideIn.class, "Slide.css");

    /** The menu items. */
    private final Map<String, UIMenuItem> menuItems = new HashMap<>();

    /**
     * Instantiates a new slide in.
     *
     * @param _id the id
     * @param _model the model
     */
    public SlideIn(final String _id,
                   final IModel<UIMenuItem> _model)
    {
        super(_id, _model);
    }

    /**
     * Render to the web response the eFapsContentReference.
     *
     * @param _response Response object
     */@Override
    public void renderHead(final IHeaderResponse _response)
    {
        super.renderHead(_response);
        _response.render(AbstractEFapsHeaderItem.forCss(SlideIn.CSS));
    }

    @Override
    public void onComponentTagBody(final MarkupStream _markupStream,
                                   final ComponentTag _openTag)
    {
        final UIMenuItem menuItem = (UIMenuItem) getDefaultModelObject();

        final Set<DojoClass> dojoClasses = new HashSet<>();
        Collections.addAll(dojoClasses, DojoClasses.aspect, DojoClasses.ready, DojoClasses.registry,
                        DojoClasses.domConstruct, DojoClasses.dom, DojoClasses.fx, DojoClasses.basefx, DojoClasses.on,
                        DojoClasses.domStyle, DojoClasses.domGeom, DojoClasses.query, DojoClasses.NodeListDom,
                        DojoClasses.NodeListFx, DojoClasses.domClass);

        final StringBuilder js = new StringBuilder()
                        .append("var sn = dom.byId('slidein');\n");

        for (final UIMenuItem childItem : menuItem.getChildren()) {
            js.append(getMenuItem(childItem));
        }

        js.append("on(dom.byId(\"slideinCollapse\"), \"click\", function(evt) {\n")
            .append("var anim;\n")
            .append("if (domGeom.getContentBox(evt.currentTarget.parentNode).w > 100) {\n")
            .append(" domClass.replace(evt.currentTarget.parentNode, \"expand\", \"collapse\"); \n")
            .append(" anim = fx.combine([\n")
            .append(" baseFx.animateProperty({\n")
            .append("node: \"slideinPane\",\n")
            .append(" properties: {\n")
            .append(" width: 56\n")
            .append("}\n")
            .append("}),\n")
            .append("baseFx.animateProperty({\n")
            .append(" node: \"slideinPane_splitter\",\n")
            .append(" properties: {\n")
            .append("left: 40\n")
            .append("}\n")
            .append("}),\n")
            .append("baseFx.animateProperty({\n")
            .append(" node: \"mainPanel\",\n")
            .append("properties: {\n")
            .append("left: 60,\n")
            .append(" width:1780\n")
            .append("}\n")
            .append("})\n")
            .append("]);\n")
            .append("} else {\n")
            .append(" domClass.replace(evt.currentTarget.parentNode, \"collapse\", \"expand\"); \n")
            .append("anim = fx.combine([\n")
            .append("baseFx.animateProperty({\n")
            .append("node: \"slideinPane\",\n")
            .append(" properties: {\n")
            .append(" width: 200\n")
            .append("}\n")
            .append("}),\n")
            .append("baseFx.animateProperty({\n")
            .append("node: \"slideinPane_splitter\",\n")
            .append("properties: {\n")
            .append("left: 40\n")
            .append(" }\n")
            .append("}),\n")
            .append("baseFx.animateProperty({\n")
            .append("node: \"mainPanel\",\n")
            .append("properties: {\n")
            .append("left: 220\n")
            .append("}\n")
            .append("})\n")
            .append("]);\n")
            .append("}\n")
            .append("aspect.after(anim, \"onEnd\", function(){\n")
            .append("registry.byId(\"borderPanel\").resize();\n")
            .append("});\n")
            .append("anim.play();\n")
            .append("});\n");

        final StringBuilder html = new StringBuilder().append("<script type=\"text/javascript\">")
                        .append(DojoWrapper.require(js, dojoClasses.toArray(new DojoClass[dojoClasses.size()])))
                        .append("\n</script>");

        replaceComponentTagBody(_markupStream, _openTag, html);
    }

    /**
     * Gets the menu item.
     *
     * @param _menuItem the menu item
     * @return the menu item
     */
    private CharSequence getMenuItem(final UIMenuItem _menuItem)
    {
        final StringBuilder js = new StringBuilder();

        final String node1 = RandomUtil.randomAlphabetic(4);
        final String node2 = RandomUtil.randomAlphabetic(4);

        js.append("var ").append(node1).append(" = domConstruct.create(\"div\", { class: \"menueentry\"}, sn);\n")
            .append("var ").append(node2).append(" = domConstruct.create(\"div\", { class: \"title");
        if (!_menuItem.getChildren().isEmpty()) {
            js.append(" closed");
        }
        js.append("\"},").append(node1).append(");\n")
            .append(getImage(_menuItem, node2))
            .append("domConstruct.create(\"span\", { class: \"menutitle\", innerHTML: \"")
            .append(StringEscapeUtils.escapeEcmaScript(StringEscapeUtils.escapeHtml4(_menuItem.getLabel())))
            .append("\"} , ").append(node2).append("); \n")
            .append(getSubMenuItem(_menuItem, node1, node2));
        return js;
    }

    /**
     * Gets the sub menu item.
     *
     * @param _menuItem the menu item
     * @param _parentNode the parent node
     * @param _titleNode the title node
     * @return the sub menu item
     */
    private CharSequence getSubMenuItem(final UIMenuItem _menuItem,
                                        final String _parentNode,
                                        final String _titleNode)
    {
        final StringBuilder js = new StringBuilder();
        final String node1 = RandomUtil.randomAlphabetic(4);

        if (_menuItem.getChildren().isEmpty()) {
            js.append(" on(").append(_titleNode).append(", \"click\", function(evt) {\n")
                .append(getEventJs(_menuItem))
                .append("});\n");
        } else {
            js.append("var ").append(node1).append(" = domConstruct.create(\"div\",")
                .append("{ class: \"nested\", style: \"display:none\"}, ")
                .append(_parentNode).append(");\n")
                .append(" on(").append(_titleNode).append(", \"click\", function(evt) {\n")
                .append("if (domStyle.get(").append(node1).append(", \"display\") !== \"none\") {\n")
                .append(" domClass.replace(evt.currentTarget, \"closed\", \"open\"); \n")
                .append("fx.wipeOut({\n")
                .append("node: ").append(node1).append("\n")
                .append("}).play();\n")
                .append("} else {\n")
                .append(" domClass.replace(evt.currentTarget, \"open\", \"closed\"); \n")
                .append("fx.wipeIn({\n")
                .append("node: ").append(node1).append("\n")
                .append("}).play();\n")
                .append("}\n")
                .append("});\n");
        }
        for (final UIMenuItem childItem : _menuItem.getChildren()) {
            final String node2 = RandomUtil.randomAlphabetic(4);
            final String node3 = RandomUtil.randomAlphabetic(4);
            js.append("var ").append(node2).append(" = domConstruct.create(\"div\",")
                .append("{ class: \"menueentry\"}, ").append(node1).append(");\n")
                .append("var ").append(node3).append(" = domConstruct.create(\"div\", { class: \"title");
            if (!childItem.getChildren().isEmpty()) {
                js.append(" closed");
            }
            js.append("\"},").append(node2).append(");\n")
                .append(getImage(childItem, node3))
                .append("domConstruct.create(\"span\", { class: \"menutitle\", innerHTML: \"")
                .append(StringEscapeUtils.escapeEcmaScript(StringEscapeUtils.escapeHtml4(childItem.getLabel())))
                .append("\"} , ").append(node3).append("); \n")
                .append(getSubMenuItem(childItem, node2, node3));
        }
        return js;
    }

    /**
     * Gets the url.
     *
     * @param _menuItem the menu item
     * @return the url
     */
    private CharSequence getEventJs(final UIMenuItem _menuItem)
    {
        final String key = RandomUtil.randomAlphabetic(8);
        this.menuItems.put(key, _menuItem);
        final StringBuilder ret = new StringBuilder();
        switch (_menuItem.getTarget()) {
            case HIDDEN:
                ret.append(getBehavior(ExecBehavior.class).getCallbackFunctionBody(CallbackParameter.converted("m",
                                "\"" + key + "\"")));
                break;
            case MODAL:
                ret.append(getBehavior(OpenModalBehavior.class).getCallbackFunctionBody(CallbackParameter.converted("m",
                                "\"" + key + "\"")));
                break;
            case POPUP:
                final PageParameters popupPageParameters = new PageParameters();
                popupPageParameters.add("m", key);
                final PopupSettings popupSettings = new PopupSettings();
                popupSettings.setHeight(_menuItem.getWindowHeight());
                popupSettings.setWidth(_menuItem.getWindowWidth());
                popupSettings.setTarget("'" + urlForListener(popupPageParameters) + "'");
                popupSettings.setWindowName("eFapsPopup");
                ret.append("(function () {").append(popupSettings.getPopupJavaScript()).append("}) ();");
                break;
            default:
                final PageParameters pageParameters = new PageParameters();
                pageParameters.add("m", key);
                ret.append("registry.byId(\"").append("mainPanel").append(
                                "\").set(\"content\", domConstruct.create(\"iframe\", {").append("\"id\": \"")
                        .append(MainPage.IFRAME_ID).append("\",\"src\": \"").append(urlForListener(pageParameters))
                        .append("\",\"style\": \"border: 0; width: 100%; height: 99%\"").append(",\"id\": \"")
                        .append(MainPage.IFRAME_ID).append("\"").append("}));");
                break;
        }
        return ret;
    }

    /**
     * Gets the image.
     *
     * @param _menuItem the menu item
     * @param _node the node
     * @return the image
     */
    private CharSequence getImage(final UIMenuItem _menuItem,
                                  final String _node)
    {
        final String label = _menuItem.getLabel();
        String content = "";
        if (StringUtils.isNotEmpty(label)) {
            content = StringUtils.left(label, 1).toUpperCase();
        }
        final StringBuilder js = new StringBuilder();
        if (StringUtils.isNotEmpty(_menuItem.getImage()) && _menuItem.getImage().endsWith(".svg")) {
            try {
                final QueryBuilder querBldr = new QueryBuilder(CIAdminUserInterface.Image);
                querBldr.addWhereAttrEqValue(CIAdminUserInterface.Image.Name, _menuItem.getImage());
                final InstanceQuery query = querBldr.getQuery();
                query.execute();
                if (query.next()) {
                    final Checkout checkout = new Checkout(query.getCurrentValue());
                    final ByteArrayOutputStream os = new ByteArrayOutputStream();
                    checkout.execute(os);
                    final String svg = new String(os.toByteArray(), StandardCharsets.UTF_8);
                    js.append("domConstruct.create(\"span\", {\n")
                        .append("innerHTML: \"").append(StringEscapeUtils.escapeEcmaScript(svg)).append("\"\n")
                        .append("}, ").append(_node).append(");\n");
                }
            } catch (final EFapsException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } else {
            js.append("domConstruct.create(\"span\", {\n")
                .append("class: \"circle ").append(content).append(" \"\n,")
                .append("innerHTML: \"").append(content).append("\"\n")
                .append("}, ").append(_node).append(");\n");
        }
        return js;
    }

    /**
     * Gets the behavior.
     *
     * @param _class the class
     * @return the behavior
     */
    protected AjaxEventBehavior getBehavior(final Class<? extends Behavior> _class)
    {
        final SlideInPanel panel = (SlideInPanel) getParent();
        return panel.visitChildren(AjaxMenuItem.class, (_item,
         _visit) -> {
            final List<? extends Behavior> behaviors = _item.getBehaviors(_class);
            if (CollectionUtils.isNotEmpty(behaviors)) {
                _visit.stop((AjaxEventBehavior) behaviors.get(0));
            } else {
                _visit.stop();
            }
        });
    }

    @Override
    public void onRequest()
    {
        final StringValue key = getRequestCycle().getRequest().getQueryParameters().getParameterValue("m");
        final UIMenuItem menuItem = this.menuItems.get(key.toString());
        try {
            if (StringUtils.endsWith(menuItem.getReference(), "/home")) {
                setResponsePage(new DashboardPage(getPage().getPageReference()));
            } else if (StringUtils.endsWith(menuItem.getReference(), "/connection")) {
                setResponsePage(new ConnectionPage(getPage().getPageReference()));
            } else {
                final AbstractCommand command = menuItem.getCommand();
                final PagePosition pagePosition = Target.POPUP.equals(menuItem.getTarget())
                                ? PagePosition.POPUP : PagePosition.CONTENT;
                if (command.getTargetTable() != null) {
                    if (command.getTargetStructurBrowserField() != null) {
                        final StructurBrowserPage page = new StructurBrowserPage(Model.of(new UIStructurBrowser(menuItem
                                        .getCommandUUID(), menuItem.getInstanceKey()).setPagePosition(pagePosition)));
                        setResponsePage(page);
                    } else {
                        if ("GridX".equals(Configuration.getAttribute(ConfigAttribute.TABLE_DEFAULTTYPECONTENT))) {
                            final GridPage page = new GridPage(Model.of(UIGrid.get(command.getUUID(), pagePosition)));
                            setResponsePage(page);
                        } else {
                            final TablePage page = new TablePage(Model.of(new UITable(menuItem.getCommandUUID(),
                                            menuItem.getInstanceKey()).setPagePosition(pagePosition)));
                            setResponsePage(page);
                        }
                    }
                } else if (command.getTargetForm() != null  || command.getTargetSearch() != null) {
                    final UIForm uiForm = new UIForm(menuItem.getCommandUUID(), menuItem.getInstanceKey())
                                    .setPagePosition(pagePosition);
                    final FormPage page = new FormPage(Model.of(uiForm));
                    setResponsePage(page);
                }
            }
        } catch (final EFapsException e) {
            SlideIn.LOG.error("Catched", e);
        }
    }

    /**
     * Getter method for the instance variable {@link #menuItems}.
     *
     * @return value of instance variable {@link #menuItems}
     */
    public Map<String, UIMenuItem> getMenuItems()
    {
        return this.menuItems;
    }
}


/*
 * Copyright 2003 - 2019 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.
 *
 */

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

import java.util.UUID;

import org.efaps.admin.AbstractAdminObject;
import org.efaps.admin.ui.Table;
import org.efaps.admin.ui.field.FieldTable;
import org.efaps.db.Instance;
import org.efaps.ui.wicket.models.objects.IFormElement;
import org.efaps.ui.wicket.models.objects.PagePosition;
import org.efaps.util.cache.CacheReloadException;

/**
 * The Class UIFieldGrid.
 *
 * @author The eFaps Team
 */
public final class UIFieldGrid
    extends UIGrid
    implements IFormElement
{

    /** The Constant serialVersionUID. */
    private static final long serialVersionUID = 1L;

    /** The field id. */
    private long fieldId;

    /**
     * Instantiates a new UI field grid.
     */
    private UIFieldGrid()
    {
    }

    /**
     * Gets the.
     *
     * @param _commandUUID the command UUID
     * @param _pagePosition the page position
     * @param _callInstance the call instance
     * @param _fieldTable the field table
     * @return the UI grid
     */
    public static UIFieldGrid get(final UUID _commandUUID,
                                  final PagePosition _pagePosition,
                                  final Instance _callInstance,
                                  final FieldTable _fieldTable)
    {
        final UIFieldGrid ret = new UIFieldGrid();
        ret.setFieldId(_fieldTable.getId()).setCmdUUID(_commandUUID).setPagePosition(_pagePosition).setCallInstance(
                        _callInstance);
        return ret;
    }

    /**
     * Getter method for the instance variable {@link #fieldId}.
     *
     * @return value of instance variable {@link #fieldId}
     */
    public long getFieldId()
    {
        return this.fieldId;
    }

    /**
     * Getter method for the instance variable {@link #fieldId}.
     *
     * @return value of instance variable {@link #fieldId}
     */
    public FieldTable getFieldTable()
    {
        return FieldTable.get(this.fieldId);
    }

    /**
     * Setter method for instance variable {@link #fieldId}.
     *
     * @param _fieldId value for instance variable {@link #fieldId}
     * @return the UI field grid
     */
    public UIFieldGrid setFieldId(final long _fieldId)
    {
        this.fieldId = _fieldId;
        return this;
    }

    @Override
    public Table getTable()
        throws CacheReloadException
    {
        return getFieldTable().getTargetTable();
    }

    @Override
    public String getCacheKey(final CacheKey _key)
    {
        return getCmdUUID() + "-" + getFieldTable().getName() + "-" + _key.getValue();
    }

    @Override
    public AbstractAdminObject getEventObject()
        throws CacheReloadException
    {
        return getFieldTable();
    }

    @Override
    public boolean isStructureTree()
        throws CacheReloadException
    {
        return getFieldTable().getTargetStructurBrowserField() != null;
    }

    @Override
    public String getStructurBrowserField()
        throws CacheReloadException
    {
        return getFieldTable().getTargetStructurBrowserField();
    }

    @Override
    public boolean isShowCheckBoxes()
        throws CacheReloadException
    {
        return getFieldTable().isTargetShowCheckBoxes();
    }

    @Override
    public String getMarkupId()
    {
        return "grid_" + getFieldTable().getName();
    }
}


/*
 * Copyright 2003 - 2016 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.
 *
 */

package org.efaps.ui.wicket.components.modalwindow;

import org.apache.wicket.Page;
import org.apache.wicket.PageReference;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
import org.apache.wicket.core.request.handler.PageProvider;
import org.apache.wicket.core.request.handler.RenderPageRequestHandler;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.mock.MockHomePage;
import org.apache.wicket.model.Model;
import org.apache.wicket.protocol.http.request.WebClientInfo;
import org.apache.wicket.request.IRequestHandler;
import org.efaps.admin.ui.Menu;
import org.efaps.ui.wicket.components.menutree.MenuUpdateBehavior;
import org.efaps.ui.wicket.models.objects.AbstractUIPageObject;
import org.efaps.ui.wicket.models.objects.ICmdUIObject;
import org.efaps.ui.wicket.models.objects.IPageObject;
import org.efaps.ui.wicket.models.objects.UIForm;
import org.efaps.ui.wicket.models.objects.UIStructurBrowser;
import org.efaps.ui.wicket.models.objects.UITable;
import org.efaps.ui.wicket.models.objects.grid.UIGrid;
import org.efaps.ui.wicket.pages.AbstractMergePage;
import org.efaps.ui.wicket.pages.content.AbstractContentPage;
import org.efaps.ui.wicket.pages.content.form.FormPage;
import org.efaps.ui.wicket.pages.content.grid.GridPage;
import org.efaps.ui.wicket.pages.content.structurbrowser.StructurBrowserPage;
import org.efaps.ui.wicket.pages.content.table.TablePage;
import org.efaps.ui.wicket.pages.contentcontainer.ContentContainerPage;
import org.efaps.ui.wicket.pages.dashboard.DashboardPage;
import org.efaps.ui.wicket.pages.error.ErrorPage;
import org.efaps.ui.wicket.pages.error.UnexpectedErrorPage;
import org.efaps.ui.wicket.pages.main.MainPage;
import org.efaps.ui.wicket.util.DojoClasses;
import org.efaps.ui.wicket.util.DojoWrapper;
import org.efaps.util.EFapsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This is a wrapper class for a modal window.
 *
 * @author The eFaps Team
 */
public class ModalWindowContainer
    extends AbstractModalWindow
{
    /**
     * Needed for serialization.
     */
    private static final long serialVersionUID = 1L;

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

    /**
     * Stores if the child mut be reloaded.
     */
    private boolean reloadChild = false;

    /**
     * Stores if the parent must be updated on close.
     */
    private boolean updateParent = false;

    /**
     * Show a file on close.
     */
    private boolean targetShowFile = false;

    /**
     * Constructor.
     *
     * @param _wicketId wicket id of this component
     */
    public ModalWindowContainer(final String _wicketId)
    {
        super(_wicketId);
    }

    /**
     * This is the getter method for the instance variable {@link #reloadChild}.
     *
     * @return value of instance variable {@link #reloadChild}
     */

    public boolean isReloadChild()
    {
        return this.reloadChild;
    }

    /**
     * This is the setter method for the instance variable {@link #reloadChild}.
     *
     * @param _reloadchild the reloadParent to set
     */
    public void setReloadChild(final boolean _reloadchild)
    {
        this.reloadChild = _reloadchild;
    }

    /**
     * @param _target AjaxRequestTarget
     * @param _uiObject uiObject of the page that was opened in the current modal
     */
    public void close(final AjaxRequestTarget _target,
                      final ICmdUIObject _uiObject)
    {
        super.close(_target);
        closeInternal(_target, _uiObject);
    }

    /**
     * Method is called when the modal window is closed.
     *
     * @param _target AjaxRequestTarget
     */
    @Override
    public void close(final IPartialPageRequestHandler _target)
    {
        super.close(_target);
        closeInternal(_target, null);
    }

    /**
     * @param _target AjaxRequestTarget
     * @param _uiObject uiObject of the page that was opened in the current modal
     */
    private void closeInternal(final IPartialPageRequestHandler _target,
                               final ICmdUIObject _uiObject)
    {
        if (this.targetShowFile) {
            ((AbstractMergePage) getPage()).getDownloadBehavior().initiate(_target);
        }
        if (this.reloadChild) {
            _target.prependJavaScript(getReloadJavaScript(_uiObject));
        }
    }

    /**
     * Method creates a JavaScript to reload the parent page.
     *
     * @param _uiObject uiObject of the page that was opened in the current modal
     * @return JavaScript
     * @throws EFapsException
     */
    public CharSequence getReloadJavaScript(final ICmdUIObject _uiObject)
    {
        final StringBuilder javascript = new StringBuilder();
        if (_uiObject instanceof IPageObject) {
            try {
                final Page page;
                final Object modelObject = getPage().getDefaultModelObject();
                if (modelObject instanceof UIGrid) {
                    final UIGrid uiGrid = (UIGrid) modelObject;
                    page = new GridPage(Model.of(UIGrid.get(uiGrid.getCmdUUID(), uiGrid.getPagePosition())
                                    .setCallInstance(uiGrid.getCallInstance())));
                } else if (modelObject instanceof UIForm) {
                    final UIForm uiForm = (UIForm) modelObject;
                    uiForm.resetModel();
                    page = new FormPage(Model.of(uiForm));
                } else if (modelObject instanceof UITable) {
                    final UITable uiTable = (UITable) modelObject;
                    uiTable.resetModel();
                    page = new TablePage(Model.of(uiTable));
                } else if (modelObject instanceof UIStructurBrowser) {
                    final UIStructurBrowser uiStrBrws = (UIStructurBrowser) modelObject;
                    uiStrBrws.resetModel();
                    page = new StructurBrowserPage(Model.of(uiStrBrws));
                } else {
                    ModalWindowContainer.LOG.error("NO PAGE");
                    page = new UnexpectedErrorPage();
                }

                final IRequestHandler handler = new RenderPageRequestHandler(new PageProvider(page));
                final String url = getRequestCycle().urlFor(handler).toString();

                switch (((IPageObject) _uiObject).getPagePosition()) {
                    case TREE:
                    case TREEMODAL:
                        javascript
                            .append("var mF = top.dojo.doc.getElementById(\"").append(MainPage.IFRAME_ID)
                                .append("\");\n")
                            .append("if (mF != null) {\n")
                            .append("mF.contentWindow.dojo.query('.dijitContentPane.eFapsCenterPanel')")
                                .append(".forEach(function(_p){\n")
                            .append("var d = mF.contentWindow.dijit.registry.byNode(_p);\n")
                            .append("d.set('content', domConstruct.create('iframe', {\n")
                            .append("\"src\": \"").append(url)
                            .append("\",\"style\": \"border: 0; width: 100%; height: 99%\"}")
                            .append("));\n")
                            .append("});\n")
                            .append("mF.contentWindow.").append(MenuUpdateBehavior.FUNCTION_NAME).append("(\"")
                            .append(MenuUpdateBehavior.PARAMETERKEY4UPDATE).append("\");\n")
                            .append("}");
                        break;
                    case CONTENT:
                    case CONTENTMODAL:
                    default:
                        javascript.append(" top.dijit.registry.byId(\"mainPanel\").set(\"content\",")
                            .append(" domConstruct.create(\"iframe\",{")
                            .append("\"id\": \"").append(MainPage.IFRAME_ID)
                            .append("\",\"src\": \"./wicket/").append(url)
                            .append("\",\"style\": \"border: 0; width: 100%; height: 99%\" }")
                            .append("))");
                }
            } catch (final EFapsException e) {
                throw new RestartResponseException(new ErrorPage(e));
            }
        } else {
            final AbstractUIPageObject uiObject = (AbstractUIPageObject) getPage().getDefaultModelObject();

            if (uiObject != null) {
                try {
                    PageReference calledByPageRef = ((AbstractContentPage) getPage()).getCalledByPageReference();
                    if (calledByPageRef != null && calledByPageRef.getPage() instanceof AbstractContentPage) {
                        calledByPageRef = ((AbstractContentPage) calledByPageRef.getPage()).getCalledByPageReference();
                    }
                    final String href = _uiObject.getCommand() == null ? null : _uiObject.getCommand().getReference();
                    final Page page;
                    boolean tree = false;
                    if ("TREE?".equalsIgnoreCase(href) && _uiObject.getInstance() != null
                                    && _uiObject.getInstance().isValid()) {
                        final Menu menu = Menu.getTypeTreeMenu(_uiObject.getInstance().getType());
                        if (menu == null) {
                            final Exception ex = new Exception("no tree menu defined for type "
                                            + _uiObject.getInstance().getType().getName());
                            throw new RestartResponseException(new ErrorPage(ex));
                        }
                        page = new ContentContainerPage(menu.getUUID(), _uiObject.getInstance().getKey());
                        tree = true;
                    } else {
                        uiObject.resetModel();
                        if (uiObject instanceof UITable) {
                            page = new TablePage(Model.of((UITable) uiObject), calledByPageRef);
                        } else if (uiObject instanceof UIForm) {
                            page = new FormPage(Model.of((UIForm) uiObject), calledByPageRef);
                        } else if (uiObject instanceof UIStructurBrowser) {
                            page = new StructurBrowserPage(Model.of((UIStructurBrowser) uiObject), calledByPageRef);
                        } else {
                            page = new MockHomePage();
                        }
                    }
                    final IRequestHandler handler = new RenderPageRequestHandler(new PageProvider(page));
                    // touch the page to ensure that the pagemanager stores it to be accessible
                    getSession().getPageManager().touchPage(page);
                    final String url = getRequestCycle().urlFor(handler).toString();
                    if (calledByPageRef != null && calledByPageRef.getPage() instanceof ContentContainerPage && !tree) {
                        final String panelId = ((ContentContainerPage) calledByPageRef.getPage()).getCenterPanelId();
                        javascript
                            .append("var mF = top.dojo.doc.getElementById(\"").append(MainPage.IFRAME_ID).append("\");")
                            .append("if (mF != null) {")
                            .append("mF.contentWindow.dijit.registry.byId(\"").append(panelId)
                            .append("\").set(\"content\",")
                                .append(" domConstruct.create(\"iframe\", {")
                                    .append("\"src\": \"").append(url)
                                    .append("\",\"style\": \"border: 0; width: 100%; height: 99%\"}")
                                .append(")); ")
                            .append("mF.contentWindow.").append(MenuUpdateBehavior.FUNCTION_NAME).append("(\"")
                            .append(MenuUpdateBehavior.PARAMETERKEY4UPDATE).append("\");")
                            .append("}");
                    } else {
                        javascript
                            .append(" top.dijit.registry.byId(\"mainPanel\").set(\"content\",")
                                .append(" domConstruct.create(\"iframe\",{")
                                    .append("\"id\": \"").append(MainPage.IFRAME_ID)
                                    .append("\",\"src\": \"./wicket/").append(url)
                                    .append("\",\"style\": \"border: 0; width: 100%; height: 99%\" }")
                                 .append("))");
                    }
                } catch (final EFapsException e) {
                    throw new RestartResponseException(new ErrorPage(e));
                }
            } else if (getPage() instanceof MainPage) {
                try {
                    // this was called by the DashBoard
                    final DashboardPage page = new DashboardPage(getPage().getPageReference());
                    final IRequestHandler handler = new RenderPageRequestHandler(new PageProvider(page));
                    // touch the page to ensure that the pagemanager stores it to be accessible
                    getSession().getPageManager().touchPage(page);
                    final String url = getRequestCycle().urlFor(handler).toString();
                    javascript
                        .append(" top.dijit.registry.byId(\"mainPanel\").set(\"content\",")
                            .append(" domConstruct.create(\"iframe\",{")
                                .append("\"id\": \"").append(MainPage.IFRAME_ID)
                                .append("\",\"src\": \"./wicket/").append(url)
                                .append("\",\"style\": \"border: 0; width: 100%; height: 99%\" }")
                             .append("))");
                } catch (final EFapsException e) {
                    throw new RestartResponseException(new ErrorPage(e));
                }
            }
        }
        return DojoWrapper.require(javascript, DojoClasses.domConstruct);
    }

    /**
     * This is the getter method for the instance variable {@link #updateParent}
     * .
     *
     * @return value of instance variable {@link #updateParent}
     */

    public boolean isUpdateParent()
    {
        return this.updateParent;
    }

    /**
     * This is the setter method for the instance variable {@link #updateParent}
     * .
     *
     * @param _updateParent the updateParent to set
     */
    public void setUpdateParent(final boolean _updateParent)
    {
        this.updateParent = _updateParent;
    }

    /**
     * This method sets this ModalWindowContainer into the state like it was
     * just created. It uses the default values as they are defined in
     * <code>org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow
     * </code>
     */
    public void reset()
    {
        super.setMinimalWidth(200);
        super.setMinimalHeight(200);
        super.setInitialHeight(400);
        super.setInitialWidth(600);
        super.setUseInitialHeight(true);
        super.setResizable(true);
        super.setHeightUnit("px");
        super.setWidthUnit("px");
        super.setPageCreator(null);
        super.setCloseButtonCallback(null);
        super.setWindowClosedCallback(null);
    }

    /**
     * This method is a exact copy of the private method getCloseJavacript() in
     * {@link #org.efaps.ui.wicket.components.modalwindow.ModalWindow}, but it has to be public.
     *
     * @return JavaScript
     */
    @Override
    public String getCloseJavacript()
    {
        return ModalWindowContainer.getCloseJavacriptInternal();
    }

    /**
     * Just a copy to be able to add the "top" .
     * @return the close script
     */
    private static String getCloseJavacriptInternal()
    {
        return "var win;\n" //
            + "try {\n"
            + " win = top.window.parent.Wicket.Window;\n"
            + "} catch (ignore) {\n"
            + "}\n"
            + "if (typeof(win) == \"undefined\" || typeof(win.current) == \"undefined\") {\n"
            + "  try {\n"
            + "     win = window.Wicket.Window;\n"
            + "  } catch (ignore) {\n"
            + "  }\n"
            + "}\n"
            + "if (typeof(win) != \"undefined\" && typeof(win.current) != \"undefined\") {\n"
            + " var close = function(w) { w.setTimeout(function() {\n"
            + "     win.current.close();\n"
            + " }, 0);  } \n"
            + " try { close(window.parent); } catch (ignore) { close(window); };\n" + "}";
    }

    @Override
    protected CharSequence getShowJavaScript()
    {
        return "top.Wicket.Window.create(settings).show();\n";
    }

    /**
     * Check it the size of the modal window is not to big and reduces it if
     * necessary.
     *
     * @see org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow#setInitialHeight(int)
     * @param _initialHeight height
     * @return this Modalwindow
     */
    @Override
    public ModalWindow setInitialHeight(final int _initialHeight)
    {
        int height = _initialHeight;
        final WebClientInfo wcInfo = (WebClientInfo) getSession().getClientInfo();
        if (wcInfo.getProperties().getBrowserHeight() > 0 && wcInfo.getProperties().getBrowserHeight() < height) {
            height = wcInfo.getProperties().getBrowserHeight() - 33;
        }
        return super.setInitialHeight(height);
    }

    /**
     * Check it the size of the modal window is not to big and reduces it if
     * necessary.
     *
     * @see org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow#setInitialWidth(int)
     * @param _initialWidth width
     * @return this Modalwindow
     */
    @Override
    public ModalWindow setInitialWidth(final int _initialWidth)
    {
        int width = _initialWidth;
        final WebClientInfo wcInfo = (WebClientInfo) getSession().getClientInfo();
        if (wcInfo.getProperties().getBrowserWidth() > 0 && wcInfo.getProperties().getBrowserWidth() < _initialWidth) {
            width = wcInfo.getProperties().getBrowserWidth();
        }
        return super.setInitialWidth(width);
    }

    /**
     * @param _targetShowFile show a file
     */
    public void setTargetShowFile(final boolean _targetShowFile)
    {
        this.targetShowFile = _targetShowFile;
    }
}