/*
 * 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.io.File;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.collections4.map.LinkedMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.wicket.RestartResponseException;
import org.efaps.admin.AbstractAdminObject;
import org.efaps.admin.datamodel.Attribute;
import org.efaps.admin.datamodel.Type;
import org.efaps.admin.datamodel.ui.DateTimeUI;
import org.efaps.admin.datamodel.ui.DateUI;
import org.efaps.admin.datamodel.ui.IUIProvider;
import org.efaps.admin.datamodel.ui.UIValue;
import org.efaps.admin.dbproperty.DBProperties;
import org.efaps.admin.event.EventDefinition;
import org.efaps.admin.event.EventExecution;
import org.efaps.admin.event.EventType;
import org.efaps.admin.event.Parameter;
import org.efaps.admin.event.Parameter.ParameterValues;
import org.efaps.admin.event.Return;
import org.efaps.admin.event.Return.ReturnValues;
import org.efaps.admin.program.esjp.EFapsClassLoader;
import org.efaps.admin.ui.AbstractCommand;
import org.efaps.admin.ui.AbstractUserInterfaceObject.TargetMode;
import org.efaps.admin.ui.Command;
import org.efaps.admin.ui.Menu;
import org.efaps.admin.ui.Table;
import org.efaps.admin.ui.field.Field;
import org.efaps.admin.user.Role;
import org.efaps.api.ci.UITableFieldProperty;
import org.efaps.api.ui.FilterBase;
import org.efaps.api.ui.IFilter;
import org.efaps.beans.ValueList;
import org.efaps.beans.valueparser.ParseException;
import org.efaps.beans.valueparser.ValueParser;
import org.efaps.db.AbstractPrintQuery;
import org.efaps.db.Context;
import org.efaps.db.Instance;
import org.efaps.db.MultiPrintQuery;
import org.efaps.db.PrintQuery;
import org.efaps.db.SelectBuilder;
import org.efaps.db.stmt.PrintStmt;
import org.efaps.db.stmt.selection.Evaluator;
import org.efaps.eql2.EQL2;
import org.efaps.eql2.IPrintStatement;
import org.efaps.ui.wicket.models.field.FieldConfiguration;
import org.efaps.ui.wicket.models.field.JSField;
import org.efaps.ui.wicket.models.field.factories.BooleanUIFactory;
import org.efaps.ui.wicket.models.field.factories.DateTimeUIFactory;
import org.efaps.ui.wicket.models.field.factories.DateUIFactory;
import org.efaps.ui.wicket.models.field.factories.DecimalUIFactory;
import org.efaps.ui.wicket.models.field.factories.IComponentFactory;
import org.efaps.ui.wicket.models.field.factories.NumberUIFactory;
import org.efaps.ui.wicket.models.objects.AbstractUI;
import org.efaps.ui.wicket.models.objects.ICmdUIObject;
import org.efaps.ui.wicket.models.objects.IPageObject;
import org.efaps.ui.wicket.models.objects.IWizardElement;
import org.efaps.ui.wicket.models.objects.PagePosition;
import org.efaps.ui.wicket.models.objects.UIWizardObject;
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;

/**
 * The Class UIGrid.
 *
 * @author The eFaps Team
 */
