package rocks.inspectit.ui.rcp.preferences.valueproviders;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.commons.collections.MapUtils;

import rocks.inspectit.ui.rcp.preferences.PreferenceException;
import rocks.inspectit.ui.rcp.preferences.PreferencesConstants;
import rocks.inspectit.ui.rcp.preferences.valueproviders.PreferenceValueProviderFactory.PreferenceValueProvider;

/**
 * This {@link PreferenceValueProvider} converts any map that has keys and values in primitive
 * warper types to preference value. Later on this preference value will be transformed to a map
 * that has both string as key and value, and thus needs transformation to initial classes of keys
 * and values.
 *
 * @author Ivan Senic
 *
 */
public class MapPreferenceValueProvider extends PreferenceValueProvider<Map<?, ?>> {

	/**
	 * Constant for denoting the empty map.
	 */
	private static final String EMPTY_MAP = "EMPTY_MAP";

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean isObjectValid(Object object) {
		return object instanceof Map;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getValueForObject(Map<?, ?> map) throws PreferenceException {
		if (MapUtils.isEmpty(map)) {
			return EMPTY_MAP;
		} else {
			StringBuilder stringBuilder = new StringBuilder();
			for (Map.Entry<?, ?> entry : map.entrySet()) {
				stringBuilder.append(String.valueOf(entry.getKey()));
				stringBuilder.append(PreferencesConstants.PREF_SPLIT_REGEX);
				stringBuilder.append(entry.getValue());
				stringBuilder.append(PreferencesConstants.PREF_OBJECT_SEPARATION_TOKEN);
			}
			return stringBuilder.toString();
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Map<?, ?> getObjectFromValue(String value) throws PreferenceException {
		if (EMPTY_MAP.equals(value)) {
			return Collections.emptyMap();
		} else {
			Map<String, String> map = new HashMap<>();
			StringTokenizer tokenizer = new StringTokenizer(value, PreferencesConstants.PREF_OBJECT_SEPARATION_TOKEN);
			while (tokenizer.hasMoreElements()) {
				String nextEntry = tokenizer.nextToken();
				String[] splitted = nextEntry.split(PreferencesConstants.PREF_SPLIT_REGEX);
				if (splitted.length == 2) {
					map.put(splitted[0], splitted[1]);
				} else {
					throw new PreferenceException("Error loading map entry for the map saved in the preference store are not correct.  Entry key and value received values via the string '" + nextEntry
							+ "' are " + Arrays.asList(splitted) + ". Definition will be skipped.");
				}
			}
			return map;
		}
	}

}
