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

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import com.buschmais.jqassistant.core.scanner.api.ScannerContext;
import com.buschmais.jqassistant.plugin.common.api.model.FileContainerDescriptor;
import com.buschmais.jqassistant.plugin.common.api.model.FileDescriptor;

/**
 * A file resolver strategy for file containers.
 */
public class ContainerFileResolver extends AbstractFileResolver {

    private Map<String, FileDescriptor> requiredFiles;

    private Map<String, FileDescriptor> containedFiles;

    private FileContainerDescriptor fileContainerDescriptor;

    public ContainerFileResolver(FileContainerDescriptor fileContainerDescriptor) {
        this.fileContainerDescriptor = fileContainerDescriptor;
        this.containedFiles = getCache(fileContainerDescriptor.getContains());
        this.requiredFiles = getCache(fileContainerDescriptor.getRequires());
    }

    @Override
    public <D extends FileDescriptor> D require(String requiredPath, String containedPath, Class<D> type, ScannerContext context) {
        final FileDescriptor fileDescriptor = containedFiles.get(containedPath);
        D result;
        if (fileDescriptor != null) {
            result = getOrCreateAs(containedPath, type, path -> fileDescriptor, context);
            containedFiles.put(containedPath, result);
        } else {
            result = getOrCreateAs(containedPath, type, path -> requiredFiles.get(containedPath), context);
            requiredFiles.put(containedPath, result);
        }
        return result;
    }

    @Override
    public <D extends FileDescriptor> D match(String containedPath, Class<D> type, ScannerContext context) {
        FileDescriptor fileDescriptor = requiredFiles.remove(containedPath);
        return getOrCreateAs(containedPath, type, path -> fileDescriptor, context);
    }

    /**
     * Flush the caches to the store.
     */
    public void flush() {
        createHierarchy();
        sync(fileContainerDescriptor.getRequires(), requiredFiles);
        sync(fileContainerDescriptor.getContains(), containedFiles);
    }

    /**
     * Sync the given target collection with the new state from the cache map.
     *
     * @param target The target collection.
     * @param after  The new state to sync to.
     */
    private void sync(Collection<FileDescriptor> target, Map<String, FileDescriptor> after) {
        Map<String, FileDescriptor> before = getCache(target);
        Map<String, FileDescriptor> all = new HashMap<>();
        all.putAll(before);
        all.putAll(after);
        for (Map.Entry<String, FileDescriptor> entry : all.entrySet()) {
            String key = entry.getKey();
            FileDescriptor fileDescriptor = entry.getValue();
            boolean hasBefore = before.containsKey(key);
            boolean hasAfter = after.containsKey(key);
            if (hasBefore && !hasAfter) {
                target.remove(fileDescriptor);
            } else if (!hasBefore && hasAfter) {
                target.add(fileDescriptor);
            }
        }
    }

    /**
     * Creates cache map from the given collection of file descriptors.
     *
     * @param fileDescriptors The collection of file descriptors.
     * @return The cache map.
     */
    private Map<String, FileDescriptor> getCache(Iterable<FileDescriptor> fileDescriptors) {
        Map<String, FileDescriptor> cache = new HashMap<>();
        for (FileDescriptor fileDescriptor : fileDescriptors) {
            cache.put(fileDescriptor.getFileName(), fileDescriptor);
        }
        return cache;
    }

    /**
     * Build the hierarchy of the container entries, i.e. add contains relations
     * from containers to their children.
     */
    private void createHierarchy() {
        for (Map.Entry<String, FileDescriptor> entry : containedFiles.entrySet()) {
            String relativePath = entry.getKey();
            FileDescriptor fileDescriptor = entry.getValue();
            int separatorIndex = relativePath.lastIndexOf('/');
            if (separatorIndex != -1) {
                String parentName = relativePath.substring(0, separatorIndex);
                FileDescriptor parentDescriptor = containedFiles.get(parentName);
                if (parentDescriptor instanceof FileContainerDescriptor) {
                    ((FileContainerDescriptor) parentDescriptor).getContains().add(fileDescriptor);
                }
            }
        }
    }

    /**
     * Adds a file to the container.
     *
     * @param path           The path of the file.
     * @param fileDescriptor The file descriptor.
     */
    public void put(String path, FileDescriptor fileDescriptor) {
        containedFiles.put(path, fileDescriptor);
    }

    /**
     * Returns the size of the container.
     *
     * @return The size of the container.
     */
    public int size() {
        return containedFiles.size();
    }
}


/*
 * 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 com.groupon.mesos.util;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.List;

import com.google.common.collect.ImmutableList;

public final class NetworkUtil
{
    private NetworkUtil()
    {
        throw new AssertionError("do not instantiate");
    }

    /**
     * Find an unused port.
     */
    public static int findUnusedPort() throws IOException
    {
        int port;

        try (ServerSocket socket = new ServerSocket()) {
            socket.bind(new InetSocketAddress(0));
            port = socket.getLocalPort();
        }

        return port;
    }

    //
    // ========================================================================
    //
    // This code was taken from https://github.com/airlift/airlift/blob/master/node/src/main/java/io/airlift/node/NodeInfo.java
    //
    // ========================================================================
    //

    public static String findPublicIp()
        throws UnknownHostException
    {
        // Check if local host address is a good v4 address
        final InetAddress localAddress = InetAddress.getLocalHost();
        if (isV4Address(localAddress) && getGoodAddresses().contains(localAddress)) {
            return localAddress.getHostAddress();
        }

        // check all up network interfaces for a good v4 address
        for (final InetAddress address : getGoodAddresses()) {
            if (isV4Address(address)) {
                return address.getHostAddress();
            }
        }

        // just return the local host address
        // it is most likely that this is a disconnected developer machine
        return localAddress.getHostAddress();
    }

    private static List<InetAddress> getGoodAddresses()
    {
        final ImmutableList.Builder<InetAddress> list = ImmutableList.builder();
        for (final NetworkInterface networkInterface : getGoodNetworkInterfaces()) {
            for (final InetAddress address : Collections.list(networkInterface.getInetAddresses())) {
                if (isGoodAddress(address)) {
                    list.add(address);
                }
            }
        }
        return list.build();
    }

    private static List<NetworkInterface> getGoodNetworkInterfaces()
    {
        try {
            final ImmutableList.Builder<NetworkInterface> builder = ImmutableList.builder();
            for (final NetworkInterface networkInterface : Collections.list(NetworkInterface.getNetworkInterfaces())) {
                try {
                    if (!networkInterface.isLoopback() && networkInterface.isUp()) {
                        builder.add(networkInterface);
                    }
                }
                catch (final SocketException se) {
                    continue; // Ignore that network interface.
                }
            }
            return builder.build();
        }
        catch (final SocketException se) {
            // Return empty list.
            return ImmutableList.of();
        }
    }

    private static boolean isV4Address(final InetAddress address)
    {
        return address.getAddress().length == 4;
    }

    private static boolean isGoodAddress(final InetAddress address)
    {
        return !address.isAnyLocalAddress() &&
            !address.isLoopbackAddress() &&
            !address.isMulticastAddress();
    }
}


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

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.wicket.request.IRequestParameters;
import org.apache.wicket.request.IWritableRequestParameters;
import org.apache.wicket.util.string.StringValue;
import org.efaps.db.Context;
import org.efaps.ui.wicket.util.ParameterUtil;
import org.efaps.util.EFapsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * TODO comment!
 *
 * @author The eFaps Team
 * @version $Id$
 */