public class UIGrid
    extends AbstractUI
    implements IPageObject, IWizardElement, ICmdUIObject
{

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

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

    /** The cmd UUID. */
    private UUID cmdUUID;

    /** The initialized. */
    private boolean initialized;

    /** The columns. */
    private final List<GridColumn> columns = new ArrayList<>();

    /** The values. */
    private final List<GridRow> values = new ArrayList<>();

    /** The filter list. */
    private final FilterList filterList = new FilterList();

    /** The call instance. */
    private Instance callInstance;

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

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

    /** The show check boxes. */
    private Boolean showCheckBoxes;

    /** The columns up to date. */
    private boolean columnsUpToDate;

    /**
     * Instantiates a new UI grid.
     *
     * @throws EFapsException the e faps exception
     */
    protected UIGrid()
    {
    }

    /**
     * Inits the.
     *
     * @throws EFapsException the e faps exception
     */
    private void init()
        throws EFapsException
    {
        if (!this.initialized) {
            this.initialized = true;
            final List<Field> fields = getTable().getFields();

            boolean check4Filter = true;
            if (Context.getThreadContext().containsSessionAttribute(getCacheKey(CacheKey.DBFILTER))) {
                check4Filter = false;
                final FilterList tmpFilterList = (FilterList) Context.getThreadContext().getSessionAttribute(
                                getCacheKey(CacheKey.DBFILTER));
                for (final IFilter filter : tmpFilterList) {
                    this.filterList.add(filter);
                }
            }

            for (final Field field : fields) {
                if (field.hasAccess(TargetMode.VIEW, null, getCommand(), null) && !field.isNoneDisplay(
                                TargetMode.VIEW)) {
                    final GridColumn column = new GridColumn().setFieldConfig(new FieldConfiguration(field.getId()));
                    this.columns.add(column);
                    // before executing the esjp add the filters that are
                    // working against the database to
                    // get them filled with the defaults
                    if (check4Filter && FilterBase.DATABASE.equals(field.getFilter().getBase())) {
                        this.filterList.add(getFilter4Field(column.getField()));
                    }
                }
            }
            if (isStructureTree()) {
                load(getPrint(getMainQueryStmt()), Collections.emptyMap());
            } else {
                final List<Instance> instances = getInstances();
                setColumnsUpToDate(CollectionUtils.isNotEmpty(instances));
                load(instances);
            }
        }
    }

    protected String getMainQueryStmt()
        throws EFapsException
    {
        final List<Return> returns = getEventObject().executeEvents(EventType.UI_TABLE_EVALUATE,
                        ParameterValues.INSTANCE, getCallInstance(),
                        ParameterValues.CALL_INSTANCE, getCallInstance(),
                        ParameterValues.PARAMETERS, Context.getThreadContext().getParameters(),
                        ParameterValues.CLASS, this,
                        ParameterValues.OTHERS, this.filterList);
        String ret = null;
        if (returns.size() < 1) {
            throw new EFapsException(UIGrid.class, "getInstanceList");
        } else {
            final Object result = returns.get(0).get(ReturnValues.VALUES);
            if (result instanceof String) {
                ret =  (String) result;
            }
        }
        return ret;
    }

    protected String getChildQueryStmt(final Collection<Instance> _instances)
        throws EFapsException
    {
        final List<Return> returns = getEventObject().executeEvents(EventType.UI_TABLE_EVALUATE,
                        ParameterValues.INSTANCE, getCallInstance(),
                        ParameterValues.CALL_INSTANCE, getCallInstance(),
                        ParameterValues.REQUEST_INSTANCES, _instances,
                        ParameterValues.PARAMETERS, Context.getThreadContext().getParameters(),
                        ParameterValues.CLASS, this,
                        ParameterValues.OTHERS, this.filterList);
        String ret = null;
        if (returns.size() < 1) {
            throw new EFapsException(UIGrid.class, "getInstanceList");
        } else {
            final Object result = returns.get(0).get(ReturnValues.VALUES);
            if (result instanceof String) {
                ret = (String) result;
            }
        }
        return ret;
    }

    protected CharSequence getPrint(final String _queryStmt)
        throws EFapsException
    {
        final StringBuilder stmtBdlr = new StringBuilder().append(_queryStmt);
        if (!_queryStmt.contains(" select ")) {
            stmtBdlr.append(" select ");
        } else {
            stmtBdlr.append(", ");
        }
        final List<String> selects = new ArrayList<>();
        for (final GridColumn column : this.columns) {
            final Field field = column.getField();
            if (field.getSelect() != null) {
                selects.add(field.getSelect() + " as " + field.getName());
            } else if (field.getAttribute() != null) {
                selects.add("attribute[" + field.getAttribute() + "]  as " + field.getName());
            }
            if (field.getSelectAlternateOID() != null) {
                selects.add(field.getSelectAlternateOID() + " as " + field.getName() + "AOID");
            }
            if (field.containsProperty(UITableFieldProperty.SORT_SELECT)) {
                selects.add(field.getProperty(UITableFieldProperty.SORT_SELECT) + " as " + field.getName() + "SORT");
            } else if (field.containsProperty(UITableFieldProperty.SORT_PHRASE)) {
                // sortValue = multi.getPhrase(field.getProperty(UITableFieldProperty.SORT_PHRASE));
            } else if (field.containsProperty(UITableFieldProperty.SORT_MSG_PHRASE)) {
                // sortValue = multi.getMsgPhrase(field.getProperty(UITableFieldProperty.SORT_MSG_PHRASE));
            }
        }
        stmtBdlr.append(selects.stream().collect(Collectors.joining(", ")));
        return stmtBdlr;
    }

    protected void load(final CharSequence _printStmt, final Map<Instance, GridRow> _parents)
        throws EFapsException
    {
        final Map<Long, JSField> jsFields = new HashMap<>();
        final IPrintStatement<?> stmt = (IPrintStatement<?>) EQL2.parse(_printStmt);
        final Evaluator evaluator = PrintStmt.get(stmt).evaluate();
        final Map<Instance, GridRow> instances = new LinkedMap<>();
        while (evaluator.next()) {
            final GridRow row = new GridRow(evaluator.inst());
            instances.put(evaluator.inst(), row);
            if (_parents.isEmpty()) {
                this.values.add(row);
            } else {
                final Instance parentInstance = evaluator.get("ParentInstance");
                if (_parents.containsKey(parentInstance)) {
                    _parents.get(parentInstance).addChild(row);
                }
            }
            for (final GridColumn column : this.columns) {
                final Field field = column.getField();
                final Instance instance = evaluateFieldInstance(evaluator, field);
                final Object value = evaluator.get(field.getName());
                Object sortValue = null;
                if (field.containsProperty(UITableFieldProperty.SORT_SELECT)
                                || field.containsProperty(UITableFieldProperty.SORT_PHRASE)
                                || field.containsProperty(UITableFieldProperty.SORT_MSG_PHRASE)) {
                    sortValue =  evaluator.get(field.getName() + "SORT");
                }

                final Attribute attr = evaluator.attribute(field.getName());
                final UIValue uiValue = UIValue.get(field, attr, value)
                                .setInstance(instance)
                                .setRequestInstances(null)
                                .setCallInstance(getCallInstance());

                final GridCell cell = getCell(column, uiValue, sortValue, jsFields);
                if (column.getFieldConfig().getField().getReference() != null) {
                    cell.setInstance(instance);
                }
                row.add(cell);
            }
        }
        if (isStructureTree() && MapUtils.isNotEmpty(instances)) {
            load(getPrint(getChildQueryStmt(instances.keySet())), instances);
        }
    }

    protected Instance evaluateFieldInstance(final Evaluator _evaluator,
                                             final Field _field)
        throws EFapsException
    {
        Instance ret = _evaluator.inst();
        if (_field.getSelectAlternateOID() != null) {
            try {
                final Object alternateObj = _evaluator.get(_field.getName() + "AOID");
                if (alternateObj instanceof String) {
                    ret = Instance.get((String) alternateObj);
                } else if (alternateObj instanceof Instance) {
                    ret = (Instance) alternateObj;
                }
            } catch (final ClassCastException e) {
                UIGrid.LOG.error("Field '{}' has invalid SelectAlternateOID value", _field);
            }
        } else if (_field.hasEvents(EventType.UI_FIELD_ALTINST)) {
            final List<Return> retTmps = _field.executeEvents(EventType.UI_FIELD_ALTINST, ParameterValues.INSTANCE, ret,
                            ParameterValues.CALL_INSTANCE, null, ParameterValues.REQUEST_INSTANCES, null,
                            ParameterValues.PARAMETERS, Context.getThreadContext()
                                                            .getParameters(), ParameterValues.CLASS, this);
            for (final Return retTmp : retTmps) {
                if (retTmp.contains(ReturnValues.INSTANCE) && retTmp.get(ReturnValues.INSTANCE) != null) {
                    ret = (Instance) retTmp.get(ReturnValues.INSTANCE);
                }
            }
        }
        return ret;
    }

    /**
     * Load.
     *
     * @param _instances the instances
     * @throws EFapsException the eFaps exception
     */
    protected void load(final List<Instance> _instance)
        throws EFapsException
    {
        if (CollectionUtils.isNotEmpty(_instance)) {
            /** The factories. */
            final Map<Long, JSField> jsFields = new HashMap<>();

            final MultiPrintQuery multi = new MultiPrintQuery(_instance);
            for (final GridColumn column : this.columns) {
                final Field field = column.getField();
                if (field.getSelect() != null) {
                    multi.addSelect(field.getSelect());
                } else if (field.getAttribute() != null) {
                    multi.addAttribute(field.getAttribute());
                } else if (field.getPhrase() != null) {
                    multi.addPhrase(field.getName(), field.getPhrase());
                } else if (field.getMsgPhrase() != null) {
                    multi.addMsgPhrase(new SelectBuilder(getBaseSelect4MsgPhrase(field)), field.getMsgPhrase());
                }
                if (field.getSelectAlternateOID() != null) {
                    multi.addSelect(field.getSelectAlternateOID());
                }
                if (field.containsProperty(UITableFieldProperty.SORT_SELECT)) {
                    multi.addSelect(field.getProperty(UITableFieldProperty.SORT_SELECT));
                } else if (field.containsProperty(UITableFieldProperty.SORT_PHRASE)) {
                    multi.addPhrase(field.getProperty(UITableFieldProperty.SORT_PHRASE), field.getProperty(
                                    UITableFieldProperty.SORT_PHRASE));
                } else if (field.containsProperty(UITableFieldProperty.SORT_MSG_PHRASE)) {
                    multi.addMsgPhrase(field.getProperty(UITableFieldProperty.SORT_MSG_PHRASE));
                }
            }
            multi.executeWithoutAccessCheck();
            while (multi.next()) {
                final GridRow row = new GridRow(multi.getCurrentInstance());
                this.values.add(row);
                for (final GridColumn column : this.columns) {
                    final Field field = column.getField();
                    final Instance instance = evaluateFieldInstance(multi, field);
                    Object value = null;
                    Object sortValue = null;
                    Attribute attr = null;
                    if (field.getSelect() != null) {
                        value = multi.<Object>getSelect(field.getSelect());
                        attr = multi.getAttribute4Select(field.getSelect());
                    } else if (field.getAttribute() != null) {
                        value = multi.<Object>getAttribute(field.getAttribute());
                        attr = multi.getAttribute4Attribute(field.getAttribute());
                    } else if (field.getPhrase() != null) {
                        value = multi.getPhrase(field.getName());
                    } else if (field.getMsgPhrase() != null) {
                        value = multi.getMsgPhrase(new SelectBuilder(getBaseSelect4MsgPhrase(field)), field
                                        .getMsgPhrase());
                    }
                    if (field.containsProperty(UITableFieldProperty.SORT_SELECT)) {
                        sortValue = multi.getSelect(field.getProperty(UITableFieldProperty.SORT_SELECT));
                    } else if (field.containsProperty(UITableFieldProperty.SORT_PHRASE)) {
                        sortValue = multi.getPhrase(field.getProperty(UITableFieldProperty.SORT_PHRASE));
                    } else if (field.containsProperty(UITableFieldProperty.SORT_MSG_PHRASE)) {
                        sortValue = multi.getMsgPhrase(field.getProperty(UITableFieldProperty.SORT_MSG_PHRASE));
                    }

                    final UIValue uiValue = UIValue.get(field, attr, value)
                                    .setInstance(instance)
                                    .setRequestInstances(multi.getInstanceList())
                                    .setCallInstance(getCallInstance());

                    final GridCell cell = getCell(column, uiValue, sortValue, jsFields);
                    if (column.getFieldConfig().getField().getReference() != null) {
                        cell.setInstance(instance);
                    }
                    row.add(cell);
                }
            }
        }
    }

    /**
     * Gets the cell.
     *
     * @param _column the column
     * @param _uiValue the ui value
     * @param _sortValue the sort value
     * @param _fields the fields
     * @return the cell
     * @throws EFapsException the e faps exception
     */
    protected GridCell getCell(final GridColumn _column,
                           final UIValue _uiValue,
                           final Object _sortValue,
                           final Map<Long, JSField> _fields)
        throws EFapsException
    {
        JSField jsField;
        if (_fields.containsKey(_uiValue.getField().getId())) {
            jsField = _fields.get(_uiValue.getField().getId());
        } else {
            jsField = new JSField(_uiValue);
            final IComponentFactory fact = jsField.getFactory();
            if (fact == null) {
                _fields.put(_uiValue.getField().getId(), null);
                jsField = null;
            } else {
                _fields.put(_uiValue.getField().getId(), jsField);
                if (fact instanceof DateUIFactory) {
                    _column.setDataType("date");
                } else if (fact instanceof DateTimeUIFactory) {
                    _column.setDataType("datetime");
                } else if (fact instanceof DecimalUIFactory || fact instanceof NumberUIFactory) {
                    _column.setDataType("number");
                } else if (fact instanceof BooleanUIFactory) {
                    _column.setDataType("enum");
                    @SuppressWarnings("unchecked")
                    final Map<String, ?> enumValues = (Map<String, ?>) _uiValue.getReadOnlyValue(TargetMode.VIEW);
                    _column.setEnumValues(enumValues.keySet());
                }
            }
        }
        final String value;
        if (jsField == null) {
            value = "";
        } else {
            jsField.setValue(_uiValue);
            value = jsField.getFactory().getStringValue(jsField);
        }
        return  new GridCell().setValue(value)
                        .setSortValue(_sortValue)
                        .setFieldConfig(_column.getFieldConfig());
    }

    /**
     * Gets the base select for msg phrase.
     *
     * @param _field Field the Base select will be evaluated for
     * @return base select
     */
    protected String getBaseSelect4MsgPhrase(final Field _field)
    {
        String ret = "";
        if (_field.getSelectAlternateOID() != null) {
            ret = StringUtils.removeEnd(_field.getSelectAlternateOID(), ".oid");
        }
        return ret;
    }

    /**
     * Gets the instances.
     *
     * @return the instances
     * @throws EFapsException the e faps exception
     */
    @SuppressWarnings("unchecked")
    protected List<Instance> getInstances()
        throws EFapsException
    {
        final List<Return> returns = getEventObject().executeEvents(EventType.UI_TABLE_EVALUATE,
                        ParameterValues.INSTANCE, getCallInstance(),
                        ParameterValues.CALL_INSTANCE, getCallInstance(),
                        ParameterValues.PARAMETERS, Context.getThreadContext().getParameters(),
                        ParameterValues.CLASS, this,
                        ParameterValues.OTHERS, this.filterList);
        List<Instance> ret = null;
        if (returns.size() < 1) {
            throw new EFapsException(UIGrid.class, "getInstanceList");
        } else {
            final Object result = returns.get(0).get(ReturnValues.VALUES);
            if (result instanceof List) {
                ret = (List<Instance>) result;
            }
        }
        return ret;
    }

    /**
     * Gets the filter for field.
     *
     * @param _field the field
     * @return the filter for field
     */
    protected IFilter getFilter4Field(final Field _field)
    {
        final IFilter ret;
        switch (_field.getFilter().getType()) {
            case STATUS:
            case PICKLIST:
                ret = new ListFilter(_field.getId());
                break;
            case FREETEXT:
            case FORM:
                ret = new MapFilter(_field.getId());
                break;
            case CLASSIFICATION:
                ret = new ClassificationFilter(_field.getId());
                break;
            case NONE:
            default:
                ret = new IFilter()
                {
                    /** The Constant serialVersionUID. */
                    private static final long serialVersionUID = 1L;

                    @Override
                    public long getFieldId()
                    {
                        return _field.getId();
                    }
                };
                break;
        }
        return ret;
    }

    /**
     * Gets the values.
     *
     * @return the values
     * @throws EFapsException on error
     */
    public List<GridRow> getValues()
        throws EFapsException
    {
        init();
        return Collections.unmodifiableList(this.values);
    }

    /**
     * Gets the filter list.
     *
     * @return the filter list
     * @throws EFapsException on error
     */
    public FilterList getFilterList()
        throws EFapsException
    {
        init();
        return this.filterList;
    }

    /**
     * This is the getter method for the instance variable {@link #table}.
     *
     * @return value of instance variable {@link #table}
     * @throws CacheReloadException on error
     */
    public Table getTable()
        throws CacheReloadException
    {
        return getCommand().getTargetTable();
    }

    /**
     * Gets the command.
     *
     * @return the command
     * @throws CacheReloadException the cache reload exception
     */
    @Override
    public AbstractCommand getCommand()
        throws CacheReloadException
    {
        AbstractCommand cmd = Command.get(getCmdUUID());
        if (cmd == null) {
            cmd = Menu.get(getCmdUUID());
        }
        return cmd;
    }

    /**
     * Checks if is structure tree.
     *
     * @return true, if is structure tree
     * @throws CacheReloadException the cache reload exception
     */
    public boolean isStructureTree()
        throws CacheReloadException
    {
        return getCommand().getTargetStructurBrowserField() != null;
    }

    /**
     * Gets the structur browser field.
     *
     * @return the structur browser field
     * @throws CacheReloadException the cache reload exception
     */
    public String getStructurBrowserField()
        throws CacheReloadException
    {
        return getCommand().getTargetStructurBrowserField();
    }

    /**
     * Gets the cmd UUID.
     *
     * @return the cmd UUID
     */
    public UUID getCmdUUID()
    {
        return this.cmdUUID;
    }

    /**
     * Sets the cmd UUID.
     *
     * @param _cmdUUID the new cmd UUID
     * @return the UI grid
     */
    public UIGrid setCmdUUID(final UUID _cmdUUID)
    {
        this.cmdUUID = _cmdUUID;
        return this;
    }

    /**
     * Gets the columns.
     *
     * @return the columns
     * @throws EFapsException on error
     */
    public List<GridColumn> getColumns()
        throws EFapsException
    {
        init();
        return Collections.unmodifiableList(this.columns);
    }

    /**
     * Gets the filter pick list.
     *
     * @param _header the header
     * @return the filter pick list
     */
    public List<String> getFilterPickList(final GridColumn _header)
    {
        // TODO Auto-generated method stub
        return null;
    }

    /**
     * Checks if is show check boxes.
     *
     * @return true, if is show check boxes
     * @throws CacheReloadException the cache reload exception
     */
    public boolean isShowCheckBoxes()
        throws CacheReloadException
    {
        return this.showCheckBoxes == null ? getCommand().isTargetShowCheckBoxes() : this.showCheckBoxes;
    }

    /**
     * Setter method for instance variable {@link #showCheckBoxes}.
     *
     * @param _showCheckBoxes value for instance variable {@link #showCheckBoxes}
     */
    public void setShowCheckBoxes(final Boolean _showCheckBoxes)
    {
        this.showCheckBoxes = _showCheckBoxes;
    }

    /**
     * This method generates the Key for a UserAttribute by using the UUID of
     * the Command and the given UserAttributeKey, so that for every Table a
     * unique key for sorting etc, is created.
     *
     * @param _key UserAttributeKey the Key is wanted
     * @return String with the key
     */
    public String getCacheKey(final CacheKey _key)
    {
        return getCmdUUID() + "-" + _key.getValue();
    }

    /**
     * Evaluate field instance.
     *
     * @param _print the print
     * @param _field field the instance is wanted for
     * @return instance for the field
     * @throws EFapsException on erro
     */
    protected Instance evaluateFieldInstance(final AbstractPrintQuery _print,
                                             final Field _field)
        throws EFapsException
    {
        Instance ret = _print.getCurrentInstance();
        if (_field.getSelectAlternateOID() != null) {
            try {
                final Object alternateObj = _print.getSelect(_field.getSelectAlternateOID());
                if (alternateObj instanceof String) {
                    ret = Instance.get((String) alternateObj);
                } else if (alternateObj instanceof Instance) {
                    ret = (Instance) alternateObj;
                }
            } catch (final ClassCastException e) {
                UIGrid.LOG.error("Field '{}' has invalid SelectAlternateOID value", _field);
            }
        } else if (_field.hasEvents(EventType.UI_FIELD_ALTINST)) {
            final List<Return> retTmps = _field.executeEvents(EventType.UI_FIELD_ALTINST, ParameterValues.INSTANCE, ret,
                            ParameterValues.CALL_INSTANCE, null, ParameterValues.REQUEST_INSTANCES, _print
                                            .getInstanceList(), ParameterValues.PARAMETERS, Context.getThreadContext()
                                                            .getParameters(), ParameterValues.CLASS, this);
            for (final Return retTmp : retTmps) {
                if (retTmp.contains(ReturnValues.INSTANCE) && retTmp.get(ReturnValues.INSTANCE) != null) {
                    ret = (Instance) retTmp.get(ReturnValues.INSTANCE);
                }
            }
        }
        return ret;
    }

    /**
     * This method retrieves the Value for the Title from the eFaps Database.
     *
     * @return Value of the Title
     */
    public String getTitle()
    {
        String title = "";
        try {
            final String key = getCommand().getTargetTitle() == null
                            ? getCommand().getName() + ".Title"
                            : getCommand().getTargetTitle();
            title = DBProperties.getProperty(key);
            if (title != null && getCallInstance() != null) {
                final PrintQuery print = new PrintQuery(getCallInstance());
                final ValueParser parser = new ValueParser(new StringReader(title));
                final ValueList list = parser.ExpressionString();
                list.makeSelect(print);
                if (print.execute()) {
                    title = list.makeString(getCallInstance(), print, TargetMode.VIEW);
                }
                // Administration
                if (Configuration.getAttributeAsBoolean(Configuration.ConfigAttribute.SHOW_OID)
                                && Context.getThreadContext()
                                                .getPerson()
                                                .isAssigned(Role.get(UUID
                                                                .fromString("1d89358d-165a-4689-8c78-fc625d37aacd")))) {
                    title = title + " " + getCallInstance().getOid();
                }
            }
        } catch (final EFapsException | ParseException e) {
            throw new RestartResponseException(new ErrorPage(new EFapsException(this.getClass(), "",
                            "Error reading the Title")));
        }
        return title;
    }

    /**
     * Method used to evaluate the type for this table from the connected
     * events.
     *
     * @return type if found
     * @throws EFapsException on error
     */
    protected Type getType()
        throws EFapsException
    {
        init();
        final Type ret;
        if (getValues().isEmpty()) {
            final List<EventDefinition> events =  getCommand().getEvents(EventType.UI_TABLE_EVALUATE);
            String typeName = null;
            if (events.size() > 1) {
                throw new EFapsException(this.getClass(), "execute4NoInstance.moreThanOneEvaluate");
            } else {
                final EventDefinition event = events.get(0);
                // test for basic or abstract types
                if (event.getProperty("Type") != null) {
                    typeName = event.getProperty("Type");
                }
                // no type yet search alternatives
                if (typeName == null) {
                    for (int i = 1; i < 100; i++) {
                        final String nameTmp = "Type" + String.format("%02d", i);
                        if (event.getProperty(nameTmp) != null) {
                            typeName = event.getProperty(nameTmp);
                        } else {
                            break;
                        }
                    }
                }
            }
            ret = typeName == null ? null : Type.get(typeName);
        } else {
            ret = getValues().get(0).getInstance().getType();
        }
        return ret;
    }

    /**
     * Checks if is date filter.
     *
     * @param _filter the filter
     * @return true, if is date filter
     * @throws EFapsException the e faps exception
     */
    public boolean isDateFilter(final IFilter _filter) throws EFapsException
    {
        final boolean ret;
        final Field field = Field.get(_filter.getFieldId());
        // Explicitly set UIProvider
        if (field.getUIProvider() != null && (field.getUIProvider() instanceof DateTimeUI || field
                        .getUIProvider() instanceof DateUI)) {
            ret = true;
        } else {
            final Attribute attr = getType().getAttribute(field.getAttribute());
            if (attr == null) {
                ret = false;
            } else {
                final IUIProvider uiProvider = attr.getAttributeType().getUIProvider();
                ret = uiProvider instanceof DateTimeUI || uiProvider instanceof DateUI;
            }
        }
        return ret;
    }

    @Override
    public Instance getInstance()
        throws EFapsException
    {
        return getCallInstance();
    }

    /**
     * Getter method for the instance variable {@link #callInstance}.
     *
     * @return value of instance variable {@link #callInstance}
     */
    public Instance getCallInstance()
    {
        return this.callInstance;
    }

    /**
     * Setter method for instance variable {@link #callInstance}.
     *
     * @param _callInstance value for instance variable {@link #callInstance}
     * @return the UI grid
     */
    public UIGrid setCallInstance(final Instance _callInstance)
    {
        this.callInstance = _callInstance;
        return this;
    }

    /**
     * Getter method for the instance variable {@link #pagePosition}.
     *
     * @return value of instance variable {@link #pagePosition}
     */
    @Override
    public PagePosition getPagePosition()
    {
        return this.pagePosition;
    }

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

    /**
     * Reload.
     *
     * @throws EFapsException the e faps exception
     */
    public void reload()
        throws EFapsException
    {
        if (!this.initialized) {
            init();
        } else {
            this.values.clear();
            Context.getThreadContext().setSessionAttribute(getCacheKey(CacheKey.DBFILTER), this.filterList);
            load(getInstances());
        }
    }

    @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;
    }

    @Override
    public List<Return> executeEvents(final EventType _eventType,
                                      final Object... _objectTuples)
        throws EFapsException
    {
        final List<Return> ret;
        if (isWizardCall()) {
            ret = ((ICmdUIObject) getUIWizardObject().getWizardElement().get(0)).executeEvents(_eventType,
                            _objectTuples);
        } else {
            ret = getEventObject().executeEvents(_eventType, _objectTuples);
        }
        return ret;
    }

    /**
     * Gets the event object.
     *
     * @return the event object
     * @throws CacheReloadException the cache reload exception
     */
    public AbstractAdminObject getEventObject()
        throws CacheReloadException
    {
        return getCommand();
    }

    /**
     * Checks if is columns up to date.
     *
     * @return the columns up to date
     */
    public boolean isColumnsUpToDate()
    {
        return this.columnsUpToDate;
    }

    /**
     * Sets the columns up to date.
     *
     * @param _columnsUpToDate the new columns up to date
     */
    public void setColumnsUpToDate(final boolean _columnsUpToDate)
    {
        this.columnsUpToDate = _columnsUpToDate;
    }

    /**
     * Gets the row for id.
     *
     * @param _rowId the row id
     * @return the row for id
     * @throws EFapsException the e faps exception
     */
    public GridRow getRow4Id(final String _rowId)
        throws EFapsException
    {
        final String[] rowIds = _rowId.split("-");
        GridRow row = null;
        for (final String id : rowIds) {
            if (row == null) {
                row = getValues().get(Integer.parseInt(id));
            } else {
                row = row.getChildren().get(Integer.parseInt(id));
            }
        }
        return row;
    }

    public String getMarkupId()
    {
        return "grid";
    }

    /**
     * Gets the.
     *
     * @param _commandUUID the command UUID
     * @param _pagePosition the page position
     * @return the UI grid
     */
    public static UIGrid get(final UUID _commandUUID,
                             final PagePosition _pagePosition)
    {
        final UIGrid ret = new UIGrid();
        ret.setCmdUUID(_commandUUID).setPagePosition(_pagePosition);
        return ret;
    }

    /**
     * Prints the.
     *
     * @param _uiGrid the ui grid
     * @return the file
     */
    public static File print(final UIGrid _uiGrid)
    {
        File ret = null;
        final String clazzName = Configuration.getAttribute(ConfigAttribute.GRIDPRINTESJP);
        try {
            UIGrid.LOG.debug("Print method executed for {}", _uiGrid);

            final Class<?> clazz = Class.forName(clazzName, false, EFapsClassLoader.getInstance());
            final EventExecution event = (EventExecution) clazz.newInstance();
            final Parameter param = new Parameter();
            param.put(ParameterValues.PARAMETERS, Context.getThreadContext().getParameters());
            param.put(ParameterValues.CLASS, _uiGrid);
            final Return retu = event.execute(param);
            if (retu != null) {
                ret = (File) retu.get(ReturnValues.VALUES);
            }
        } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            UIGrid.LOG.error("Catched", e);
        } catch (final EFapsException e) {
            UIGrid.LOG.error("Catched", e);
        }
        return ret;
    }

    /**
     * Prints the.
     *
     * @param _instance the instance
     * @return the file
     */
    public static File checkout(final Instance _instance)
    {
        File ret = null;
        final String clazzName = Configuration.getAttribute(ConfigAttribute.GRIDCHECKOUTESJP);
        try {
            UIGrid.LOG.debug("Checkout method executed for {}", _instance);

            final Class<?> clazz = Class.forName(clazzName, false, EFapsClassLoader.getInstance());
            final EventExecution event = (EventExecution) clazz.newInstance();
            final Parameter param = new Parameter();
            param.put(ParameterValues.PARAMETERS, Context.getThreadContext().getParameters());
            param.put(ParameterValues.INSTANCE, _instance);
            final Return retu = event.execute(param);
            if (retu != null) {
                ret = (File) retu.get(ReturnValues.VALUES);
            }
        } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            UIGrid.LOG.error("Catched", e);
        } catch (final EFapsException e) {
            UIGrid.LOG.error("Catched", e);
        }
        return ret;
    }
}


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

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.wicket.extensions.markup.html.repeater.tree.ITreeProvider;
import org.apache.wicket.markup.repeater.data.ListDataProvider;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.efaps.admin.EFapsSystemConfiguration;
import org.efaps.admin.dbproperty.DBProperties;
import org.efaps.admin.index.ISearch;
import org.efaps.admin.index.Index;
import org.efaps.admin.index.SearchConfig;
import org.efaps.admin.index.Searcher;
import org.efaps.admin.program.esjp.EFapsClassLoader;
import org.efaps.json.index.SearchResult;
import org.efaps.json.index.result.DimValue;
import org.efaps.json.index.result.Dimension;
import org.efaps.json.index.result.Element;
import org.efaps.util.EFapsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The Class IndexSearch.
 *
 * @author The eFaps Team
 */
