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

package net.ranides.assira.collection.map;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import net.ranides.assira.math.Randomizer;
import net.ranides.assira.text.format.AnsiString;
import net.ranides.assira.time.TimeStack;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.Ignore;

/**
 *
 * @author Mariusz Sieron <m.sieron@samsung.com>
 */
public class ColumnTest {


    private static final Column<String, Float> FIELD_X = Column.make("x", Float.class);
    private static final Column<String, Float> FIELD_Y = Column.make("y", Float.class);
    private static final Column<String, Integer> FIELD_Z = Column.make("z", Integer.class);
    private static final Column<String, Long> FIELD_ID = Column.make("id", Long.class);

    private static final Column<String, String> FIELD_A = Column.make("a", String.class);
    private static final Column<String, CharSequence> FIELD_B = Column.make("b", CharSequence.class);


    @Test
    public void testGet() {
        Float vx = 2.5f;
        Float vy = 3.5f;
        Integer vz = 15;
        Long vid = 1017L;
        String va = "hello";
        AnsiString vb = new AnsiString("world");

        Map<String, Number> idata = new HashMap<>();
        idata.put("x", vx);
        idata.put("y", vy);
        idata.put("z", vz);
        idata.put("id", vid);

        Map<String, CharSequence> sdata = new HashMap<>();
        sdata.put("a", va);
        sdata.put("b", vb);

        Map<String, Object> odata = new HashMap<>();
        odata.putAll(idata);
        odata.putAll(sdata);

        assertEquals(vx, FIELD_X.get(idata), 1e-4f);
        assertEquals(vy, FIELD_Y.get(idata), 1e-4f);
        assertEquals(vz, FIELD_Z.get(idata) );
        assertEquals(vid, FIELD_ID.get(idata) );

        assertEquals(va, FIELD_A.get(sdata));
        assertEquals(vb, FIELD_B.get(sdata));

    }

    @Test
    public void testEntry() {

        Map<String, Integer> map1 = new HashMap<>();
        Map<String, Integer> map2 = new TreeMap<>();
        Map<String, Integer> map3 = new ConcurrentHashMap<>();

        map1.put("a", 17);
        map2.put("b", 14);
        map3.put("c", 11);

        final Entry<String,Integer> entry1 = Column.entry(map1, "a");
        entry1.setValue(entry1.getValue() + 1);

        final Entry<String,Integer> entry2 = Column.entry(map2, "b");
        entry2.setValue(entry2.getValue() + 1);

        final Entry<String,Integer> entry3 = Column.entry(map3, "c");
        entry3.setValue(entry3.getValue() + 1);

        assertEquals( (Integer)18, map1.get("a"));
        assertEquals( (Integer)15, map2.get("b"));
        assertEquals( (Integer)12, map3.get("c"));
    }

    @Test
    public void testEntryColumn() {

        final Column<String, Integer> FA = Column.make("a", Integer.class);
        final Column<String, Integer> FB = Column.make("b", Integer.class);

        Map<String, Integer> map1 = new HashMap<>();
        Map<String, Integer> map2 = new TreeMap<>();

        FA.put(map1, 17);
        FB.put(map2, 14);

        final Entry<String,Integer> entry1 = FA.entry(map1);
        entry1.setValue(entry1.getValue() + 1);

        final Entry<String,Integer> entry2 = FB.entry(map2);
        entry2.setValue(entry2.getValue() + 1);

        assertEquals( (Integer)18, map1.get("a"));
        assertEquals( (Integer)15, map2.get("b"));
    }

    /**
     * Number of keys = 128'000
     *      | put   opt   dve  | det
     * -----+------------------+-------
     * Tree | 8800  6400  -    |  72 %
     * Hash | 1300  1600  1800 | 123 %
     * Conc | 2000  4100  2300 | 115 %
     *
     * Number of keys = 128
     *      | put   opt   dve  | det
     * -----+------------------+-------
     * Tree | 6500  4600  -    |  70 %
     * Hash | 1800  1600  3200 |  88 %
     * Conc | 5700  11600 6700 | 117 %
     */
    @Ignore("manual slow")
    @Test
    public void testPerfEntry() {

        String[] keys = new String[128];
        for(int i=0, n=keys.length; i<n; i++) {
            keys[i] = Randomizer.text(32);
        }

        Map<String, Integer> treemap = new TreeMap<>();
        Map<String, Integer> hashmap = new HashMap<>();
        Map<String, Integer> concmap = new ConcurrentHashMap<>();
        for(String key : keys) {
            treemap.put(key, Randomizer.number(1000));
            hashmap.put(key, Randomizer.number(1000));
            concmap.put(key, Randomizer.number(1000));
        }

        runPerfEntry(keys, 1000000, treemap);
        runPerfEntry(keys, 1000000, hashmap);
        runPerfEntry(keys, 1000000, concmap);
    }

    private void runPerfEntry(String[] keys, int count, Map<String, Integer> map) {
        TimeStack ts = new TimeStack();

        ts.start();
        for(int t=0; t<count; t++) {
            for(String key : keys) {
                map.put(key, map.get(key)+1);
            }
        }

        long t1 = ts.restart();

        for(int t=0; t<count; t++) {
            for(String key : keys) {
                final Entry<String, Integer> entry = Column.entry(map, key);
                entry.setValue(entry.getValue()+1);
            }
        }

        long t2 = ts.stop();

        System.out.println("time = " + t1 + " / " + t2);

    }


}
