/*******************************************************************************
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 *
 * This program and the accompanying materials 
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.ui.internal.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashPipe;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;

public final class Util {
	
    public final static SortedMap EMPTY_SORTED_MAP = Collections
            .unmodifiableSortedMap(new TreeMap());

    public final static SortedSet EMPTY_SORTED_SET = Collections
            .unmodifiableSortedSet(new TreeSet());

    public final static String ZERO_LENGTH_STRING = ""; //$NON-NLS-1$

	/**
	 * Ensures that a string is not null. Converts null strings into empty
	 * strings, and leaves any other string unmodified. Use this to help
	 * wrap calls to methods that return null instead of the empty string.
	 * Can also help protect against implementation errors in methods that
	 * are not supposed to return null. 
	 * 
	 * @param input input string (may be null)
	 * @return input if not null, or the empty string if input is null
	 */
	public static String safeString(String input) {
		if (input != null) {
			return input;
		}
		
		return ZERO_LENGTH_STRING;
	}
    
    public static void assertInstance(Object object, Class c) {
        assertInstance(object, c, false);
    }

    public static void assertInstance(Object object, Class c, boolean allowNull) {
        if (object == null && allowNull) return;

        if (object == null || c == null)
            throw new NullPointerException();
        else if (!c.isInstance(object)) throw new IllegalArgumentException();
    }

    public static int compare(boolean left, boolean right) {
        return left == false ? (right == true ? -1 : 0) : 1;
    }

    public static int compare(Comparable left, Comparable right) {
        if (left == null && right == null)
            return 0;
        else if (left == null)
            return -1;
        else if (right == null)
            return 1;
        else
            return left.compareTo(right);
    }

    public static int compare(Comparable[] left, Comparable[] right) {
        if (left == null && right == null)
            return 0;
        else if (left == null)
            return -1;
        else if (right == null)
            return 1;
        else {
            int l = left.length;
            int r = right.length;

            if (l != r)
                return l - r;
            else {
                for (int i = 0; i < l; i++) {
                    int compareTo = compare(left[i], right[i]);

                    if (compareTo != 0) return compareTo;
                }

                return 0;
            }
        }
    }

    public static int compare(int left, int right) {
        return left - right;
    }

    public static int compare(List left, List right) {
        if (left == null && right == null)
            return 0;
        else if (left == null)
            return -1;
        else if (right == null)
            return 1;
        else {
            int l = left.size();
            int r = right.size();

            if (l != r)
                return l - r;
            else {
                for (int i = 0; i < l; i++) {
                    int compareTo = compare((Comparable) left.get(i),
                            (Comparable) right.get(i));

                    if (compareTo != 0) return compareTo;
                }

                return 0;
            }
        }
    }

    public static int compare(Object left, Object right) {
        if (left == null && right == null)
            return 0;
        else if (left == null)
            return -1;
        else if (right == null)
            return 1;
        else
            return left.toString().compareTo(right.toString());
    }

    public static void diff(Map left, Map right, Set leftOnly, Set different,
            Set rightOnly) {
        if (left == null || right == null || leftOnly == null
                || different == null || rightOnly == null)
                throw new NullPointerException();

        Iterator iterator = left.keySet().iterator();

        while (iterator.hasNext()) {
            Object key = iterator.next();

            if (!right.containsKey(key))
                leftOnly.add(key);
            else if (!Util.equals(left.get(key), right.get(key)))
                    different.add(key);
        }

        iterator = right.keySet().iterator();

        while (iterator.hasNext()) {
            Object key = iterator.next();

            if (!left.containsKey(key)) rightOnly.add(key);
        }
    }

    public static void diff(Set left, Set right, Set leftOnly, Set rightOnly) {
        if (left == null || right == null || leftOnly == null
                || rightOnly == null) throw new NullPointerException();

        Iterator iterator = left.iterator();

        while (iterator.hasNext()) {
            Object object = iterator.next();

            if (!right.contains(object)) leftOnly.add(object);
        }

        iterator = right.iterator();

        while (iterator.hasNext()) {
            Object object = iterator.next();

            if (!left.contains(object)) rightOnly.add(object);
        }
    }

    public static boolean endsWith(List left, List right, boolean equals) {
        if (left == null || right == null)
            return false;
        else {
            int l = left.size();
            int r = right.size();

            if (r > l || !equals && r == l) return false;

            for (int i = 0; i < r; i++)
                if (!equals(left.get(l - i - 1), right.get(r - i - 1)))
                        return false;

            return true;
        }
    }

    public static boolean endsWith(Object[] left, Object[] right, boolean equals) {
        if (left == null || right == null)
            return false;
        else {
            int l = left.length;
            int r = right.length;

            if (r > l || !equals && r == l) return false;

            for (int i = 0; i < r; i++)
                if (!equals(left[l - i - 1], right[r - i - 1])) return false;

            return true;
        }
    }

    public static boolean equals(boolean left, boolean right) {
        return left == right;
    }

    public static boolean equals(int left, int right) {
        return left == right;
    }

    public static boolean equals(Object left, Object right) {
        return left == null ? right == null : ((right != null) && left
                .equals(right));
    }

    public static int hashCode(boolean b) {
        return b ? Boolean.TRUE.hashCode() : Boolean.FALSE.hashCode();
    }

    public static int hashCode(int i) {
        return i;
    }

    public static int hashCode(Object object) {
        return object != null ? object.hashCode() : 0;
    }

    public static Collection safeCopy(Collection collection, Class c) {
        return safeCopy(collection, c, false);
    }

    public static Collection safeCopy(Collection collection, Class c,
            boolean allowNullElements) {
        if (collection == null || c == null) throw new NullPointerException();

        collection = Collections.unmodifiableCollection(new ArrayList(collection));
        Iterator iterator = collection.iterator();

        while (iterator.hasNext())
            assertInstance(iterator.next(), c, allowNullElements);

        return collection;
    }

    public static List safeCopy(List list, Class c) {
        return safeCopy(list, c, false);
    }

    public static List safeCopy(List list, Class c, boolean allowNullElements) {
        if (list == null || c == null) throw new NullPointerException();

        list = Collections.unmodifiableList(new ArrayList(list));
        Iterator iterator = list.iterator();

        while (iterator.hasNext())
            assertInstance(iterator.next(), c, allowNullElements);

        return list;
    }

    public static Map safeCopy(Map map, Class keyClass, Class valueClass) {
        return safeCopy(map, keyClass, valueClass, false, false);
    }

    public static Map safeCopy(Map map, Class keyClass, Class valueClass,
            boolean allowNullKeys, boolean allowNullValues) {
        if (map == null || keyClass == null || valueClass == null)
                throw new NullPointerException();

        map = Collections.unmodifiableMap(new HashMap(map));
        Iterator iterator = map.entrySet().iterator();

        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            assertInstance(entry.getKey(), keyClass, allowNullKeys);
            assertInstance(entry.getValue(), valueClass, allowNullValues);
        }

        return map;
    }

    public static Set safeCopy(Set set, Class c) {
        return safeCopy(set, c, false);
    }

    public static Set safeCopy(Set set, Class c, boolean allowNullElements) {
        if (set == null || c == null) throw new NullPointerException();

        set = Collections.unmodifiableSet(new HashSet(set));
        Iterator iterator = set.iterator();

        while (iterator.hasNext())
            assertInstance(iterator.next(), c, allowNullElements);

        return set;
    }

    public static SortedMap safeCopy(SortedMap sortedMap, Class keyClass,
            Class valueClass) {
        return safeCopy(sortedMap, keyClass, valueClass, false, false);
    }

    public static SortedMap safeCopy(SortedMap sortedMap, Class keyClass,
            Class valueClass, boolean allowNullKeys, boolean allowNullValues) {
        if (sortedMap == null || keyClass == null || valueClass == null)
                throw new NullPointerException();

        sortedMap = Collections.unmodifiableSortedMap(new TreeMap(sortedMap));
        Iterator iterator = sortedMap.entrySet().iterator();

        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            assertInstance(entry.getKey(), keyClass, allowNullKeys);
            assertInstance(entry.getValue(), valueClass, allowNullValues);
        }

        return sortedMap;
    }

    public static SortedSet safeCopy(SortedSet sortedSet, Class c) {
        return safeCopy(sortedSet, c, false);
    }

    public static SortedSet safeCopy(SortedSet sortedSet, Class c,
            boolean allowNullElements) {
        if (sortedSet == null || c == null) throw new NullPointerException();

        sortedSet = Collections.unmodifiableSortedSet(new TreeSet(sortedSet));
        Iterator iterator = sortedSet.iterator();

        while (iterator.hasNext())
            assertInstance(iterator.next(), c, allowNullElements);

        return sortedSet;
    }

    public static boolean startsWith(List left, List right, boolean equals) {
        if (left == null || right == null)
            return false;
        else {
            int l = left.size();
            int r = right.size();

            if (r > l || !equals && r == l) return false;

            for (int i = 0; i < r; i++)
                if (!equals(left.get(i), right.get(i))) return false;

            return true;
        }
    }

    public static boolean startsWith(Object[] left, Object[] right,
            boolean equals) {
        if (left == null || right == null)
            return false;
        else {
            int l = left.length;
            int r = right.length;

            if (r > l || !equals && r == l) return false;

            for (int i = 0; i < r; i++)
                if (!equals(left[i], right[i])) return false;

            return true;
        }
    }

    public static String translateString(ResourceBundle resourceBundle,
            String key) {
        return Util.translateString(resourceBundle, key, key, true, true);
    }

    public static String translateString(ResourceBundle resourceBundle,
            String key, String string, boolean signal, boolean trim) {
        if (resourceBundle != null && key != null)
                try {
                    final String translatedString = resourceBundle
                            .getString(key);

                    if (translatedString != null)
                            return trim ? translatedString.trim()
                                    : translatedString;
                } catch (MissingResourceException eMissingResource) {
                    if (signal) System.err.println(eMissingResource);
                }

        return trim ? string.trim() : string;
    }

    private Util() {
    }
}