public class IndexSearch
    implements Serializable
{

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

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

    /** The base query (The Query as set by the User). */
    private String currentQuery = "";
    /** The base query (The Query as set by the User). */
    private String previousQuery = "";

    /** The dimensions. */
    private List<Dimension> dimensions;

    /** The search. */
    private ISearch search;

    /** The result. */
    private SearchResult result;

    /** The dimension provider. */
    private DimensionProvider dimensionProvider;

    /** The element data provider. */
    private ElementDataProvider elementDataProvider;

    /** The previous search name. */
    private String previousSearchName;

    /**
     * Gets the query.
     *
     * @return the query
     */
    protected String getQuery()
    {
        final StringBuilder ret = new StringBuilder();
        try {
            final String clazzname;
            if (EFapsSystemConfiguration.get().containsAttributeValue("org.efaps.kernel.index.QueryBuilder")) {
                clazzname = EFapsSystemConfiguration.get().getAttributeValue("org.efaps.kernel.index.QueryBuilder");
            } else {
                clazzname = "org.efaps.esjp.admin.index.LucenceQueryBuilder";
            }
            final Class<?> clazz = Class.forName(clazzname, false, EFapsClassLoader.getInstance());
            final Object obj = clazz.newInstance();
            final Method method = clazz.getMethod("getQuery4DimValues", String.class, List.class, List.class);
            final Object newQuery = method.invoke(obj, getCurrentQuery(), getIncluded(), getExcluded());
            ret.append(newQuery);
        } catch (final EFapsException | ClassNotFoundException | InstantiationException | IllegalAccessException
                        | NoSuchMethodException | SecurityException | IllegalArgumentException
                        | InvocationTargetException e) {
            IndexSearch.LOG.error("Catched", e);
            ret.append(getCurrentQuery());
        }
        return ret.toString();
    }

    /**
     * Search.
     */
    public void search()
    {
        try {
            this.previousSearchName = this.search == null ? null : this.search.getName();
            this.search = Index.getSearch();
            this.search.setQuery(getQuery());
            this.result = Searcher.search(this.search);
            if (StringUtils.isNotEmpty(getCurrentQuery()) && !getCurrentQuery().equals(getPreviousQuery())
                            && dimFilterApplied(null)) {
                final ISearch tmpSearch = new ISearch()
                {

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

                    @Override
                    public void setQuery(final String _query)
                    {
                    }

                    @Override
                    public String getQuery()
                    {
                        return getCurrentQuery();
                    }

                    @Override
                    public int getNumHits()
                    {
                        return 1;
                    }

                    @Override
                    public List<SearchConfig> getConfigs()
                        throws EFapsException
                    {
                        final List<SearchConfig> ret = new ArrayList<>();
                        ret.add(SearchConfig.ACTIVATE_DIMENSION);
                        return ret;
                    };
                };
                final SearchResult tmpResult = Searcher.search(tmpSearch);
                this.dimensions = tmpResult.getDimensions();
            } else {
                this.dimensions = this.result.getDimensions();
            }
            getDataProvider().setElements(this.result.getElements());
            fillDimensionProvider(!getCurrentQuery().equals(getPreviousQuery()));
        } catch (final EFapsException e) {
            IndexSearch.LOG.error("Catched", e);
        }
    }

    /**
     * Gets the excluded.
     *
     * @return the excluded
     */
    private List<DimValue> getExcluded()
    {
        final List<DimValue> ret = new ArrayList<>();
        for (final DimTreeNode node : getDimensionProvider().getRootList()) {
            ret.addAll(node.getExcluded());
        }
        return ret;
    }

    /**
     * Gets the included.
     *
     * @return the included
     */
    private List<DimValue> getIncluded()
    {
        final List<DimValue> ret = new ArrayList<>();
        for (final DimTreeNode node : getDimensionProvider().getRootList()) {
            ret.addAll(node.getIncluded());
        }
        return ret;
    }

    /**
     * Check if a dimension filter applied.
     *
     * @param _nodes the nodes
     * @return true, if successful
     */
    private boolean dimFilterApplied(final List<DimTreeNode> _nodes)
    {
        final List<DimTreeNode> nodes = _nodes == null ? getDimensionProvider().getRootList() : _nodes;

        boolean ret = false;
        for (final DimTreeNode node : nodes) {
            if (node.getStatus() != null) {
                ret = true;
                break;
            }
            ret = dimFilterApplied(node.getChildren());
            if (ret) {
                break;
            }
        }
        return ret;
    }

    /**
     * Fill dimension provider.
     *
     * @param _updateDim the update dim
     */
    private void fillDimensionProvider(final boolean _updateDim)
    {
        final DimensionProvider provider = getDimensionProvider();
        final Iterator<? extends DimTreeNode> currentIter = provider.getRoots();

        final List<Dimension> dims = getDimensions();
        if (_updateDim && dims.isEmpty()) {
            provider.getRootList().clear();
        } else {
            Collections.sort(dims, new Comparator<Dimension>()
            {

                @Override
                public int compare(final Dimension _arg0,
                                   final Dimension _arg1)
                {
                    final String dim0 = DBProperties.getProperty(DimensionPanel.class.getName() + "." + _arg0.getKey());
                    final String dim1 = DBProperties.getProperty(DimensionPanel.class.getName() + "." + _arg1.getKey());
                    return dim0.compareTo(dim1);
                }
            });

            final Iterator<Dimension> newDimsIter = dims.iterator();
            while (currentIter.hasNext()) {
                final DimTreeNode current = currentIter.next();
                if (newDimsIter.hasNext()) {
                    final Dimension newDim = newDimsIter.next();
                    if (!newDim.getKey().equals(((Dimension) current.getValue()).getKey())) {
                        currentIter.remove();
                    } else if (_updateDim) {
                        current.update(newDim.getValues());
                    }
                }
            }
            // add new ones
            while (newDimsIter.hasNext()) {
                final DimTreeNode node = new DimTreeNode().setValue(newDimsIter.next());
                provider.getRootList().add(node);
            }
        }
    }

    /**
     * Gets the search.
     *
     * @return the search
     */
    public ISearch getSearch()
    {
        return this.search;
    }

    /**
     * Gets the result.
     *
     * @return the result
     */
    public SearchResult getResult()
    {
        return this.result;
    }

    /**
     * Gets the data provider.
     *
     * @return the data provider
     */
    public ElementDataProvider getDataProvider()
    {
        if (this.elementDataProvider == null) {
            this.elementDataProvider = new ElementDataProvider();
        }
        return this.elementDataProvider;
    }

    /**
     * Gets the dimension provider.
     *
     * @return the dimension provider
     */
    public DimensionProvider getDimensionProvider()
    {
        if (this.dimensionProvider == null) {
            this.dimensionProvider = new DimensionProvider();
        }
        return this.dimensionProvider;
    }

    /**
     * Gets the base query (The Query as set by the User).
     *
     * @return the base query (The Query as set by the User)
     */
    public String getCurrentQuery()
    {
        return this.currentQuery;
    }

    /**
     * Sets the base query (The Query as set by the User).
     *
     * @param _currentQuery the new base query (The Query as set by the User)
     */
    public void setCurrentQuery(final String _currentQuery)
    {
        this.previousQuery = this.currentQuery;
        this.currentQuery = _currentQuery;
    }

    /**
     * Gets the base query (The Query as set by the User).
     *
     * @return the base query (The Query as set by the User)
     */
    public String getPreviousQuery()
    {
        return this.previousQuery;
    }

    /**
     * Sets the base query (The Query as set by the User).
     *
     * @param _previousQuery the new base query (The Query as set by the User)
     */
    public void setPreviousQuery(final String _previousQuery)
    {
        this.previousQuery = _previousQuery;
    }

    /**
     * Gets the dimensions.
     *
     * @return the dimensions
     */
    public List<Dimension> getDimensions()
    {
        return this.dimensions;
    }

    /**
     * Checks if is update table.
     *
     * @return true, if is update table
     */
    public boolean isUpdateTable()
    {
        return !getSearch().getName().equals(this.previousSearchName);
    }

    /**
     * The Class ElementDataProvider.
     *
     * @author The eFaps Team
     */
    public static class ElementDataProvider
        extends ListDataProvider<Element>
    {

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

        /** The elements. */
        private List<Element> elements = new ArrayList<>();

        @Override
        protected List<Element> getData()
        {
            return this.elements;
        }

        /**
         * Gets the elements.
         *
         * @return the elements
         */
        public List<Element> getElements()
        {
            return this.elements;
        }

        /**
         * Sets the elements.
         *
         * @param _elements the new elements
         */
        public void setElements(final List<Element> _elements)
        {
            this.elements = _elements;
        }
    }

    /**
     * The Class DimensionProvider.
     */
    public static class DimensionProvider
        implements ITreeProvider<DimTreeNode>
    {

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

        /** The roots. */
        private final List<DimTreeNode> roots = new ArrayList<>();

        @Override
        public void detach()
        {
        }

        @Override
        public Iterator<? extends DimTreeNode> getRoots()
        {
            return this.roots.iterator();
        }

        /**
         * Gets the dimensions.
         *
         * @return the dimensions
         */
        public List<DimTreeNode> getRootList()
        {
            return this.roots;
        }

        @Override
        public boolean hasChildren(final DimTreeNode _node)
        {
            return !_node.getChildren().isEmpty();
        }

        @Override
        public Iterator<? extends DimTreeNode> getChildren(final DimTreeNode _node)
        {
            return _node.getChildren().iterator();
        }

        @Override
        public IModel<DimTreeNode> model(final DimTreeNode _object)
        {
            return Model.<DimTreeNode>of(_object);
        }
    }

    /**
     * The Class TreeValue.
     *
     */
    public static class DimTreeNode
        implements Serializable
    {

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

        /** The value. */
        private Object value;

        /** The status. */
        private Boolean status;

        /** The children. */
        private List<DimTreeNode> children = new ArrayList<>();

        /**
         * Gets the value.
         *
         * @return the value
         */
        public Object getValue()
        {
            return this.value;
        }

        /**
         * Update.
         *
         * @param _set the set
         */
        public void update(final Set<DimValue> _set)
        {
            final List<DimValue> values = new ArrayList<>(_set);
            Collections.sort(values, new Comparator<DimValue>()
            {

                @Override
                public int compare(final DimValue _o1,
                                   final DimValue _o2)
                {
                    return _o1.getLabel().compareTo(_o2.getLabel());
                }
            });
            final List<DimTreeNode> newChildren = new ArrayList<>();
            for (final DimValue val : values) {
                final DimTreeNode existing = getChild(val);
                final DimTreeNode newNode = new DimTreeNode().setValue(val).setStatus(existing == null ? null
                                : existing.getStatus());
                newChildren.add(newNode);
                if (existing != null) {
                    existing.update(val.getChildren());
                    newNode.setChildren(existing.getChildren());
                }
            }
            setChildren(newChildren);
        }

        /**
         * Gets the child.
         *
         * @param _val the val
         * @return the child
         */
        private DimTreeNode getChild(final DimValue _val)
        {
            DimTreeNode ret = null;
            for (final DimTreeNode node : this.children) {
                if (node.getLabel().equals(_val.getLabel())) {
                    ret = node;
                    break;
                }
            }
            return ret;
        }

        /**
         * Gets the excluded.
         *
         * @return the excluded
         */
        public List<DimValue> getExcluded()
        {
            final List<DimValue> ret = new ArrayList<>();
            if (BooleanUtils.isFalse(this.status)) {
                ret.add((DimValue) this.value);
            }
            for (final DimTreeNode child : getChildren()) {
                ret.addAll(child.getExcluded());
            }
            return ret;
        }

        /**
         * Gets the included.
         *
         * @return the included
         */
        public List<DimValue> getIncluded()
        {
            final List<DimValue> ret = new ArrayList<>();
            if (BooleanUtils.isTrue(this.status)) {
                ret.add((DimValue) this.value);
            }
            for (final DimTreeNode child : getChildren()) {
                ret.addAll(child.getIncluded());
            }
            return ret;
        }

        /**
         * Sets the value.
         *
         * @param _value the new value
         * @return the value wrapper
         */
        public DimTreeNode setValue(final Object _value)
        {
            this.value = _value;
            if (_value instanceof Dimension) {
                final List<DimValue> values = new ArrayList<>(((Dimension) _value).getValues());
                Collections.sort(values, new Comparator<DimValue>()
                {

                    @Override
                    public int compare(final DimValue _o1,
                                       final DimValue _o2)
                    {
                        return _o1.getLabel().compareTo(_o2.getLabel());
                    }
                });
                for (final DimValue dimvalue : values) {
                    this.children.add(new DimTreeNode().setValue(dimvalue));
                }
            } else {
                final List<DimValue> values = new ArrayList<>(((DimValue) _value).getChildren());
                Collections.sort(values, new Comparator<DimValue>()
                {

                    @Override
                    public int compare(final DimValue _o1,
                                       final DimValue _o2)
                    {
                        return _o1.getLabel().compareTo(_o2.getLabel());
                    }
                });
                for (final DimValue dimvalue : values) {
                    this.children.add(new DimTreeNode().setValue(dimvalue));
                }
            }
            return this;
        }

        /**
         * Gets the label.
         *
         * @return the label
         */
        public String getLabel()
        {
            final String ret;
            if (this.value instanceof Dimension) {
                ret = DBProperties.getProperty(DimensionPanel.class.getName() + "." + ((Dimension) this.value)
                                .getKey());
            } else {
                ret = ((DimValue) this.value).getLabel();
            }
            return ret;
        }

        @Override
        public boolean equals(final Object _obj)
        {
            final boolean ret;
            if (_obj instanceof DimTreeNode) {
                ret = getValue().equals(((DimTreeNode) _obj).getValue());
            } else {
                ret = super.equals(_obj);
            }
            return ret;
        }

        @Override
        public int hashCode()
        {
            return getValue().hashCode();
        }

        /**
         * Gets the status.
         *
         * @return the status
         */
        public Boolean getStatus()
        {
            return this.status;
        }

        /**
         * Sets the status.
         *
         * @param _status the status
         * @return the dim tree node
         */
        public DimTreeNode setStatus(final Boolean _status)
        {
            this.status = _status;
            return this;
        }

        /**
         * Gets the children.
         *
         * @return the children
         */
        public List<DimTreeNode> getChildren()
        {
            return this.children;
        }

        /**
         * Sets the children.
         *
         * @param _children the new children
         */
        public void setChildren(final List<DimTreeNode> _children)
        {
            this.children = _children;
        }
    }

}