public class EFapsRequestParametersAdapter
    implements IWritableRequestParameters
{
    /**
     * Logger for this class.
     */
    private static final Logger LOG = LoggerFactory.getLogger(EFapsRequestParametersAdapter.class);

    /**
     * Mapping of the parameters.
     */
    private final Map<String, List<StringValue>> parameters = new HashMap<String, List<StringValue>>();

    /**
     * @param _parameters paramters to work on
     */
    public EFapsRequestParametersAdapter(final IRequestParameters... _parameters)
    {
        for (final IRequestParameters p : _parameters) {
            for (final String name : p.getParameterNames()) {
                final List<StringValue> values = p.getParameterValues(name);
                this.parameters.put(name, values);
                EFapsRequestParametersAdapter.LOG.trace("adding parameter from request. Name: '{}', value: {}", name,
                                values);
            }
        }
    }

    /**
     * Returns immutable set of all available parameter names.
     * @return list of parameter names
     */
    @Override
    public Set<String> getParameterNames()
    {
        return Collections.unmodifiableSet(this.parameters.keySet());
    }

    /**
     * Returns single value for parameter with specified name. This method always returns non-null
     * result even if the parameter does not exist.
     *
     * @param _name parameter name
     * @return {@link StringValue} wrapping the actual value
     */
    @Override
    public StringValue getParameterValue(final String _name)
    {
        final List<StringValue> values = this.parameters.get(_name);
        return (values != null && !values.isEmpty()) ? values.get(0)
                        : StringValue.valueOf((String) null);
    }

    /**
     * Returns list of values for parameter with specified name. If the parameter does not exist
     * this method returns null
     *
     * @param _name parameter name
     * @return list of all values for given parameter or null if parameter does not
     *         exist
     */
    @Override
    public List<StringValue> getParameterValues(final String _name)
    {
        final List<StringValue> values = this.parameters.get(_name);
        return values != null ? Collections.unmodifiableList(values) : null;
    }

    /**
     * Sets the values for given parameter.
     *
     * @param _name parameter name
     * @param _value values
     */
    @Override
    public void setParameterValues(final String _name,
                                   final List<StringValue> _value)
    {
        this.parameters.put(_name, _value);
        try {
            Context.getThreadContext().getParameters().put(_name, ParameterUtil.stringValues2Array(_value));
        } catch (final EFapsException e) {
            EFapsRequestParametersAdapter.LOG.error("Could not set parameter '{}' in Context.", _name);
        }
    }

    /**
     * Sets value for given key.
     *
     * @param _key key for the value
     * @param _value value
     */
    public void setParameterValue(final String _key,
                                  final String _value)
    {
        final List<StringValue> list = new ArrayList<StringValue>(1);
        list.add(StringValue.valueOf(_value));
        setParameterValues(_key, list);
    }

    /**
     * Adds a value for given key.
     *
     * @param _key key for the value
     * @param _value value
     */
    public void addParameterValue(final String _key,
                                  final String _value)
    {
        List<StringValue> list = this.parameters.get(_key);
        if (list == null) {
            list = new ArrayList<StringValue>(1);
            this.parameters.put(_key, list);
        }
        list.add(StringValue.valueOf(_value));
        try {
            Context.getThreadContext().getParameters().put(_key, ParameterUtil.stringValues2Array(list));
        } catch (final EFapsException e) {
            EFapsRequestParametersAdapter.LOG.error("Could not add parameter '{}' in Context.", _key);
        }
    }

    /**
     * Clears all parameters.
     */
    @Override
    public void reset()
    {
        this.parameters.clear();
    }
}


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

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

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import org.efaps.ui.wicket.behaviors.dojo.AutoCompleteBehavior;
import org.efaps.ui.wicket.behaviors.dojo.AutoCompleteBehavior.Type;
import org.efaps.ui.wicket.util.Configuration;
import org.efaps.ui.wicket.util.Configuration.ConfigAttribute;
import org.efaps.util.EFapsException;

/**
 * TODO comment!
 *
 * @author The eFaps Team
 */
public class AutoCompleteSettings
    implements Serializable
{

    /**
     * Editvalue definition.
     */
    public enum EditValue
    {
        /** Use the ID. */
        ID,
        /** Use the OID. (Default) */
        OID,
        /** Don't set the value for edit. */
        NONE;
    }

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    /**
     * Show the down arrow.
     */
    private boolean hasDownArrow = false;

    /**
     * Minimum input length for starting the GET request.
     */
    private int minInputLength = Configuration.getAttributeAsInteger(ConfigAttribute.AUTOC_MININPUT);

    /**
     * Max length for the Choice value.
     */
    private int maxChoiceLength = Configuration.getAttributeAsInteger(ConfigAttribute.AUTOC_MAXCHOICE);

    /**
     * Max length for the Value value.
     */
    private int maxValueLength = Configuration.getAttributeAsInteger(ConfigAttribute.AUTOC_MAXVALUE);

    /**
     * Max Result shown in the Interface. To deactivate set to -1.
     */
    private int maxResult = Configuration.getAttributeAsInteger(ConfigAttribute.AUTOC_MAXRESULT);

    /**
     * Name of the parameter.
     */
    private String paramName = Configuration.getAttribute(ConfigAttribute.AUTOC_PARAMNAME);

    /**
     * Delay in milliseconds between when user types something
     * and we start searching based on that value.
     */
    private int searchDelay =  Configuration.getAttributeAsInteger(ConfigAttribute.AUTOC_SEARCHDELAY);

    /**
     * Edit value definition.
     */
    private EditValue value4Edit = EditValue.OID;

    /**
     * Name of the extra parameters that will be send via GET.
     */
    private final Set<String> extraParameters = new HashSet<String>();

    /**
     * If required "AutoComplete" will be rendered, else "AutoSuggestion".
     */
    private boolean required = true;

    /**
     * The AutoComplete Type.
     */
    private AutoCompleteBehavior.Type autoType;

    /** The field configuration. */
    private FieldConfiguration fieldConfiguration;

    /**
     * Instantiates a new auto complete settings.
     */
    public AutoCompleteSettings()
    {
    }

    /**
     * Instantiates a new auto complete settings.
     *
     * @param _fieldConfiguration the field configuration
     */
    public AutoCompleteSettings(final FieldConfiguration _fieldConfiguration)
    {
        this.fieldConfiguration = _fieldConfiguration;
    }

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

    /**
     * Setter method for instance variable {@link #hasDownArrow}.
     *
     * @param _hasDownArrow value for instance variable {@link #hasDownArrow}
     */
    public void setHasDownArrow(final boolean _hasDownArrow)
    {
        this.hasDownArrow = _hasDownArrow;
    }

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

    /**
     * Setter method for instance variable {@link #minInputLength}.
     *
     * @param _minInputLength value for instance variable {@link #minInputLength}
     */
    public void setMinInputLength(final int _minInputLength)
    {
        this.minInputLength = _minInputLength;
    }

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

    /**
     * Setter method for instance variable {@link #searchDelay}.
     *
     * @param _searchDelay value for instance variable {@link #searchDelay}
     */
    public void setSearchDelay(final int _searchDelay)
    {
        this.searchDelay = _searchDelay;
    }

    /**
     * Getter method for the instance variable {@link #parameterName}.
     *
     * @return value of instance variable {@link #parameterName}
     */
    public String getParamName()
    {
        return this.paramName;
    }

    /**
     * Setter method for instance variable {@link #parameterName}.
     *
     * @param _parameterName value for instance variable {@link #parameterName}
     */
    public void setParamName(final String _parameterName)
    {
        this.paramName = _parameterName;
    }

    /**
     * Getter method for the instance variable {@link #extraParameters}.
     *
     * @return value of instance variable {@link #extraParameters}
     */
    public Set<String> getExtraParameters()
    {
        return this.extraParameters;
    }

    /**
     * Getter method for the instance variable {@link #fieldName}.
     *
     * @return value of instance variable {@link #fieldName}
     * @throws EFapsException on error
     */
    public String getFieldName()
    {
        return getFieldConfiguration().getName();
    }

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

    /**
     * Setter method for instance variable {@link #maxChoiceLength}.
     *
     * @param _maxChoiceLength value for instance variable {@link #maxChoiceLength}
     */
    public void setMaxChoiceLength(final int _maxChoiceLength)
    {
        this.maxChoiceLength = _maxChoiceLength;
    }

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

    /**
     * Setter method for instance variable {@link #maxValueLength}.
     *
     * @param _maxValueLength value for instance variable {@link #maxValueLength}
     */
    public void setMaxValueLength(final int _maxValueLength)
    {
        this.maxValueLength = _maxValueLength;
    }

    /**
     * Getter method for the instance variable {@link #value4Edit}.
     *
     * @return value of instance variable {@link #value4Edit}
     */
    public EditValue getValue4Edit()
    {
        return this.value4Edit;
    }

    /**
     * Setter method for instance variable {@link #value4Edit}.
     *
     * @param _value4Edit value for instance variable {@link #value4Edit}
     */
    public void setValue4Edit(final EditValue _value4Edit)
    {
        this.value4Edit = _value4Edit;
    }

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

    /**
     * Setter method for instance variable {@link #maxResult}.
     *
     * @param _maxResult value for instance variable {@link #maxResult}
     */
    public void setMaxResult(final int _maxResult)
    {
        this.maxResult = _maxResult;
    }

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

    /**
     * Setter method for instance variable {@link #required}.
     *
     * @param _required value for instance variable {@link #required}
     */
    public void setRequired(final boolean _required)
    {
        this.required = _required;
    }

    /**
     * Getter method for the instance variable {@link #autoType}.
     *
     * @return value of instance variable {@link #autoType}
     */
    public AutoCompleteBehavior.Type getAutoType()
    {
        if (this.autoType == null) {
            if (isRequired()) {
                setAutoType(Type.COMPLETE);
            } else {
                setAutoType(Type.SUGGESTION);
            }
        }
        return this.autoType;
    }

    /**
     * Setter method for instance variable {@link #autoType}.
     *
     * @param _autoType value for instance variable {@link #autoType}
     */
    public void setAutoType(final AutoCompleteBehavior.Type _autoType)
    {
        this.autoType = _autoType;
    }

    /**
     * Gets the field configuration.
     *
     * @return the field configuration
     */
    public FieldConfiguration getFieldConfiguration()
    {
        return this.fieldConfiguration;
    }

    /**
     * Sets the field configuration.
     *
     * @param _fieldConfiguration the new field configuration
     */
    public void setFieldConfiguration(final FieldConfiguration _fieldConfiguration)
    {
        this.fieldConfiguration = _fieldConfiguration;
    }
}


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

