/*******************************************************************************
 *  Copyright (c) 2000, 2015 IBM Corporation and others.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  which accompanies this distribution, and is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 *
 *  Contributors:
 *     IBM Corporation - initial API and implementation
 *     Alexander Kurtakov <akurtako@redhat.com> - Bug 459343
 *******************************************************************************/
package org.eclipse.core.tests.internal.utils;

import java.util.*;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.eclipse.core.internal.utils.ObjectMap;
import org.eclipse.core.tests.resources.ResourceTest;

public class ObjectMapTest extends ResourceTest {
	private static final int MAXIMUM = 100;
	private Object[] values;

	/**
	 * Need a zero argument constructor to satisfy the test harness.
	 * This constructor should not do any real work nor should it be
	 * called by user code.
	 */
	public ObjectMapTest() {
		super();
	}

	/**
	 * Creates a new markers test.
	 */
	public ObjectMapTest(String name) {
		super(name);
	}

	/**
	 * Configures the markers test suite.
	 */
	public static Test suite() {
		return new TestSuite(ObjectMapTest.class);

		//TestSuite suite = new TestSuite();
		//suite.addTest(new ObjectMapTest("_testPR"));
		//return suite;
	}

	public void testPut() {

		// create the objects to insert into the map
		ObjectMap<Integer, Object> map = new ObjectMap<>();
		int max = 100;
		Object[] values = new Object[max];
		for (int i = 0; i < max; i++) {
			values[i] = Long.valueOf(System.currentTimeMillis());
		}

		// add each object to the map
		for (int i = 0; i < values.length; i++) {
			Integer key = Integer.valueOf(i);
			map.put(key, values[i]);
			assertTrue("2.0." + i, map.containsKey(key));
			assertTrue("2.1." + i, map.containsValue(values[i]));
			assertEquals("2.2." + i, i + 1, map.size());
		}

		// make sure they are all still there
		assertEquals("3.0", max, map.size());
		for (int i = 0; i < values.length; i++) {
			Integer key = Integer.valueOf(i);
			assertTrue("3.1." + i, map.containsKey(key));
			assertNotNull("3.2." + i, map.get(key));
		}
	}

	public void testPutEmptyMap() {
		ObjectMap<Object, Object> map = new ObjectMap<>(new HashMap<>());
		map.put(new Object(), new Object());
	}

	public void testRemove() {

		// populate the map
		ObjectMap<Integer, Object> map = populateMap(MAXIMUM);

		// remove each element
		for (int i = MAXIMUM - 1; i >= 0; i--) {
			Object key = Integer.valueOf(i);
			map.remove(key);
			assertTrue("2.0." + i, !map.containsKey(key));
			assertEquals("2.1," + i, i, map.size());
			// check that the others still exist
			for (int j = 0; j < i; j++) {
				assertTrue("2.2." + j, map.containsKey(Integer.valueOf(j)));
			}
		}

		// all gone?
		assertEquals("3.0", 0, map.size());
	}

	public void testContains() {
		ObjectMap<Integer, Object> map = populateMap(MAXIMUM);

		for (int i = 0; i < MAXIMUM; i++) {
			assertTrue("2.0." + i, map.containsKey(Integer.valueOf(i)));
			assertTrue("2.1." + i, map.containsValue(values[i]));
		}

		assertFalse("3.0", map.containsKey(Integer.valueOf(MAXIMUM + 1)));
		assertFalse("3.1", map.containsKey(Integer.valueOf(-1)));
		assertFalse("3.2", map.containsValue(null));
		assertFalse("3.3", map.containsValue(getRandomString()));
	}

	public void testValues() {
		ObjectMap<Integer, Object> map = populateMap(MAXIMUM);

		Collection<Object> result = map.values();
		for (int i = 0; i < MAXIMUM; i++) {
			assertTrue("2.0." + i, result.contains(values[i]));
		}
	}

	public void testKeySet() {
		ObjectMap<Integer, Object> map = populateMap(MAXIMUM);
		Set<Integer> keys = map.keySet();
		assertEquals("1.0", MAXIMUM, keys.size());
	}

	public void testEntrySet() {
		ObjectMap<Integer, Object> map = populateMap(MAXIMUM);
		Set<Map.Entry<Integer, Object>> entries = map.entrySet();
		for (int i = 0; i < MAXIMUM; i++) {
			assertTrue("1.0." + i, contains(entries, values[i]));
		}
	}

	/**
	 * The given set is a set of Map.Entry objects.
	 */
	private boolean contains(Set<Map.Entry<Integer, Object>> set, Object value) {
		for (Map.Entry<Integer, Object> entry : set) {
			if (entry.getValue().equals(value)) {
				return true;
			}
		}
		return false;
	}

	private ObjectMap<Integer, Object> populateMap(int max) {
		// populate the map
		ObjectMap<Integer, Object> map = new ObjectMap<>();
		values = new Object[max];
		for (int i = 0; i < max; i++) {
			values[i] = Long.valueOf(System.currentTimeMillis());
			map.put(Integer.valueOf(i), values[i]);
		}
		assertEquals("#populateMap", max, map.size());
		return map;
	}

	/*
	 * Bug 62231 - empty ObjectMap.toHashMap() causes NullPointerException
	 */
	public void testBug_62231() {
		ObjectMap<Object, Object> map = new ObjectMap<>();
		try {
			map.entrySet();
		} catch (NullPointerException e) {
			fail("1.0");
		}
		map.clear();
		try {
			map.entrySet();
		} catch (NullPointerException e) {
			fail("1.1");
		}

	}
}
