/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.collection.suite.maps;

import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.function.Function;
import javax.annotation.Resource;
import net.ranides.assira.collection.maps.IntMap;
import net.ranides.assira.collection.maps.IntMap.IntEntry;
import net.ranides.assira.test.TMap;
import net.ranides.assira.test.TMap.TItem;
import static net.ranides.assira.junit.NewAssert.*;
import net.ranides.assira.junit.TestContract;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
@SuppressWarnings("PMD.MethodNameRules")
public final class IntMapTester<V> {
    
    @Resource(name = "map!")
    private TMap<Integer,V> $var;
    
    @Resource(name = "map.default!")
    private V $default = null;
    
    @TestContract
    public void basicEntrySet_Contains(Function<int[], IntMap<V>> f) {
        IntMap<V> target = f.apply(new int[]{1,2,3,5});
        Set<IntEntry<V>> set = target.fastEntrySet();

		assertEquals(4, set.size());
        assertEquals(true, set.contains($var.item(1).entryInt()));
        assertEquals(true, set.contains($var.item(2).entryInt()));
        assertEquals(true, set.contains($var.item(3).entryInt()));
        assertEquals(true, set.contains($var.item(5).entryInt()));
        
        assertEquals(false, set.contains($var.item(4).entryInt()));
        assertEquals(false, set.contains(new Object()));
        
	}
    
    @TestContract
    public void basicEntrySet_Remove(Function<int[], IntMap<V>> f) {
        IntMap<V> target = f.apply(new int[]{1,2,3,7});
        Set<IntEntry<V>> set = target.fastEntrySet();
		
        assertEquals(false, set.remove($var.item(1).entryInt(5)));
        assertEquals(true, set.remove($var.item(1).entryInt()));
        assertEquals(false, set.remove($var.item(4).entryInt()));
        assertEquals(false, set.remove(new Object()));
        
        assertEquals(false, set.contains($var.item(1).entryInt()));
        assertEquals(true, set.contains($var.item(2).entryInt()));
        assertEquals(true, set.contains($var.item(3).entryInt()));
        assertEquals(true, set.contains($var.item(7).entryInt()));
        
	}
    
    @TestContract
    public void basicEntrySet_Iterator(Function<int[], IntMap<V>> f) {
        IntMap<V> target = f.apply(new int[]{1,2,3,5});
        Set<IntEntry<V>> set = target.fastEntrySet();
		
		assertEquals(4, set.size());

        Iterator<IntEntry<V>> iterator = set.iterator();
        while(iterator.hasNext()) {
            IntEntry<V> entry = iterator.next();
            assertEquals(target.get(entry.getIntKey()), entry.getValue());
        }
        
        assertThrows(NoSuchElementException.class, ()-> iterator.next());
	}
    
    @TestContract
    public void basicEntrySet_Iterator_SetValue(IntMap<V> target) {
        Set<IntEntry<V>> set = target.fastEntrySet();
                
		assertEquals(0, set.size());
		$var.list(1,2,3,5).into(target);
        int k1 = $var.item(1).keyInt();
		int k2 = $var.item(2).keyInt();
        V v1 = $var.item(101).value();
        V v2 = $var.item(102).value();
		
		Iterator<IntEntry<V>> iterator = set.iterator();
		while(iterator.hasNext()) {
			IntEntry<V> entry = iterator.next();
			if(k1 == entry.getIntKey()) {
                entry.setValue(v1);
            }
            if(k2 == entry.getIntKey()) {
                entry.setValue(v2);
            }
		}
		assertContains(target, $var.item(1).keyInt(), v1);
		assertContains(target, $var.item(2).keyInt(), v2);
		assertContains(target, $var.item(5));
		assertContains(target, $var.item(3));
	}
    
    @TestContract
    public void basicEntrySet_Iterator_Remove(Function<int[], IntMap<V>> f) {
        IntMap<V> target = f.apply(new int[]{1,2,3,5});
        Set<IntEntry<V>> set = target.fastEntrySet();
        
        int k1 = $var.item(1).keyInt();
		int k2 = $var.item(2).keyInt();
		
		Iterator<IntEntry<V>> iterator = set.iterator();
		while(iterator.hasNext()) {
			IntEntry<V> entry = iterator.next();
            int key = entry.getKey();
            
			if(k1 == key) {
                iterator.remove();
            }
            if(k2 == key) {
                iterator.remove();
                assertThrows(IllegalStateException.class, ()-> iterator.remove());
            }
		}
        
        assertEquals(2, target.size());
        assertNotContains(target, $var.item(1));
        assertNotContains(target, $var.item(2));
		assertContains(target, $var.item(3));
		assertContains(target, $var.item(5));
        
        set.clear();
        assertEquals(0, target.size());
	}
    
    @TestContract
    public void basicEntrySet_Iterator_RemoveAll(Function<int[], IntMap<V>> f) {
        IntMap<V> target = f.apply($var.range(1024).indexes());
        
        Set<IntEntry<V>> set = target.fastEntrySet();
        
        ;
            
		Iterator<IntEntry<V>> iterator = set.iterator();
		while(iterator.hasNext()) {
			iterator.next();
            iterator.remove();
		}
        assertEquals(0, target.size());
	}
    
	private void assertContains(IntMap<V> target, int key, V value) {
        assertEquals(true, target.containsKey(key));
        assertEquals(value, target.get(key));
    }
    
    private void assertContains(IntMap<V> target, TItem<?,V> item) {
		assertContains(target, item.keyInt(), item.value());
    }
    
    private void assertNotContains(IntMap<V> target, TItem<?,V> item) {
        assertEquals(false, target.containsKey(item.keyInt()));
        assertEquals($default, target.get(item.keyInt()));
    }
	
}