package org.efaps.ui.wicket.models.field.factories;

import java.util.List;

import org.apache.wicket.Component;
import org.apache.wicket.model.Model;
import org.efaps.admin.datamodel.IEnum;
import org.efaps.admin.datamodel.ui.BitEnumUI;
import org.efaps.ui.wicket.components.values.CheckBoxField;
import org.efaps.ui.wicket.models.field.AbstractUIField;
import org.efaps.ui.wicket.util.EnumUtil;
import org.efaps.util.EFapsException;

/**
 * TODO comment!
 *
 * @author The eFaps Team
 * @version $Id: BitEnumUIFactory.java 11692 2014-01-14 19:54:16Z jan@moxter.net
 *          $
 */
// CHECKSTYLE:OFF
public final class BitEnumUIFactory
    extends AbstractUIFactory
// CHECKSTYLE:ON
{

    /**
     * Factory Instance.
     */
    private static BitEnumUIFactory FACTORY;

    /**
     * Singelton.
     */
    private BitEnumUIFactory()
    {
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    @Override
    public Component getEditable(final String _wicketId,
                                 final AbstractUIField _abstractUIField)
        throws EFapsException
    {
        Component ret = null;
        if (applies(_abstractUIField)) {
            ret = new CheckBoxField(_wicketId, Model.of(_abstractUIField),
                            (List<Object>) _abstractUIField.getValue().getEditValue(
                                            _abstractUIField.getParent().getMode()),
                            _abstractUIField.getFieldConfiguration());
        }
        return ret;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean applies(final AbstractUIField _abstractUIField)
        throws EFapsException
    {
        return _abstractUIField.getValue().getUIProvider() instanceof BitEnumUI;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected String getReadOnlyValue(final AbstractUIField _uiField)
        throws EFapsException
    {
        final StringBuilder bldr = new StringBuilder();
        final Object valueTmp = _uiField.getValue().getReadOnlyValue(_uiField.getParent().getMode());
        if (valueTmp instanceof List) {
            boolean first = true;
            for (final Object obj : (List<?>) valueTmp) {
                if (first) {
                    first = false;
                } else {
                    bldr.append(", ");
                }
                bldr.append(EnumUtil.getUILabel((IEnum) obj));
            }
        }
        final String ret = bldr.toString();
        return ret;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getKey()
    {
        return BitEnumUIFactory.class.getName();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getPickListValue(final AbstractUIField _uiField)
        throws EFapsException
    {
        return getReadOnlyValue(_uiField);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Comparable<String> getCompareValue(final AbstractUIField _uiField)
        throws EFapsException
    {
        return getReadOnlyValue(_uiField);
    }

    /**
     * @return IComponentFactory instance
     */
    public static IComponentFactory get()
    {
        if (BitEnumUIFactory.FACTORY == null) {
            BitEnumUIFactory.FACTORY = new BitEnumUIFactory();
        }
        return BitEnumUIFactory.FACTORY;
    }
}


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

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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.efaps.admin.access.AccessTypeEnums;
import org.efaps.admin.datamodel.Type;
import org.efaps.admin.event.EventType;
import org.efaps.admin.event.Parameter.ParameterValues;
import org.efaps.admin.event.Return;
import org.efaps.admin.event.Return.ReturnValues;
import org.efaps.admin.ui.AbstractCommand;
import org.efaps.admin.ui.AbstractUserInterfaceObject.TargetMode;
import org.efaps.admin.ui.Command;
import org.efaps.admin.ui.Menu;
import org.efaps.admin.ui.field.Field;
import org.efaps.db.AbstractPrintQuery;
import org.efaps.db.Context;
import org.efaps.db.Instance;
import org.efaps.ui.wicket.models.field.IHidden;
import org.efaps.util.EFapsException;
import org.efaps.util.RandomUtil;
import org.efaps.util.cache.CacheReloadException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * TODO comment!
 *
 * @author The eFaps Team
 */
public abstract class AbstractUIPageObject
    extends AbstractUIObject
    implements ICmdUIObject
{

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

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

    /**
     * Mapping between the id used for the interface and an oid from eFaps.
     */
    private final Map<String, String> uiID2Oid = new HashMap<>();

    /**
     * Random that can be used for the id in the userinterface and stored in
     * {@link #uiID2Oid}.
     */
    private final Random random = new Random();

    /**
     * A list of cells that will be rendered hidden in tht page.
     */
    private final List<IHidden> hidden = new ArrayList<>();

    /**
     * Map of instance with access definition.
     */
    private final Map<Instance, Boolean> accessMap = new HashMap<>();

    /**
     * This instance variable stores the UUID of the CommandAbstract that is the
     * target of this Page.
     */
    private UUID targetCmdUUID;

    /**
     * Stores a wizard object.
     */
    private UIWizardObject wizard;

    /**
     * Is this uiobject used in a wizard call.
     */
    private boolean partOfWizardCall;

    /**
     * Should the target of this object render a butto for revise.
     */
    private boolean targetCmdRevise;

    /**
     * Should a revise button be rendered.
     */
    private boolean renderRevise = false;

    /**
     * Must a file be shown that is returned from the esjp.
     */
    private boolean isTargetShowFile;

    /**
     * Name of the wiki file, that is the target of the help link shown in the
     * form, table etc.
     */
    private String helpTarget;

    /**
     * Constructor.
     *
     * @param _commandUUID UUID for this Model
     * @param _instanceKey instance id for this Model
     * @param _openerId id of the opener
     * @throws CacheReloadException on error
     */
    public AbstractUIPageObject(final UUID _commandUUID,
                                final String _instanceKey,
                                final String _openerId)
        throws CacheReloadException
    {
        super(_commandUUID, _instanceKey, _openerId);
        if (_commandUUID != null) {
            final AbstractCommand cmd = getCommand();
            if (cmd.getTargetCommand() != null) {
                final AbstractCommand trgCmd = cmd.getTargetCommand();
                this.targetCmdUUID = trgCmd.getUUID();
                this.targetCmdRevise = trgCmd.isTargetCmdRevise();
            } else if (TargetMode.SEARCH.equals(getMode())) {
                this.targetCmdRevise = cmd.isTargetCmdRevise();
            }
            this.isTargetShowFile = cmd.isTargetShowFile();
            this.helpTarget = cmd.getTargetHelp();
        }
    }

    /**
     * Constructor.
     *
     * @param _commandUUID UUID for this Model
     * @param _instanceKey instance id for this Model
     * @throws CacheReloadException on error
     */
    public AbstractUIPageObject(final UUID _commandUUID,
                                final String _instanceKey)
        throws CacheReloadException
    {
        this(_commandUUID, _instanceKey, null);
    }

    /**
     * Getter method for instance variable {@link #hiddenCells}.
     *
     * @return value of instance variable {@link #hiddenCells}
     */
    public List<IHidden> getHidden()
    {
        return this.hidden;
    }

    /**
     * Method to add a hidden Cell to the list {@link #hiddenCells}.
     *
     * @param _hiddenCell cell to add
     */
    public void addHidden(final IHidden _hiddenCell)
    {
        this.hidden.add(_hiddenCell);
    }

    /**
     * Get the CommandAbstract that is the target of this Page.
     *
     * @return the calling CommandAbstract UIClassification
     * @throws CacheReloadException the cache reload exception
     * @see #targetCmdUUID
     */
    public AbstractCommand getTargetCmd()
        throws CacheReloadException
    {
        AbstractCommand cmd = Command.get(this.targetCmdUUID);
        if (cmd == null) {
            cmd = Menu.get(this.targetCmdUUID);
        }
        return cmd;
    }

    /**
     * Getter method for instance variable {@link #targetCmdUUID}.
     *
     * @return value of instance variable {@link #targetCmdUUID}
     */
    public UUID getTargetCmdUUID()
    {
        return this.targetCmdUUID;
    }

    /**
     * Setter method for instance variable {@link #targetCmdUUID}.
     *
     * @param _targetCmdUUID value for instance variable {@link #targetCmdUUID}
     */
    public void setTargetCmdUUID(final UUID _targetCmdUUID)
    {
        this.targetCmdUUID = _targetCmdUUID;
    }

    /**
     * Method returns if this pageobject has a target command.
     *
     * @return true if targetCmdUUID !=null
     */
    public boolean hasTargetCmd()
    {
        return this.targetCmdUUID != null;
    }

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

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

    /**
     * Setter method for instance variable {@link #targetCmdRevise}.
     *
     * @param _targetCmdRevise value for instance variable
     *            {@link #targetCmdRevise}
     */
    public void setTargetCmdRevise(final boolean _targetCmdRevise)
    {
        this.targetCmdRevise = _targetCmdRevise;
    }

    /**
     * Getter method for instance variable {@link #wizard}.
     *
     * @return value of instance variable {@link #wizard}
     */
    public UIWizardObject getWizard()
    {
        return this.wizard;
    }

    /**
     * Setter method for instance variable {@link #wizard}.
     *
     * @param _wizard value for instance variable {@link #wizard}
     */
    public void setWizard(final UIWizardObject _wizard)
    {
        this.wizard = _wizard;
    }

    /**
     * Setter method for instance variable {@link #partOfWizardCall}.
     *
     * @param _wizardCall value for instance variable {@link #partOfWizardCall}
     */
    public void setPartOfWizardCall(final boolean _wizardCall)
    {
        this.partOfWizardCall = _wizardCall;
    }

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

    /**
     * Method to get the value for a key in case of wizard.
     *
     * @param _key key for the value
     * @return value for the object, if found, else null
     */
    protected Object getValue4Wizard(final String _key)
    {
        Object ret = null;
        final Map<String, String[]> para = this.wizard.getParameters((IWizardElement) this);
        if (para != null && para.containsKey(_key)) {
            final String[] value = para.get(_key);
            ret = value[0];
        }
        return ret;
    }

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

    /**
     * Setter method for instance variable {@link #renderRevise}.
     *
     * @param _renderRevise value for instance variable {@link #renderRevise}
     */
    public void setRenderRevise(final boolean _renderRevise)
    {
        this.renderRevise = _renderRevise;
    }

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

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

    /**
     * @return a new for this instance unique random key.
     */
    public String getNewRandom()
    {
        return ((Integer) this.random.nextInt()).toString();
    }

    /**
     * Used to check the access to e.g. TreeMenus.
     *
     * @param _instances Instances that must be checked for access
     * @return Map with Instance to Boolean
     * @throws EFapsException on error
     */
    protected Map<Instance, Boolean> checkAccessToInstances(final List<Instance> _instances)
        throws EFapsException
    {
        final Map<Type, List<Instance>> types = new HashMap<>();
        for (final Instance instance : _instances) {
            final List<Instance> list;
            if (!types.containsKey(instance.getType())) {
                list = new ArrayList<>();
                types.put(instance.getType(), list);
            } else {
                list = types.get(instance.getType());
            }
            list.add(instance);
        }
        // check the access for the given instances
        for (final Entry<Type, List<Instance>> entry : types.entrySet()) {
            this.accessMap.putAll(entry.getKey().checkAccess(entry.getValue(), AccessTypeEnums.SHOW.getAccessType()));
        }
        return this.accessMap;
    }

    /**
     * Getter method for the instance variable {@link #accessMap}.
     *
     * @return value of instance variable {@link #accessMap}
     */
    public Map<Instance, Boolean> getAccessMap()
    {
        return this.accessMap;
    }

    /**
     * Register oid.
     *
     * @param _oid the oid
     * @return the string
     */
    public String registerOID(final String _oid)
    {
        final String ret = RandomUtil.randomAlphanumeric(8);
        getUiID2Oid().put(ret, _oid);
        return ret;
    }

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

    /**
     * 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) {
                AbstractUIPageObject.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, getInstance(),
                            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;
    }
}


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

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

import java.util.Optional;

import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.extensions.markup.html.repeater.tree.NestedTree;
import org.apache.wicket.extensions.markup.html.repeater.tree.Node;
import org.apache.wicket.extensions.markup.html.repeater.tree.theme.HumanTheme;
import org.apache.wicket.extensions.markup.html.repeater.tree.theme.WindowsTheme;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.util.SetModel;
import org.efaps.admin.ui.field.FieldTable;
import org.efaps.ui.wicket.components.table.field.FieldPanel;
import org.efaps.ui.wicket.models.field.AbstractUIField;
import org.efaps.ui.wicket.models.objects.UIFieldStructurBrowser;
import org.efaps.ui.wicket.models.objects.UIStructurBrowser;
import org.efaps.ui.wicket.resources.AbstractEFapsHeaderItem;
import org.efaps.ui.wicket.resources.EFapsContentReference;
import org.efaps.ui.wicket.util.Configuration;
import org.efaps.ui.wicket.util.Configuration.ConfigAttribute;
import org.efaps.util.cache.CacheReloadException;

/**
 * This class renders a TreeTable, which loads the children asynchron.<br>
 * The items of the tree consists of junction link, icon and label.
 * The table shows the columns as defined in the model.
 *
 * @author The eFaps Team
 */
public class StructurBrowserTreeTable
    extends NestedTree<UIStructurBrowser>
{
    /**
     * Needed for serialization.
     */
    private static final long serialVersionUID = 1L;

    /**
     * ResourceReference to the StyleSheet used for this TreeTable.
     */
    private static final EFapsContentReference CSS = new EFapsContentReference(StructurBrowserTreeTable.class,
                    "StructurTreeTable.css");

    /** The topic name. */
    private final String topicName;

    /**
     * Constructor.
     *
     * @param _wicketId wicket id for this component
     * @param _model model
     * @throws CacheReloadException on error
     */
    public StructurBrowserTreeTable(final String _wicketId,
                                    final IModel<UIStructurBrowser> _model)
        throws CacheReloadException
    {
        super(_wicketId, new StructurBrowserProvider(_model),
                        new SetModel<>(_model.getObject().getExpandedBrowsers()));
        if (_model.getObject() instanceof UIFieldStructurBrowser) {
            final FieldTable field = FieldTable.get(((UIFieldStructurBrowser) _model.getObject()).getFieldTabelId());
            this.topicName = field.getName();
        } else {
            this.topicName = _model.getObject().getTable().getName();
        }

        if ("human".equals(Configuration.getAttribute(ConfigAttribute.STRUCBRWSRTREE_CLASS))) {
            add(new HumanTheme());
        } else if ("windows".equals(Configuration.getAttribute(ConfigAttribute.STRUCBRWSRTREE_CLASS))) {
            add(new WindowsTheme());
        }
    }

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

    @Override
    protected Component newContentComponent(final String _wicketId,
                                            final IModel<UIStructurBrowser> _model)
    {
        final UIStructurBrowser strucBrws = _model.getObject();
        final AbstractUIField uiField = strucBrws.getColumns().get(strucBrws.getBrowserFieldIndex());
        return new FieldPanel(_wicketId, Model.of(uiField));
    }

    @Override
    public void expand(final UIStructurBrowser _uiStrBrws)
    {
        super.expand(_uiStrBrws);
        _uiStrBrws.setExpanded(true);
        final Optional<AjaxRequestTarget> optionalTarget = getRequestCycle().find(AjaxRequestTarget.class);
        final StringBuilder js = new StringBuilder()
                    .append("highlight();positionTableColumns(eFapsTable").append(_uiStrBrws.getTableId()).append(");")
                    .append("require([\"dojo/topic\"], function(topic){\n")
                    .append("topic.publish(\"eFaps/expand/").append(this.topicName).append("\");\n")
                    .append("})\n");
        optionalTarget.ifPresent(target -> target.appendJavaScript(js));
    }

    /**
     * Collapse the given node, tries to update the affected branch if the
     * change happens on an {@link AjaxRequestTarget}.
     *
     * @param _uiStrBrws    the object to collapse
     */
    @Override
    public void collapse(final UIStructurBrowser _uiStrBrws)
    {
        super.collapse(_uiStrBrws);
        _uiStrBrws.setExpanded(false);
        final Optional<AjaxRequestTarget> optionalTarget = getRequestCycle().find(AjaxRequestTarget.class);
        final StringBuilder js = new StringBuilder()
                    .append("positionTableColumns(eFapsTable").append(_uiStrBrws.getTableId()).append(");")
                    .append("require([\"dojo/topic\"], function(topic){\n")
                    .append("topic.publish(\"eFaps/collapse/").append(this.topicName).append("\");\n")
                    .append("})\n");
        optionalTarget.ifPresent(target -> target.appendJavaScript(js));
    }

    /**
     * Create a new component for a node.
     *
     * @param _wicketId  the component id
     * @param _model     the model containing the node
     * @return created component
     */
    @Override
    public Component newNodeComponent(final String _wicketId,
                                      final IModel<UIStructurBrowser> _model)
    {
        return new Node<UIStructurBrowser>(_wicketId, this, _model)
        {

            private static final long serialVersionUID = 1L;

            @Override
            protected Component createContent(final String _wicketId,
                                              final IModel<UIStructurBrowser> _model)
            {
                return newContentComponent(_wicketId, _model);
            }

            @Override
            protected MarkupContainer createJunctionComponent(final String _id)
            {
                final UIStructurBrowser strucBrws = (UIStructurBrowser) getDefaultModelObject();
                final MarkupContainer ret;
                if (strucBrws.hasChildren() && strucBrws.isForceExpanded()) {
                    ret = new WebMarkupContainer(_id);

                } else {
                    ret = super.createJunctionComponent(_id);
                }

                if (strucBrws.getLevel() > 0) {
                    ret.add(AttributeModifier.append("style", "margin-left:" + 15 * (strucBrws.getLevel() - 1) + "px"));
                }
                return ret;
            }
        };
    }

    /**
     * Create a new subtree.
     *
     * @param _wicketId     wicket id for this component
     * @param _model        the model of the new subtree
     * @return the created component
     */
    @Override
    public Component newSubtree(final String _wicketId,
                                final IModel<UIStructurBrowser> _model)
    {
        return new SubElement(_wicketId, this, _model);
    }
}


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

import lombok.Data;

import java.io.Serializable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * Type representing the flavor of an index. Known flavors are exposed as static constants.
 */
@Data
public class IndexFlavor implements Serializable {
    private static final long serialVersionUID = 4450074251836253214L;

    /**
     * The flavour of a standard text index
     */
    public static final IndexFlavor STANDARD = new IndexFlavor("standard");

    /**
     * The flavour of an explorer text index
     */
    public static final IndexFlavor EXPLORER = new IndexFlavor("explorer");

    /**
     * The flavour of a categorization text index
     */
    public static final IndexFlavor CATEGORIZATION = new IndexFlavor("categorization");

    /**
     * The flavour of a custom fields text index
     */
    public static final IndexFlavor CUSTOM_FIELDS = new IndexFlavor("custom_fields");

    /**
     * The flavour of a query manipulation text index
     */
    public static final IndexFlavor QUERY_MANIPULATION = new IndexFlavor("querymanipulation");

    /**
     * The flavour of a jumbo text index
     */
    public static final IndexFlavor JUMBO = new IndexFlavor("jumbo");

    private final String name;

    /**
     * Creates a new IndexFlavor with the given name
     * @param name The name of the IndexFlavor
     */
    public IndexFlavor(final String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }

    /**
     * @return A set containing all the IndexFlavor instances declared in static fields
     */
    public static Set<IndexFlavor> allOf() {
        return new HashSet<>(Arrays.asList(
                STANDARD,
                EXPLORER,
                CATEGORIZATION,
                CUSTOM_FIELDS,
                QUERY_MANIPULATION,
                JUMBO
        ));
    }

    /**
     * Returns a set containing all the known index flavours, except those is the given set
     * @param indexFlavors The index flavours which will not be included in the returned set
     * @return The complement of the given set of index flavours
     */
    public static Set<IndexFlavor> complementOf(final Set<IndexFlavor> indexFlavors) {
        final Set<IndexFlavor> set = allOf();
        set.removeAll(indexFlavors);
        return set;
    }

    /**
     * Returns a set containing the given index flavours
     * @param first The first index flavour to add
     * @param rest The remaining index flavours to add
     * @return A set containing the given index flavours
     */
    public static Set<IndexFlavor> of(final IndexFlavor first, final IndexFlavor... rest) {
        final Set<IndexFlavor> set = new HashSet<>();
        set.add(first);
        set.addAll(Arrays.asList(rest));
        return set;
    }
}


/*
 * 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.models.field.factories;

import java.io.Serializable;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.BooleanUtils;
import org.apache.wicket.Component;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.efaps.admin.datamodel.ui.BooleanUI;
import org.efaps.api.ui.UIType;
import org.efaps.ui.wicket.components.values.BooleanField;
import org.efaps.ui.wicket.components.values.CheckBoxField;
import org.efaps.ui.wicket.models.field.AbstractUIField;
import org.efaps.ui.wicket.models.field.FieldConfiguration;
import org.efaps.ui.wicket.models.field.set.UIFieldSetValue;
import org.efaps.util.EFapsException;

/**
 * TODO comment!
 *
 * @author The eFaps Team
 */
// CHECKSTYLE:OFF
public final class BooleanUIFactory
    extends AbstractUIFactory
// CHECKSTYLE:ON
{

    /**
     * Factory Instance.
     */
    private static BooleanUIFactory FACTORY;

    /**
     * Singelton.
     */
    private BooleanUIFactory()
    {
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    @Override
    public Component getEditable(final String _wicketId,
                                 final AbstractUIField _uiField)
        throws EFapsException
    {
        Component ret = null;
        if (applies(_uiField)) {
            final FieldConfiguration config = _uiField.getFieldConfiguration();
            final UIType uiType = config.getUIType();
            if (uiType.equals(UIType.CHECKBOX)) {
                ret = new CheckBoxField(_wicketId, Model.of(_uiField), null, config);
            } else {
                final IModel<Map<Object, Object>> model = Model.ofMap((Map<Object, Object>) _uiField.getValue()
                                .getEditValue(_uiField.getParent().getMode()));
                final Serializable value = _uiField.getValue().getDbValue();
                ret = new BooleanField(_wicketId, value, model, _uiField.getFieldConfiguration(), _uiField.getLabel(),
                                _uiField instanceof UIFieldSetValue);
            }
        }
        return ret;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean applies(final AbstractUIField _uiField)
        throws EFapsException
    {
        return _uiField.getValue().getUIProvider() instanceof BooleanUI;
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    @Override
    protected String getReadOnlyValue(final AbstractUIField _uiField)
        throws EFapsException
    {
        String strValue = "";
        if (_uiField.getValue().getDbValue() != null) {
            final Map<Object, Object> map = (Map<Object, Object>) _uiField.getValue()
                            .getReadOnlyValue(_uiField.getParent().getMode());
            for (final Entry<Object, Object> entry : map.entrySet()) {
                if (entry.getValue().equals(_uiField.getValue().getDbValue())) {
                    strValue = (String) entry.getKey();
                    break;
                }
            }
        }
        return strValue;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getKey()
    {
        return BooleanUIFactory.class.getName();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getPickListValue(final AbstractUIField _uiField)
        throws EFapsException
    {
        return getReadOnlyValue(_uiField);
    }

    @Override
    public Comparable<?> getCompareValue(final AbstractUIField _uiField)
        throws EFapsException
    {
        return BooleanUtils.toBooleanDefaultIfNull((Boolean) _uiField.getValue().getDbValue(), false);
    }

    /**
     * @return IComponentFactory instance
     */
    public static IComponentFactory get()
    {
        if (BooleanUIFactory.FACTORY == null) {
            BooleanUIFactory.FACTORY = new BooleanUIFactory();
        }
        return BooleanUIFactory.FACTORY;
    }
}


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

import lombok.EqualsAndHashCode;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Map implementation which supports multiple values for keys. This allow converting items in a list to multiple HTTP
 * query parameters/parts. Adding a key pairing multiple times has no effect beyond the first.
 *

 * Somewhat unusually, get is NOT supported on this map, as it makes little semantic sense.
 *

 * This map does not support null keys and values
 * @param <K> The type of the map's keys
 * @param <V> The type of the map's values
 */
@SuppressWarnings("NullableProblems")
public class MultiMap<K, V> implements Map<K, V> {

    private final Set<Map.Entry<K, V>> entries = new LinkedHashSet<>();

    /**
     * @return The number of entries in the map
     */
    @Override
    public int size() {
        return entries.size();
    }

    /**
     * @return True if the map has no entries; false otherwise
     */
    @Override
    public boolean isEmpty() {
        return entries.isEmpty();
    }

    /**
     * @param key The key to test
     * @return True if at least one value exists for the key; false otherwise
     */
    @Override
    public boolean containsKey(final Object key) {
        for (final Map.Entry<K, V> entry : entries) {
            if (key.equals(entry.getKey())) {
                return true;
            }
        }

        return false;
    }

    /**
     * @param value The key to test
     * @return True if at least one key exists for the given value; false otherwise
     */
    @Override
    public boolean containsValue(final Object value) {
        for (final Map.Entry<K, V> entry : entries) {
            if (value.equals(entry.getValue())) {
                return true;
            }
        }

        return false;
    }

    /**
     * This method is NOT supported.
     * @param key The key
     * @return This method will not return
     * @throws java.lang.UnsupportedOperationException Under all circumstances
     */
    @Override
    public V get(final Object key) {
        throw new UnsupportedOperationException();
    }

    /**
     * Add an entry for the given key-value pair to the map
     * @param key The key
     * @param value The value
     * @return value
     */
    @Override
    public V put(final K key, final V value) {
        entries.add(new Entry(key, value));

        return value;
    }

    /**
     * Remove all entries for the given key
     * @param key The key
     * @return Some value that was paired with the key. The exact value is indeterminate
     */
    @Override
    public V remove(final Object key) {
        final Iterator<Map.Entry<K, V>> iterator = entries.iterator();
        V lastValue = null;

        while (iterator.hasNext()) {
            final Map.Entry<K, V> entry = iterator.next();
            lastValue = entry.getValue();

            if (key.equals(entry.getKey())) {
                iterator.remove();
            }
        }

        return lastValue;
    }

    /**
     * Add all the entries in the given map to this map
     * @param m The map to add entries from
     */
    @Override
    public void putAll(final Map<? extends K, ? extends V> m) {
        for (final Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
            put(entry.getKey(), entry.getValue());
        }
    }

    /**
     * Removes all entries from the map
     */
    @Override
    public void clear() {
        entries.clear();
    }

    /**
     * @return A set containing all the keys in the map. Note that this will not have the same size as the map
     */
    @Override
    public Set<K> keySet() {
        final Set<K> keys = entries.stream().map(Map.Entry::getKey).collect(Collectors.toSet());

        return keys;
    }

    /**
     * @return A collection containing all the values in the map
     */
    @Override
    public Collection<V> values() {
        final Set<V> values = entries.stream().map(Map.Entry::getValue).collect(Collectors.toSet());

        return values;
    }

    /**
     * @return A set containing all the entries in the map
     */
    @Override
    public Set<Map.Entry<K, V>> entrySet() {
        return entries;
    }

    @EqualsAndHashCode
    private class Entry implements Map.Entry<K, V> {

        private final K key;
        private V value;

        private Entry(final K key, final V value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public K getKey() {
            return key;
        }

        @Override
        public V getValue() {
            return value;
        }

        @Override
        public V setValue(final V value) {
            final V oldValue = this.value;

            this.value = value;

            return oldValue;
        }
    }
}


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

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import org.efaps.util.RandomUtil;

/**
 * The Class AbstractUI.
 */
public abstract class AbstractUI
    implements Serializable
{

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

    /** The idmap. */
    private final Map<String, Long> random2id = new HashMap<>();

    /**
     * Gets the random for ID.
     *
     * @param _id the id
     * @return the random for ID
     */
    public String getRandom4ID(final Long _id)
    {
        final String rid = RandomUtil.randomAlphanumeric(8);
        this.random2id.put(rid, _id);
        return rid;
    };

    /**
     * Gets the ID for random.
     *
     * @param _rid the rid
     * @return the ID for random
     */
    public Long getID4Random(final String _rid)
    {
        return this.random2id.get(_rid);
    };
}


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

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

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.UUID;

import org.efaps.admin.ui.AbstractCommand;
import org.efaps.admin.ui.AbstractCommand.SortDirection;
import org.efaps.admin.ui.Table;
import org.efaps.admin.ui.field.Field;
import org.efaps.db.Context;
import org.efaps.util.EFapsException;
import org.efaps.util.cache.CacheReloadException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * TODO comment!
 *
 * @author The eFaps Team
 */
public abstract class AbstractUIHeaderObject
    extends AbstractUIPageObject
{

    /**
     * This enum holds the Values used as part of the key for the UserAttributes
     * or SessionAttribute witch belong to a TableModel.
     */
    public enum UserCacheKey
    {
        /**
         * Key for UserAttributes used for the order of Columns.
         */
        COLUMNORDER("columnOrder"),
        /**
         * Key for UserAttributes used for the widths of Columns.
         */
        COLUMNWIDTH("columnWidths"),
        /**
         * Key for UserAttributes used for the sort direction.
         */
        SORTDIRECTION("sortDirection"),
        /**
         * Key for UserAttributes used for the Column.
         */
        SORTKEY("sortKey"),
        /**
         * Key for SessionAttribute used for the filter of a table.
         */
        FILTER("filter"),
        /**
         * Key for SessionAttribute used for the filter of a table.
         */
        GRIDX("gridx");

        /**
         * Value of the user attribute.
         */
        private final String value;

        /**
         * Constructor setting the instance variable.
         *
         * @param _value Value
         */
        UserCacheKey(final String _value)
        {
            this.value = _value;
        }

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

    /**
     *
     */
    private static final long serialVersionUID = 1L;

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

    /**
     * The instance Array holds the Label for the Columns.
     */
    private final List<UITableHeader> headers = new ArrayList<>();

    /**
     * This instance variable stores the Id of the table. This int is used to
     * distinguish tables in case that there are more than one table on one
     * page.
     */
    private int tableId = 1;

    /**
     * The instance variable stores the UUID for the table which must be shown.
     *
     * @see #getTable
     */
    private UUID tableUUID;

    /**
     * This instance variable sores if the Table should show CheckBodes.
     */
    private boolean showCheckBoxes = false;

    /**
     * This instance variable stores if the Widths of the Columns are set by
     * UserAttributes.
     */
    private boolean userWidths = false;

    /**
     * This instance variable stores the total weight of the widths of the
     * Cells. (Sum of all widths)
     */
    private int widthWeight;

    /**
     * The size of the current values list including filtereing etc. Update on
     * filter events etc.
     */
    private int size;

    /**
     * The instance variable stores the string of the sort direction.
     *
     * @see #getSortDirection
     * @see #setSortDirection
     */
    private SortDirection sortDirection = SortDirection.NONE;

    /**
     * The instance variable stores the string of the sort key.
     *
     * @see #getSortKey
     * @see #setSortKey
     */
    private String sortKey = null;

    /**
     * Is Drag and drop allowed.
     */
    private boolean dnD = true;

    /**
     * @param _commandUUID UUID of the Command
     * @param _instanceKey key to the instance
     * @param _openerId id of the opener
     * @throws CacheReloadException on error
     */
    public AbstractUIHeaderObject(final UUID _commandUUID,
                                  final String _instanceKey,
                                  final String _openerId)
        throws CacheReloadException
    {
        super(_commandUUID, _instanceKey, _openerId);
        initialize();
    }

    /**
     * @param _commandUUID UUID of the Command
     * @param _instanceKey key to the instance
     * @throws CacheReloadException on error
     */
    public AbstractUIHeaderObject(final UUID _commandUUID,
                                  final String _instanceKey)
        throws CacheReloadException
    {
        super(_commandUUID, _instanceKey);
        initialize();
    }

    /**
     * @throws CacheReloadException on error
     */
    protected void initialize()
        throws CacheReloadException
    {
        final AbstractCommand cmd = getCommand();
        if (cmd != null) {
            setDnD(!"true".equalsIgnoreCase(cmd.getProperty("TargetDeactivateDnD")));
        }
    }

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

    /**
     * Setter method for instance variable {@link #dnD}.
     *
     * @param _dnD value for instance variable {@link #dnD}
     */
    public void setDnD(final boolean _dnD)
    {
        this.dnD = _dnD;
    }

    /**
     * This is the getter method for the instance variable {@link #tableId}.
     *
     * @return value of instance variable {@link #tableId}
     */
    public int getTableId()
    {
        return this.tableId * 100;
    }

    /**
     * This is the setter method for the instance variable {@link #tableId}.
     *
     * @param _tableId the tableId to set
     */
    public void setTableId(final int _tableId)
    {
        this.tableId = _tableId;
    }

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

    /**
     * Setter method for instance variable {@link #tableUUID}.
     *
     * @param _tableUUID value for instance variable {@link #tableUUID}
     */
    protected void setTableUUID(final UUID _tableUUID)
    {
        this.tableUUID = _tableUUID;
    }

    /**
     * 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 getTableUUID() == null ? null : Table.get(getTableUUID());
    }

    /**
     * @return true if the check boxes must be shown, other false
     *         is returned.
     * @see #showCheckBoxes
     */
    public boolean isShowCheckBoxes()
    {
        boolean ret;
        if (super.isSubmit() && !isCreateMode()) {
            ret = true;
        } else {
            ret = this.showCheckBoxes;
        }
        return ret;
    }

    /**
     * To make it overwritable.
     *
     * @return true if the check boxes must be shown, other false
     *         is returned.
     * @see #showCheckBoxes
     */
    protected boolean getShowCheckBoxes()
    {
        return this.showCheckBoxes;
    }

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

    /**
     * In create or edit mode this Table is editable.
     *
     * @return is this Table editable.
     */
    public boolean isEditable()
    {
        return isCreateMode() || isEditMode();
    }

    /**
     * This is the getter method for the instance variable {@link #headers}.
     *
     * @return value of instance variable {@link #headers}
     */
    public List<UITableHeader> getHeaders()
    {
        return this.headers;
    }

    /**
     * @param _fieldId id of the
     * @return UITableHeader header
     */
    public UITableHeader getHeader4Id(final long _fieldId)
    {
        UITableHeader ret = null;
        for (final UITableHeader header : this.headers) {
            if (header.getFieldId() == _fieldId) {
                ret = header;
                break;
            }
        }
        return ret;
    }

    /**
     * Are the values of the Rows filtered or not.
     *
     * @return true if filtered, else false
     */
    public boolean isFiltered()
    {
        return false;
    }

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

    /**
     * @param _userWidth must the user with be set
     */
    protected void setUserWidth(final boolean _userWidth)
    {
        this.userWidths = _userWidth;
    }

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

    /**
     * Setter method for instance variable {@link #widthWeight}.
     *
     * @param _widthWeight value for instance variable {@link #widthWeight}
     */
    protected void setWidthWeight(final int _widthWeight)
    {
        this.widthWeight = _widthWeight;
    }

    /**
     * This method retieves the UserAttribute for the ColumnWidths and evaluates
     * the string.
     *
     * @return List with the values of the columns in Pixel
     */
    protected List<Integer> getUserWidths()
    {
        List<Integer> ret = null;
        try {
            if (Context.getThreadContext().containsUserAttribute(
                            getCacheKey(UITable.UserCacheKey.COLUMNWIDTH))) {
                setUserWidth(true);
                final String widths = Context.getThreadContext().getUserAttribute(
                                getCacheKey(UITable.UserCacheKey.COLUMNWIDTH));

                final StringTokenizer tokens = new StringTokenizer(widths, ";");

                ret = new ArrayList<>();

                while (tokens.hasMoreTokens()) {
                    final String token = tokens.nextToken();
                    for (int i = 0; i < token.length(); i++) {
                        if (!Character.isDigit(token.charAt(i))) {
                            final int width = Integer.parseInt(token.substring(0, i));
                            ret.add(width);
                            break;
                        }
                    }
                }
            }
        } catch (final NumberFormatException e) {
            // we don't throw an error because this are only Usersettings
            AbstractUIHeaderObject.LOG.error("error during the retrieve of UserAttributes in getUserWidths()", e);
        } catch (final EFapsException e) {
            // we don't throw an error because this are only Usersettings
            AbstractUIHeaderObject.LOG.error("error during the retrieve of UserAttributes in getUserWidths()", e);
        }
        return ret;
    }

    /**
     * Getter method for the instance variable {@link #sortDirection}.
     *
     * @return value of instance variable {@link #sortDirection}
     */
    public SortDirection getSortDirection()
    {
        return this.sortDirection;
    }

    /**
     * Method to set he sort direction.
     *
     * @param _sortdirection sort direction to set
     */
    public void setSortDirection(final SortDirection _sortdirection)
    {
        this.sortDirection = _sortdirection;
        try {
            Context.getThreadContext().setUserAttribute(getCacheKey(UserCacheKey.SORTDIRECTION),
                            _sortdirection.getValue());
        } catch (final EFapsException e) {
            // we don't throw an error because this are only Usersettings
            AbstractUIHeaderObject.LOG.error("error during the retrieve of UserAttributes", e);
        }
    }

    /**
     * @param _sortdirection sortdirection
     */
    public void setSortDirectionInternal(final SortDirection _sortdirection)
    {
        this.sortDirection = _sortdirection;
    }

    /**
     * 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 UserCacheKey _key)
    {
        return super.getCommandUUID() + "-" + _key.getValue();
    }

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

    /**
     * Setter method for instance variable {@link #size}.
     *
     * @param _size value for instance variable {@link #size}
     */
    protected void setSize(final int _size)
    {
        this.size = _size;
    }

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

    /**
     * Setter method for instance variable {@link #sortKey}.
     *
     * @param _sortKey value for instance variable {@link #sortKey}
     */
    public void setSortKey(final String _sortKey)
    {
        setSortKeyInternal(_sortKey);
        try {
            Context.getThreadContext().setUserAttribute(getCacheKey(UITable.UserCacheKey.SORTKEY),
                            _sortKey);
        } catch (final EFapsException e) {
            // we don't throw an error because this are only Usersettings
            AbstractUIHeaderObject.LOG.error("error during the retrieve of UserAttributes", e);
        }
    }

    /**
     * @param _sortKey sort key
     */
    protected void setSortKeyInternal(final String _sortKey)
    {
        this.sortKey = _sortKey;
    }

    /**
     * Method to set the order of the columns.
     *
     * @param _markupsIds ids of the columns as a string with ; separated
     */
    public void setColumnOrder(final String _markupsIds)
    {
        final StringTokenizer tokens = new StringTokenizer(_markupsIds, ";");
        final StringBuilder columnOrder = new StringBuilder();
        while (tokens.hasMoreTokens()) {
            final String markupId = tokens.nextToken();
            for (final UITableHeader header : getHeaders()) {
                if (markupId.equals(header.getMarkupId())) {
                    columnOrder.append(header.getFieldName()).append(";");
                    break;
                }
            }
        }
        try {
            Context.getThreadContext().setUserAttribute(getCacheKey(UITable.UserCacheKey.COLUMNORDER),
                            columnOrder.toString());
        } catch (final EFapsException e) {
            // we don't throw an error because this are only Usersettings
            AbstractUIHeaderObject.LOG.error("error during the setting of UserAttributes", e);
        }
    }

    /**
     * This method looks if for this TableModel a UserAttribute for the sorting
     * of the Columns exist. If they exist the Fields will be sorted as defined
     * by the User. If no definition of the User exist the Original default
     * sorting of the columns will be used. In the Case that the Definition of
     * the Table was altered Field which are not sorted yet will be sorted in at
     * the last position.
     *
     * @return List of fields
     */
    protected List<Field> getUserSortedColumns()
    {
        List<Field> ret = new ArrayList<>();
        try {
            final List<Field> fields = getTable().getFields();
            if (Context.getThreadContext().containsUserAttribute(
                            getCacheKey(UITable.UserCacheKey.COLUMNORDER))) {

                final String columnOrder = Context.getThreadContext().getUserAttribute(
                                getCacheKey(UITable.UserCacheKey.COLUMNORDER));

                final StringTokenizer tokens = new StringTokenizer(columnOrder, ";");
                while (tokens.hasMoreTokens()) {
                    final String fieldname = tokens.nextToken();
                    for (int i = 0; i < fields.size(); i++) {
                        if (fieldname.equals(fields.get(i).getName())) {
                            ret.add(fields.get(i));
                            fields.remove(i);
                        }
                    }
                }
                if (!fields.isEmpty()) {
                    for (final Field field : fields) {
                        ret.add(field);
                    }
                }
            } else {
                ret = fields;
            }
        } catch (final EFapsException e) {
            AbstractUIHeaderObject.LOG.debug("Error on sorting columns");
        }
        return ret;
    }

    /**
     * Sort the UIObject.
     *
     * @throws EFapsException on error
     */
    public abstract void sort()
        throws EFapsException;
}


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

import org.apache.wicket.Page;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.MarkupStream;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.efaps.admin.ui.AbstractCommand.SortDirection;
import org.efaps.ui.wicket.models.objects.UIFieldStructurBrowser;
import org.efaps.ui.wicket.models.objects.UIForm;
import org.efaps.ui.wicket.models.objects.UIStructurBrowser;
import org.efaps.ui.wicket.pages.content.form.FormPage;
import org.efaps.ui.wicket.pages.content.structurbrowser.StructurBrowserPage;
import org.efaps.ui.wicket.pages.error.ErrorPage;
import org.efaps.util.EFapsException;

/**
 * Class renders a Link used to sort a Structur Browser.
 *
 * @author The eFaps Team
 * @version $Id$
 */
public class SortHeaderColumnLink
    extends Link<UIStructurBrowser>
{

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

    /**
     * The value for the header.
     */
    private final String header;

    /**
     * Constructor.
     *
     * @param _wicketId wicket id for this component
     * @param _header header to set
     * @param _model model for this component
     */
    public SortHeaderColumnLink(final String _wicketId,
                                final String _header,
                                final IModel<UIStructurBrowser> _model)
    {
        super(_wicketId, _model);
        this.header = _header;
    }

    /**
     * On the tag the class is set.
     *
     * @param _tag tag to be set
     */
    @Override
    protected void onComponentTag(final ComponentTag _tag)
    {
        super.onComponentTag(_tag);
        final UIStructurBrowser structurBrowser = (UIStructurBrowser) getDefaultModelObject();
        if (structurBrowser.getSortDirection().equals(SortDirection.ASCENDING)) {
            _tag.put("class", "sortLabelAsc");
        } else {
            _tag.put("class", "sortLabelDsc");
        }
    }

    /**
     * The body of the component is filled with the header.
     *
     * @param _markupStream MarkupStream
     * @param _openTag ComponentTag
     */
    @Override
    public void onComponentTagBody(final MarkupStream _markupStream,
                                      final ComponentTag _openTag)
    {
        replaceComponentTagBody(_markupStream, _openTag, this.header);
    }

    /**
     * On click the model is sorted and a new page with this model as response
     * rendered.
     */
    @Override
    public void onClick()
    {
        final UIStructurBrowser structurBrowser = (UIStructurBrowser) getDefaultModelObject();
        // toggle sort direction
        if (structurBrowser.getSortDirection() == SortDirection.NONE
                        || structurBrowser.getSortDirection() == SortDirection.DESCENDING) {
            structurBrowser.setSortDirection(SortDirection.ASCENDING);
        } else {
            structurBrowser.setSortDirection(SortDirection.DESCENDING);
        }
        structurBrowser.sort();
        try {
            final Page page;
            if (structurBrowser instanceof UIFieldStructurBrowser) {
                page = new FormPage(Model.of((UIForm) getPage().getDefaultModelObject()));
            } else {
                page = new StructurBrowserPage(Model.of(structurBrowser));
            }
            getRequestCycle().setResponsePage(page);
        } catch (final EFapsException e) {
            getRequestCycle().setResponsePage(new ErrorPage(e));
        }
    }
}


package org.irenical.jindy;

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

import java.util.Iterator;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;

public class ConfigFactory {

  public static String DEFAULT_CONFIG_NAME;

  private static Logger LOG;

  private static Map<String, Config> configs;

  private static IConfigFactory defaultConfigFactory;

  private static ConfigContext context;

  private synchronized static void init() {
    if (configs == null) {
      DEFAULT_CONFIG_NAME = "DEFAULT";
      configs = new ConcurrentHashMap<>();
      LOG = LoggerFactory.getLogger(ConfigFactory.class);
    }
  }

  private static void log(boolean debug, String message, Exception error) {
    // during initialization, logging might not exist yet
    if (LOG != null) {
      if (error != null) {
        LOG.error(message, error);
      } else if (debug) {
        LOG.debug(message);
      } else {
        LOG.info(message);
      }
    }
  }

  /**
   * Returns the default Config, same as getConfig(null)
   *
   * @return the default Config instance
   */
  public static Config getConfig() {
    return getConfig(null);
  }

  /**
   * Returns Config for given name, same as getConfig(name,null)
   *
   * @param name
   *          - the Config name
   * @return the Config instance for given name
   */
  public static Config getConfig(String name) {
    return getConfig(name, null);
  }

  /**
   * Returns a Config instance, instantiating it on first call. If no factory
   * implementation is provided, one will be searched using Service Loader If a
   * Config with given name already exists, it will be simply returned
   *
   * @param name
   *          - the Config instance name
   * @param factory
   *          - a custom factory implementation
   * @return the Config instance with given name, instanciating one if needed
   */
  public static Config getConfig(String name, IConfigFactory factory) {
    if (configs == null) {
      init();
    }
    if (name == null) {
      name = DEFAULT_CONFIG_NAME;
    }

    Config got = configs.get(name);
    if (got == null) {
      log(true, "No Config instance named " + name + "... requesting a new one", null);
      // recheck in synchronized block to avoid double instantiation
      // will block concurrent calls to this Config until
      // the initialization is complete
      synchronized (name.intern()) {
        got = configs.get(name);
        if (got == null) {
          got = factory == null ? load(name) : factory.createConfig(name);
          if (got == null) {
            log(false, "Factory " + factory + " returned a null Config", null);
            throw new InvalidConfigException(
                "Invalid Config returned by " + factory + " factory: null");
          }
          configs.put(name, got);
        }
      }
    }
    return got;
  }

  private static Config load(String name) {
    log(false, "Looking for a IConfigFactory implementation", null);
    ServiceLoader<IConfigFactory> loader = ServiceLoader.load(IConfigFactory.class);
    Iterator<IConfigFactory> implIterator = loader.iterator();
    IConfigFactory got = null;
    if (implIterator.hasNext()) {
      got = implIterator.next();
    }

    // error on multiple bindings
    if (implIterator.hasNext()) {
      StringBuilder sb = new StringBuilder(
          "Multiple bindings found on classpath for " + IConfigFactory.class.getName() + "[");
      boolean first = true;
      for (IConfigFactory current : loader) {
        if (!first) {
          sb.append(",");
        }
        sb.append(current.getClass().getName());
        first = false;
      }
      sb.append("]");
      log(false, sb.toString(), null);
      throw new ConfigMultipleBindingsException(sb.toString());
    }

    // ok on single binding
    if (got != null) {
      log(false, "Found a IConfigFactory implementation: " + got.getClass().getName(), null);
      return got.createConfig(name);
    }

    synchronized (ConfigFactory.class) {
      if (defaultConfigFactory != null) {
        return defaultConfigFactory.createConfig(name);
      }
    }

    // error on no binding
    log(false,
        "No bindings found. Make sure you have an implementation class declared in META-INF/services/"
            + IConfigFactory.class.getName(),
        null);
    throw new ConfigBindingNotFoundException(
        "No bindings found. Make sure you have an implementation class declared in META-INF/services/"
            + IConfigFactory.class.getName());
  }

  public synchronized static void setDefaultConfigFactory(IConfigFactory factory) {
    defaultConfigFactory = factory;
  }

  public static void setContext(ConfigContext context) {
    ConfigFactory.context = context;
  }

  public static ConfigContext getContext() {
    return context;
  }

  /**
   * Discards all Config instances
   */
  public synchronized static void clear() {
    if (configs != null) {
      configs.clear();
    }

    defaultConfigFactory = null;
  }

}


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

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

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

import org.efaps.db.Instance;
import org.efaps.ui.wicket.models.AbstractInstanceObject;
import org.efaps.ui.wicket.models.field.IFilterable;
import org.efaps.ui.wicket.models.field.IHidden;
import org.efaps.util.EFapsException;
import org.efaps.util.cache.CacheReloadException;

/**
 * Class represents one row in the UITable.
 *
 * @author The eFaps Team
 * @version $Id$
 */
public class UIRow
    extends AbstractInstanceObject
{

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

    /**
     * The instance variable stores the values for the table.
     *
     */
    private final List<IFilterable> cells = new ArrayList<>();

    /**
     * This list contains the hidden cells for this row.
     */
    private final List<IHidden> hidden = new ArrayList<>();

    /**
     * Parent of this row.
     */
    private final AbstractUIObject parent;

    /**
     * Constructor used in case that no instances are given. e.g. on create.
     *
     * @param _parent Parent object of this row
     */
    public UIRow(final AbstractUIObject _parent)
    {
        this(_parent, null);
    }

    /**
     * The constructor creates a new instance of class Row.
     *
     * @param _parent Parent object of this row
     * @param _instanceKeys string with all oids for this row
     */
    public UIRow(final AbstractUIObject _parent,
                 final String _instanceKeys)
    {
        super(_instanceKeys);
        this.parent = _parent;
    }

    /**
     * The instance method adds a new attribute value (from instance
     * {@link AttributeTypeInterface}) to the values.
     *
     * @param _instObj cell model to add
     * @see #values
     */
    public void add(final IFilterable _instObj)
    {
        this.cells.add(_instObj);
    }

    /**
     * Add a hidden cell to this row.
     *
     * @param _hiddenCell hidden cell to be added
     */
    public void addHidden(final IHidden _hiddenCell)
    {
        this.hidden.add(_hiddenCell);
    }

    /**
     * Getter method for instance variable {@link #hidden}.
     *
     * @return value of instance variable {@link #hidden}
     */
    public List<IHidden> getHidden()
    {
        for (final IHidden hidden : this.hidden) {
            hidden.setAdded(false);
        }
        return this.hidden;
    }

    /**
     * The instance method returns the size of the array list {@link #values}.
     *
     * @see #values
     * @return size of instance variable {@link #values}
     */
    public int getSize()
    {
        return getCells().size();
    }

    /**
     * This is the getter method for the values variable {@link #values}.
     *
     * @return value of values variable {@link #values}
     * @see #values
     */
    public List<IFilterable> getCells()
    {
        return this.cells;
    }

    /**
     * Getter method for the instance variable {@link #parent}.
     *
     * @return value of instance variable {@link #parent}
     */
    public AbstractUIObject getParent()
    {
        return this.parent;
    }

    /**
     * @see org.efaps.ui.wicket.models.AbstractInstanceObject#getInstanceFromManager()
     * @throws EFapsException on error
     * @return Instance
     */
    @Override
    public Instance getInstanceFromManager()
        throws EFapsException
    {
        return getParent().getInstanceFromManager();
    }

    /**
     * @see org.efaps.ui.wicket.models.AbstractInstanceObject#hasInstanceManager()
     * @return parent
     * @throws CacheReloadException on error
     */
    @Override
    public boolean hasInstanceManager()
        throws CacheReloadException
    {
        return getParent().hasInstanceManager();
    }
}


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

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

/**
 * TODO comment!
 *
 * @author The eFaps Team
 * @version $Id$
 */
public class MessageListenerBehavior
    extends AbstractDojoBehavior
{
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    /**
     * Render to the web response whatever the component wants to contribute to
     * the head section.
     *
     * @param _component    Component this behavior belongs to
     * @param _response     Response object
     */
    @Override
    public void renderHead(final Component _component,
                           final IHeaderResponse _response)
    {
        super.renderHead(_component, _response);
        _response.render(JavaScriptHeaderItem.forScript(MessageListenerBehavior.getScript(_component),
                            _component.getClass().getName() + "_MessageListener"));

    }

    /**
     * @param _component _component the script will be rendered for
     * @return the Javascript
     */
    private static CharSequence getScript(final Component _component)
    {
        final StringBuilder js = new StringBuilder()
            .append("on(window, \"message\", function(event) {\n")
            .append("var node = dom.byId('").append(_component.getMarkupId(true)).append("');\n")
            .append("if (event.data==\"\") {\n")
            .append("domStyle.set(node, \"display\", \"none\");\n")
            .append("} else {\n")
            .append("domStyle.set(node, \"display\", \"block\");\n")
            .append("node.innerHTML = event.data;\n")
            .append("}\n")
            .append("});");
        return DojoWrapper.require(js, DojoClasses.dom, DojoClasses.domStyle, DojoClasses.on);
    }
}