/*
 * Copyright 2003 - 2014 The eFaps Team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Revision:        $Rev$
 * Last Changed:    $Date$
 * Last Changed By: $Author$
 */

package org.efaps.ui.wicket.components;

import java.io.Serializable;
import java.io.StringReader;
import java.util.UUID;

import org.apache.wicket.Component;
import org.apache.wicket.Page;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.request.cycle.RequestCycle;
import org.efaps.admin.dbproperty.DBProperties;
import org.efaps.admin.ui.AbstractUserInterfaceObject.TargetMode;
import org.efaps.admin.ui.Menu;
import org.efaps.beans.ValueList;
import org.efaps.beans.valueparser.ParseException;
import org.efaps.beans.valueparser.ValueParser;
import org.efaps.db.Instance;
import org.efaps.db.PrintQuery;
import org.efaps.ui.wicket.models.objects.AbstractUIObject;
import org.efaps.ui.wicket.pages.contentcontainer.ContentContainerPage;
import org.efaps.ui.wicket.pages.error.ErrorPage;
import org.efaps.util.EFapsException;

/**
 * TODO comment!
 *
 * @author The eFaps Team
 * @version $Id$
 */
public class RecentObjectLink
    implements IRecent, Serializable
{
    /**
     * Needed for serialization.
     */
    private static final long serialVersionUID = 1L;
    /**
     * Instance of the Object thi slink belongs to.
     */
    private final Instance instance;

    /**
     * Label of this link.
     */

    private String label;
    /**
     * UUID of the menu.
     */
    private UUID menuUUID;

    /**
     * UUID of the selected command.
     */
    private UUID cmdUUID;

    /**
     * @param _uiObject     uiObject this Link belongs to
     * @throws EFapsException on error
     */
    public RecentObjectLink(final AbstractUIObject _uiObject)
        throws EFapsException
    {
        this.instance = _uiObject.getInstance();
        try {
            if (getInstance() != null && getInstance().isValid()) {
                final Menu menu = Menu.getTypeTreeMenu(getInstance().getType());
                this.menuUUID = menu.getUUID();
                this.label = DBProperties.getProperty(menu.getLabel());
                this.cmdUUID = _uiObject.getCommandUUID();

                final ValueParser parser = new ValueParser(new StringReader(getLabel()));
                final ValueList list = parser.ExpressionString();
                if (list.getExpressions().size() > 0) {
                    final PrintQuery print = new PrintQuery(getInstance());
                    list.makeSelect(print);
                    if (print.execute()) {
                        this.label = list.makeString(getInstance(), print, TargetMode.VIEW);
                    }
                }
            }
        } catch (final EFapsException e) {
            throw new RestartResponseException(new ErrorPage(e));
        } catch (final ParseException e) {
            throw new RestartResponseException(new ErrorPage(e));
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void open(final Component _openComponent)
        throws EFapsException
    {
        Page page;
        try {
            page = new ContentContainerPage(this.menuUUID, getInstance().getOid(), this.cmdUUID);
        } catch (final EFapsException e) {
            page = new ErrorPage(e);
        }
        RequestCycle.get().setResponsePage(page);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getLabel(final int _maxLength)
        throws EFapsException
    {
        String labelTmp = getLabel();
        if (labelTmp.length() > _maxLength) {
            labelTmp = labelTmp.substring(0, _maxLength - 3) + "...";
        }
        return labelTmp;
    }

    /**
     * Getter method for the instance variable {@link #label}.
     *
     * @return value of instance variable {@link #label}
     */
    protected String getLabel()
    {
        return this.label;
    }

    /**
     * Getter method for the instance variable {@link #instance}.
     *
     * @return value of instance variable {@link #instance}
     */
    protected Instance getInstance()
    {
        return this.instance;
    }

}


/*
 * Copyright 2003 - 2018 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 java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.wicket.Component;
import org.apache.wicket.ajax.WicketAjaxJQueryResourceReference;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.markup.head.CssHeaderItem;
import org.apache.wicket.markup.head.HeaderItem;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.IReferenceHeaderItem;
import org.apache.wicket.markup.head.PriorityHeaderItem;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.Response;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.handler.resource.ResourceReferenceRequestHandler;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.request.resource.CssResourceReference;
import org.apache.wicket.request.resource.JavaScriptResourceReference;
import org.apache.wicket.request.resource.ResourceReference;
import org.apache.wicket.util.string.Strings;
import org.efaps.db.Context;
import org.efaps.ui.wicket.util.Configuration;
import org.efaps.ui.wicket.util.Configuration.ConfigAttribute;
import org.efaps.util.EFapsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class renders the Links for the JavaScripts in the Head for Behaviors
 * using Dojo.
 *
 * @author The eFaps Team
 */
public abstract class AbstractDojoBehavior
    extends Behavior
{

    /**
     * Reference to the stylesheet.
     */
    public static final ResourceReference CSS_TUNDRA = new CssResourceReference(AbstractDojoBehavior.class,
                    "dijit/themes/tundra/tundra.css");

    /**
     * Reference to the stylesheet.
     */
    public static final ResourceReference CSS_CLARO = new CssResourceReference(AbstractDojoBehavior.class,
                    "dijit/themes/claro/claro.css");

    /**
     * Reference to the stylesheet.
     */
    public static final ResourceReference CSS_NIHILO = new CssResourceReference(AbstractDojoBehavior.class,
                    "dijit/themes/nihilo/nihilo.css");

    /**
     * Reference to the stylesheet.
     */
    public static final ResourceReference CSS_SORIA = new CssResourceReference(AbstractDojoBehavior.class,
                    "dijit/themes/soria/soria.css");

    /**
     * Reference to the JavaScript.
     */
    public static final JavaScriptResourceReference JS_DOJO = new JavaScriptResourceReference(
                    AbstractDojoBehavior.class,
                    "dojo/dojo.js");

    /**
     * Logger.
     */
    private static final Logger LOG =  LoggerFactory.getLogger(AbstractDojoBehavior.class);

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

    /**
     * Render the links for the head.
     *
     * @see org.apache.wicket.behavior.AbstractBehavior#renderHead(org.apache.wicket.markup.html.IHeaderResponse)
     * @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(new PriorityHeaderItem(new DojoHeaderItem(AbstractDojoBehavior.JS_DOJO,
                        AbstractDojoBehavior.class.getName())));
        final String clazz = Configuration.getAttribute(ConfigAttribute.DOJO_CLASS);

        ResourceReference reference = null;
        if ("tundra".equals(clazz)) {
            reference = AbstractDojoBehavior.CSS_TUNDRA;
        } else if ("claro".equals(clazz)) {
            reference = AbstractDojoBehavior.CSS_CLARO;
        } else if ("nihilo".equals(clazz)) {
            reference = AbstractDojoBehavior.CSS_NIHILO;
        } else if ("soria".equals(clazz)) {
            reference = AbstractDojoBehavior.CSS_TUNDRA;
        }
        if (reference != null) {
            _response.render(CssHeaderItem.forReference(reference));
        }
    }

    /**
     * All components using dojo must render the id of the component.
     *
     * @see org.apache.wicket.behavior.AbstractBehavior#beforeRender(org.apache.wicket.Component)
     * @param _component component
     */
    @Override
    public void beforeRender(final Component _component)
    {
        super.beforeRender(_component);
        _component.setOutputMarkupId(true);
    }

    /**
     * Class to add Dojo script tags.
     */
    public static final class DojoHeaderItem
        extends HeaderItem
        implements IReferenceHeaderItem
    {
        /**
         *
         */
        private static final long serialVersionUID = 1L;

        /**
         * Resource refrecne with the actual script.
         */
        private final ResourceReference reference;

        /**
         * Id this script will be identified by.
         */
        private final String id;

        /**
         * @param _reference the ResourceReference3
         * @param _id       id of this script
         */
        public DojoHeaderItem(final ResourceReference _reference,
                              final String _id)
        {
            this.id = _id;
            this.reference = _reference;
        }

        /**
         * @return the reference for the item.
         */
        @Override
        public ResourceReference getReference()
        {
            return this.reference;
        }

        /**
         * @return The tokens this {@code HeaderItem} can be identified by. If
         *         any of the tokens has already been rendered, this
         *         {@code HeaderItem} will not be rendered.
         */
        @Override
        public Iterable<?> getRenderTokens()
        {
            final String url = Strings.stripJSessionId(getUrl());
            final List<String> ret;
            if (Strings.isEmpty(this.id)) {
                ret = Collections.singletonList("javascript-" + url);
            } else {
                ret = Arrays.asList("javascript-" + this.id, "javascript-" + url);
            }
            return ret;
        }

        /**
         * Renders the {@code HeaderItem} to the response.
         *
         * @param _response Response
         */
        @Override
        public void render(final Response _response)
        {
            final String url = getUrl();
            _response.write("<script type=\"text/javascript\">\n");
            _response.write(" var dojoConfig = {");
            _response.write("baseUrl:\"");
            _response.write(url.substring(0, url.lastIndexOf("/")));
            _response.write("\",");
            _response.write("async:true,");

            if (WebApplication.get().getDebugSettings().isAjaxDebugModeEnabled()) {
                _response.write("isDebug:true,");
            }
            _response.write("locale:\"");
            try {
                _response.write(Context.getThreadContext().getLocale().toLanguageTag());
            } catch (final EFapsException e) {
                AbstractDojoBehavior.LOG.warn("Could not set correct locale for Dojo");
            }
            _response.write("\",");
            _response.write("parseOnLoad: true");
            _response.write(" };");
            _response.write("</script>\n");
            _response.write("<script type=\"text/javascript\"");
            if (this.id != null) {
                _response.write(" id=\"" + this.id + "\" ");
            }
            _response.write(" src=\"");
            _response.write(url);
            _response.write("\"></script>");
            _response.write("\n");
        }

        /**
         * @return the url for this resource
         */
        private String getUrl()
        {
            final IRequestHandler handler = new ResourceReferenceRequestHandler(getReference(),
                            new PageParameters());
            return RequestCycle.get().urlFor(handler).toString();
        }

        @Override
        public List<HeaderItem> getDependencies()
        {
            final List<HeaderItem> ret = new ArrayList<>();
            ret.addAll(WicketAjaxJQueryResourceReference.get().getDependencies());
            return ret;
        }
    }
}


/*
 * 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.pages.content.form;

import java.util.List;

import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Page;
import org.apache.wicket.PageReference;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.efaps.ui.wicket.components.FormContainer;
import org.efaps.ui.wicket.components.classification.ClassificationPathPanel;
import org.efaps.ui.wicket.components.form.FormPanel;
import org.efaps.ui.wicket.components.gridx.GridXPanel;
import org.efaps.ui.wicket.components.heading.HeadingPanel;
import org.efaps.ui.wicket.components.modalwindow.ModalWindowContainer;
import org.efaps.ui.wicket.components.table.TablePanel;
import org.efaps.ui.wicket.components.table.header.HeaderPanel;
import org.efaps.ui.wicket.components.tree.StructurBrowserTreeTablePanel;
import org.efaps.ui.wicket.models.field.IHidden;
import org.efaps.ui.wicket.models.objects.UIClassification;
import org.efaps.ui.wicket.models.objects.UIFieldForm;
import org.efaps.ui.wicket.models.objects.UIFieldStructurBrowser;
import org.efaps.ui.wicket.models.objects.UIFieldTable;
import org.efaps.ui.wicket.models.objects.UIForm;
import org.efaps.ui.wicket.models.objects.UIForm.Element;
import org.efaps.ui.wicket.models.objects.UIForm.ElementType;
import org.efaps.ui.wicket.models.objects.UIForm.FormElement;
import org.efaps.ui.wicket.models.objects.grid.UIFieldGrid;
import org.efaps.ui.wicket.models.objects.UIHeading;
import org.efaps.ui.wicket.pages.content.AbstractContentPage;
import org.efaps.ui.wicket.resources.AbstractEFapsHeaderItem;
import org.efaps.ui.wicket.resources.EFapsContentReference;
import org.efaps.util.EFapsException;

/**
 * @author The eFaps Team
 */
public class FormPage
    extends AbstractContentPage
{

    /**
     * Reference to the css stylesheet.
     */
    private static final EFapsContentReference CSS = new EFapsContentReference(FormPage.class, "FormPage.css");

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

    /**
     * @param _model model for the page
     * @throws EFapsException on error
     */
    public FormPage(final IModel<?> _model)
        throws EFapsException
    {
        this(_model, (ModalWindowContainer) null);
    }

    /**
     * @param _model model for the page
     * @param _modalWindow modal window
     * @throws EFapsException on error
     */
    public FormPage(final IModel<?> _model,
                    final ModalWindowContainer _modalWindow)
        throws EFapsException
    {
        super(_model, _modalWindow);
        this.addComponents();
    }

    /**
     * @param _model            model for the page
     * @param _pageReference    PageReference
     * @throws EFapsException on error
     */
    public FormPage(final IModel<?> _model,
                    final PageReference _pageReference)
        throws EFapsException
    {
        this(_model, null, _pageReference);
    }

    /**
     * @param _model            model
     * @param _modalWindow      window
     * @param _pageReference    reference
     * @throws EFapsException on error
     */
    public FormPage(final IModel<?> _model,
                    final ModalWindowContainer _modalWindow,
                    final PageReference _pageReference)
        throws EFapsException
    {
        super(_model, _modalWindow, _pageReference);
        this.addComponents();
    }

    /**
     * Method to add the components to this page.
     *
     * @throws EFapsException on error
     */
    protected void addComponents()
        throws EFapsException
    {
        final UIForm uiForm = (UIForm) super.getDefaultModelObject();

        if (!uiForm.isInitialized()) {
            uiForm.execute();
        }

        final FormContainer form = new FormContainer("form");
        this.add(form);
        form.add(AttributeModifier.append("class", uiForm.getMode().toString()));
        if (uiForm.isMultiPart() && (uiForm.isCreateMode() || uiForm.isEditMode())) {
            form.setMultiPart(true);
            form.setMaxSize(this.getApplication().getApplicationSettings().getDefaultMaximumUploadSize());
        }

        super.addComponents(form);

        final WebMarkupContainer script = new WebMarkupContainer("selectscript");
        this.add(script);
        script.setVisible(uiForm.isCreateMode() || uiForm.isEditMode() || uiForm.isSearchMode());
        FormPage.updateFormContainer(this, form, uiForm);
    }

    /**
     * Method used to update the Form Container.
     *
     * @param _page page
     * @param _form formcontainer
     * @param _uiForm model
     * @throws EFapsException on error
     */
    public static void updateFormContainer(final Page _page,
                                           final FormContainer _form,
                                           final UIForm _uiForm)
        throws EFapsException
    {

        if (!_uiForm.isInitialized()) {
            _uiForm.execute();
        }
        // the hidden cells must be marked as not added yet.
        for (final IHidden cell : _uiForm.getHidden()) {
            cell.setAdded(false);
        }
        int i = 0;
        final RepeatingView elementRepeater = new RepeatingView("elementRepeater");
        _form.add(elementRepeater);
        for (final Element element : _uiForm.getElements()) {
            switch (element.getType()) {
                case FORM:
                    elementRepeater.add(new FormPanel(elementRepeater.newChildId(), _page, Model.of(_uiForm),
                                    (FormElement) element.getElement(), _form));
                    break;
                case HEADING:
                    final UIHeading headingmodel = (UIHeading) element.getElement();
                    elementRepeater.add(new HeadingPanel(elementRepeater.newChildId(), Model.of(headingmodel)));
                    break;
                case TABLE:
                    i++;
                    final UIFieldTable fieldTable = (UIFieldTable) element.getElement();
                    fieldTable.setTableId(i);
                    final TablePanel table = new TablePanel(elementRepeater.newChildId(),
                                    Model.of(fieldTable), _page);
                    final HeaderPanel header = new HeaderPanel(elementRepeater.newChildId(), table);
                    elementRepeater.add(header);
                    elementRepeater.add(table);
                    break;
                case GRID:
                    final UIFieldGrid grid = (UIFieldGrid) element.getElement();
                    final GridXPanel gridPanel = new GridXPanel(elementRepeater.newChildId(), Model.of(grid));
                    elementRepeater.add(gridPanel);
                    break;
                case CLASSIFICATION:
                    elementRepeater.add(new ClassificationPathPanel(elementRepeater.newChildId(),
                                    Model.of((UIClassification) element.getElement())));
                    break;
                case STRUCBRWS:
                    i++;
                    final UIFieldStructurBrowser strBrwsr = (UIFieldStructurBrowser) element.getElement();
                    strBrwsr.setTableId(i);
                    final StructurBrowserTreeTablePanel strucBrws = new StructurBrowserTreeTablePanel(
                                    elementRepeater.newChildId(), Model.of(strBrwsr));
                    elementRepeater.add(strucBrws);
                    break;
                case SUBFORM:
                    final UIFieldForm uiFieldForm = (UIFieldForm) element.getElement();
                    if (!uiFieldForm.isInitialized()) {
                        if (uiFieldForm.getInstance() == null && uiFieldForm.isCreateMode()) {
                            uiFieldForm.setInstanceKey(_uiForm.getInstanceKey());
                        }
                        uiFieldForm.execute();
                    }
                    final List<Element> elements = uiFieldForm.getElements();
                    for (final Element subElement : elements) {
                        if (subElement.getType().equals(ElementType.FORM)) {
                            elementRepeater.add(new FormPanel(elementRepeater.newChildId(), _page, Model.of(
                                            uiFieldForm), (FormElement) subElement.getElement(), _form));
                        } else if (subElement.getType().equals(ElementType.HEADING)) {
                            elementRepeater.add(new HeadingPanel(elementRepeater.newChildId(), Model.of(
                                            (UIHeading) subElement.getElement())));
                        } else if (subElement.getType().equals(ElementType.TABLE)) {
                            i++;
                            final UIFieldTable fieldTable2 = (UIFieldTable) subElement.getElement();
                            fieldTable2.setTableId(i);
                            final TablePanel table2 = new TablePanel(elementRepeater.newChildId(), Model.of(
                                            fieldTable2), _page);
                            final HeaderPanel header2 = new HeaderPanel(elementRepeater.newChildId(), table2);
                            elementRepeater.add(header2);
                            elementRepeater.add(table2);
                        }
                    }
                    break;
                default:
                    break;
            }
        }
    }

    @Override
    public void renderHead(final IHeaderResponse _response)
    {
        super.renderHead(_response);
        _response.render(AbstractEFapsHeaderItem.forCss(FormPage.CSS));
    }
}


/*
 * Copyright 2015-2016 Hewlett-Packard Development Company, L.P.
 * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
 */

package com.hp.autonomy.hod.client.api.userstore.group;

import com.hp.autonomy.hod.client.api.authentication.EntityType;
import com.hp.autonomy.hod.client.api.authentication.TokenType;
import com.hp.autonomy.hod.client.api.resource.ResourceIdentifier;
import com.hp.autonomy.hod.client.config.HodServiceConfig;
import com.hp.autonomy.hod.client.config.Requester;
import com.hp.autonomy.hod.client.error.HodErrorException;
import com.hp.autonomy.hod.client.token.TokenProxy;
import com.hp.autonomy.hod.client.util.MultiMap;
import com.hp.autonomy.hod.client.util.StatusResponse;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;

public class GroupsServiceImpl implements GroupsService {
    private final GroupsBackend backend;
    private final Requester<?, TokenType.Simple> requester;

    public GroupsServiceImpl(final HodServiceConfig<?, TokenType.Simple> config) {
        backend = config.getRestAdapter().create(GroupsBackend.class);
        requester = config.getRequester();
    }

    @Override
    public List<Group> list(final ResourceIdentifier userStore) throws HodErrorException {
        return requester.makeRequest(ListGroupsResponse.class, listBackendCaller(userStore)).getGroups();
    }

    @Override
    public List<Group> list(final TokenProxy<?, TokenType.Simple> tokenProxy, final ResourceIdentifier userStore) throws HodErrorException {
        return requester.makeRequest(tokenProxy, ListGroupsResponse.class, listBackendCaller(userStore)).getGroups();
    }

    @Override
    public GroupInfo getInfo(final ResourceIdentifier userStore, final String name) throws HodErrorException {
        return requester.makeRequest(GroupInfo.class, getInfoBackendCaller(userStore, name));
    }

    @Override
    public GroupInfo getInfo(final TokenProxy<?, TokenType.Simple> tokenProxy, final ResourceIdentifier userStore, final String name) throws HodErrorException {
        return requester.makeRequest(tokenProxy, GroupInfo.class, getInfoBackendCaller(userStore, name));
    }

    @Override
    public CreateGroupResponse create(final ResourceIdentifier userStore, final String name) throws HodErrorException {
        return requester.makeRequest(CreateGroupResponse.class, createBackendCaller(userStore, Collections.<String, Object>emptyMap(), name));
    }

    @Override
    public CreateGroupResponse create(final TokenProxy<?, TokenType.Simple> tokenProxy, final ResourceIdentifier userStore, final String name) throws HodErrorException {
        return requester.makeRequest(tokenProxy, CreateGroupResponse.class, createBackendCaller(userStore, Collections.<String, Object>emptyMap(), name));
    }

    @Override
    public CreateGroupResponse createWithHierarchy(final ResourceIdentifier userStore, final String name, final List<String> parents, final List<String> children) throws HodErrorException {
        return requester.makeRequest(CreateGroupResponse.class, createBackendCaller(userStore, buildHierarchyParameters(parents, children), name));
    }

    @Override
    public CreateGroupResponse createWithHierarchy(final TokenProxy<?, TokenType.Simple> tokenProxy, final ResourceIdentifier userStore, final String name, final List<String> parents, final List<String> children) throws HodErrorException {
        return requester.makeRequest(tokenProxy, CreateGroupResponse.class, createBackendCaller(userStore, buildHierarchyParameters(parents, children), name));
    }

    @Override
    public void delete(final ResourceIdentifier userStore, final String name) throws HodErrorException {
        requester.makeRequest(StatusResponse.class, deleteBackendCaller(userStore, name));
    }

    @Override
    public void delete(final TokenProxy<?, TokenType.Simple> tokenProxy, final ResourceIdentifier userStore, final String name) throws HodErrorException {
        requester.makeRequest(tokenProxy, StatusResponse.class, deleteBackendCaller(userStore, name));
    }

    @Override
    public void assignUser(final ResourceIdentifier userStore, final String groupName, final UUID userUuid) throws HodErrorException {
        requester.makeRequest(StatusResponse.class, assignBackendCaller(userStore, groupName, userUuid));
    }

    @Override
    public void assignUser(final TokenProxy<?, TokenType.Simple> tokenProxy, final ResourceIdentifier userStore, final String groupName, final UUID userUuid) throws HodErrorException {
        requester.makeRequest(tokenProxy, StatusResponse.class, assignBackendCaller(userStore, groupName, userUuid));
    }

    @Override
    public void removeUser(final ResourceIdentifier userStore, final String groupName, final UUID userUuid) throws HodErrorException {
        requester.makeRequest(StatusResponse.class, removeBackendCaller(userStore, groupName, userUuid));
    }

    @Override
    public void removeUser(final TokenProxy<?, TokenType.Simple> tokenProxy, final ResourceIdentifier userStore, final String groupName, final UUID userUuid) throws HodErrorException {
        requester.makeRequest(tokenProxy, StatusResponse.class, removeBackendCaller(userStore, groupName, userUuid));
    }

    @Override
    public void link(final ResourceIdentifier userStore, final String parent, final String child) throws HodErrorException {
        requester.makeRequest(StatusResponse.class, linkBackendCaller(userStore, parent, child));
    }

    @Override
    public void link(final TokenProxy<?, TokenType.Simple> tokenProxy, final ResourceIdentifier userStore, final String parent, final String child) throws HodErrorException {
        requester.makeRequest(tokenProxy, StatusResponse.class, linkBackendCaller(userStore, parent, child));
    }

    @Override
    public void unlink(final ResourceIdentifier userStore, final String parent, final String child) throws HodErrorException {
        requester.makeRequest(StatusResponse.class, unlinkBackendCaller(userStore, parent, child));
    }

    @Override
    public void unlink(final TokenProxy<?, TokenType.Simple> tokenProxy, final ResourceIdentifier userStore, final String parent, final String child) throws HodErrorException {
        requester.makeRequest(tokenProxy, StatusResponse.class, unlinkBackendCaller(userStore, parent, child));
    }

    // Build the hierarchy parameters map for a create group request
    private Map<String, Object> buildHierarchyParameters(final List<String> parents, final List<String> children) {
        final MultiMap<String, Object> parameters = new MultiMap<>();

        if (parents != null) {
            for (final String parent : parents) {
                parameters.put("parents", parent);
            }
        }

        if (children != null) {
            for (final String child : children) {
                parameters.put("children", child);
            }
        }

        return parameters;
    }

    private Requester.BackendCaller<EntityType, TokenType.Simple> listBackendCaller(final ResourceIdentifier userStore) {
        return token -> backend.list(token, userStore);
    }

    private Requester.BackendCaller<EntityType, TokenType.Simple> getInfoBackendCaller(final ResourceIdentifier userStore, final String group) {
        return token -> backend.getInfo(token, userStore, group);
    }

    private Requester.BackendCaller<EntityType, TokenType.Simple> createBackendCaller(final ResourceIdentifier userStore, final Map<String, Object> hierarchyParameters, final String group) {
        return token -> backend.create(token, userStore, group, hierarchyParameters);
    }

    private Requester.BackendCaller<EntityType, TokenType.Simple> deleteBackendCaller(final ResourceIdentifier userStore, final String group) {
        return token -> backend.delete(token, userStore, group);
    }

    private Requester.BackendCaller<EntityType, TokenType.Simple> assignBackendCaller(final ResourceIdentifier userStore, final String group, final UUID userUuid) {
        return token -> backend.assignUser(token, userStore, group, userUuid.toString());
    }

    private Requester.BackendCaller<EntityType, TokenType.Simple> removeBackendCaller(final ResourceIdentifier userStore, final String group, final UUID userUuid) {
        return token -> backend.removeUser(token, userStore, group, userUuid.toString());
    }

    private Requester.BackendCaller<EntityType, TokenType.Simple> linkBackendCaller(final ResourceIdentifier userStore, final String parent, final String child) {
        return token -> backend.link(token, userStore, parent, child);
    }

    private Requester.BackendCaller<EntityType, TokenType.Simple> unlinkBackendCaller(final ResourceIdentifier userStore, final String parent, final String child) {
        return token -> backend.unlink(token, userStore, parent, child);
    }
}


package com.buschmais.jqassistant.plugin.xml.api.scanner;

import java.io.IOException;
import java.io.InputStream;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import com.buschmais.jqassistant.plugin.common.api.scanner.filesystem.FileResource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Provides functionality to verify if a file resource represents a specific XML
 * document, e.g. by checking for the presence of a root element.
 */
public final class XMLFileFilter {

    private static XMLInputFactory factory ;

    private static final Logger LOGGER = LoggerFactory.getLogger(XMLFileFilter.class);

    static {
        factory = XMLInputFactory.newInstance();
        factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
    }

    /**
     * Private constructor.
     */
    private XMLFileFilter() {
    }

    /**
     * Matches a file resource for being an XML file with a specific root
     * element.
     *
     * @param fileResource
     *            The file resource.
     * @param path
     *            The path of the file resource.
     * @param expectedRootElement
     *            The expected local name of the root element.
     * @return `true` If the file is an XML file and contains the
     *         expected root element.
     * @throws IOException
     *             If the file resource cannot be read.
     */
    public static boolean rootElementMatches(FileResource fileResource, String path, String expectedRootElement) throws IOException {
        try (InputStream stream = fileResource.createStream()) {
            XMLStreamReader reader = factory.createXMLStreamReader(stream);
            while (reader.hasNext()) {
                int event = reader.next();
                switch (event) {
                    case XMLStreamConstants.START_ELEMENT:
                        String rootElement = reader.getLocalName();
                        return expectedRootElement.equals(rootElement);
                }
            }
        } catch (XMLStreamException e) {
            LOGGER.warn("Cannot parse XML file '{}'.", path);
        }
        return false;

    }

    public static Boolean rootElementMatches(FileResource fileResource, String path, String expectedRootElement,
                                             String expectedNameSpace) throws IOException {
        try (InputStream stream = fileResource.createStream()) {
            XMLStreamReader reader = factory.createXMLStreamReader(stream);
            while (reader.hasNext()) {
                int event = reader.next();
                switch (event) {
                    case XMLStreamConstants.START_ELEMENT:
                        String rootElement = reader.getLocalName();
                        int namespaces = reader.getNamespaceCount();
                        if (expectedRootElement.equals(rootElement)) {
                            // In case of Java 8 -> for-loops are faster!
                            for (int i = 0; i < namespaces; i++) {
                                String namespaceURI = reader.getNamespaceURI(i);
                                if (expectedNameSpace.equals(namespaceURI)) {
                                    return true;
                                }
                            }
                        }
                        return false;
                }
            }
        } catch (XMLStreamException e) {
            LOGGER.warn("Cannot parse XML file '{}'.", path);
        }
        return false;
    }
}


package org.javastack.preferences.example;

import java.util.prefs.Preferences;

public class Example {
	/**
	 * Simple Test
	 */
	public static void main(final String[] args) throws Throwable {
		final Preferences config = Preferences.systemNodeForPackage(Example.class);
		System.out.println(config.get("mykey", "my-default-value1"));
		System.out.println(config.get("mykey2", "my-default-value2"));
		System.out.println(config.get("other.key", "my-default-value3"));
		System.out.println(config.get("urlbase", "my-default-value4"));
		System.out.println(config.get("urlsearch", "my-default-value5"));
	}
}


package org.javastack.preferences;

import org.javastack.classloadermap.ClassLoaderMap;
import org.javastack.mapexpression.mapper.Mapper;

class CustomMapper implements Mapper {
	private static final CustomMapper singleton = new CustomMapper();

	private CustomMapper() {
	}

	/**
	 * Map PropertyName in format "keyName:default-value" to
	 * {@link ClassLoaderMap#get(ClassLoader, String, String)} or {@link System#getProperty(String)} or
	 * {@code default-value}
	 *
	 * @param propName string in format keyName[:default-value]
	 * @return maped value
	 */
	@Override
	public String map(final String propName) {
		if (propName == null)
			return null;
		String keyName = propName, defValue = null;
		final int offsetDefault = propName.indexOf(':');
		if (offsetDefault != -1) {
			keyName = propName.substring(0, offsetDefault);
			defValue = propName.substring(offsetDefault + 1);
		}
		final ClassLoader ctxLoader = Thread.currentThread().getContextClassLoader();
		String value = ClassLoaderMap.get(ctxLoader, keyName, null);
		if (value == null) {
			value = System.getProperty(propName, defValue);
		}
		return value;
	}

	public static CustomMapper getInstance() {
		return singleton;
	}
}