package be.iminds.ilabt.jfed.lowlevel.stitching;

import org.testng.Assert;
import org.testng.annotations.Test;

import java.util.*;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;

/**
 * VlanRangeHelperTest
 */
public class VlanRangeTest {
    @Test
    public void testRange() {
        String a = "5012";
        String b = "1";
        String c = "13-987";

        VlanRange.Range rA = new VlanRange.Range(a);
        VlanRange.Range rb = new VlanRange.Range(b);
        VlanRange.Range rc = new VlanRange.Range(c);

        Assert.assertEquals(rA.from, 5012);
        Assert.assertEquals(rA.to, 5012);
        Assert.assertEquals(rb.from, 1);
        Assert.assertEquals(rb.to, 1);
        Assert.assertEquals(rc.from, 13);
        Assert.assertEquals(rc.to, 987);
        Assert.assertEquals(rA, new VlanRange.Range(5012, 5012));
        Assert.assertEquals(rA, new VlanRange.Range(5012));
        Assert.assertEquals(rc, new VlanRange.Range(13, 987));
        Assert.assertEquals(rc, new VlanRange.Range(rc));
        Assert.assertEquals(rb, new VlanRange.Range(rb));
        Assert.assertEquals(rA, new VlanRange.Range(rA));
    }

    @Test
    public void testRangeSplit() {
        String a = "10";
        String b = "5-6";
        String c = "20-30";

        VlanRange.Range rA = new VlanRange.Range(a);
        VlanRange.Range rB = new VlanRange.Range(b);
        VlanRange.Range rC = new VlanRange.Range(c);

        VlanRange.Range.Pair<VlanRange.Range, VlanRange.Range> splitA = rA.split(10);
        VlanRange.Range.Pair<VlanRange.Range, VlanRange.Range> splitB1 = rB.split(5);
        VlanRange.Range.Pair<VlanRange.Range, VlanRange.Range> splitB2 = rB.split(6);
        VlanRange.Range.Pair<VlanRange.Range, VlanRange.Range> splitC1 = rC.split(20);
        VlanRange.Range.Pair<VlanRange.Range, VlanRange.Range> splitC2 = rC.split(21);
        VlanRange.Range.Pair<VlanRange.Range, VlanRange.Range> splitC3 = rC.split(25);
        VlanRange.Range.Pair<VlanRange.Range, VlanRange.Range> splitC4 = rC.split(29);
        VlanRange.Range.Pair<VlanRange.Range, VlanRange.Range> splitC5 = rC.split(30);

        Assert.assertNull(splitA.getFirst());
        Assert.assertNull(splitA.getSecond());

        Assert.assertNull(splitB1.getFirst());
        Assert.assertEquals(splitB1.getSecond(), new VlanRange.Range(6, 6));

        Assert.assertEquals(splitB2.getFirst(), new VlanRange.Range(5, 5));
        Assert.assertNull(splitB2.getSecond());

        Assert.assertNull(splitC1.getFirst());
        Assert.assertEquals(splitC1.getSecond(), new VlanRange.Range(21, 30));

        Assert.assertEquals(splitC2.getFirst(), new VlanRange.Range(20, 20));
        Assert.assertEquals(splitC2.getSecond(), new VlanRange.Range(22, 30));

        Assert.assertEquals(splitC3.getFirst(), new VlanRange.Range(20, 24));
        Assert.assertEquals(splitC3.getSecond(), new VlanRange.Range(26, 30));

        Assert.assertEquals(splitC4.getFirst(), new VlanRange.Range(20, 28));
        Assert.assertEquals(splitC4.getSecond(), new VlanRange.Range(30, 30));

        Assert.assertEquals(splitC5.getFirst(), new VlanRange.Range(20, 29));
        Assert.assertNull(splitC5.getSecond());
    }

    @Test
    public void testVlanRangeHelperRemoveAllSimple() {
        String exa = "5,15-16,20-22";

        VlanRange ha = new VlanRange(exa);
        SortedSet<Integer> unavailableVlans = new TreeSet<Integer>();
        unavailableVlans.add(5);
        unavailableVlans.add(15);
        unavailableVlans.add(21);

        String targetA = "16,20,22";
        VlanRange targetHa = new VlanRange(targetA);

        ha.removeAll(unavailableVlans);
        Assert.assertEquals(targetHa, ha, "VlanRangeHelper must be equal");
    }

    @Test
    public void testVlanRangeHelperRetainAllSimple() {
        String exa = "5,15-16,20-22";

        VlanRange ha = new VlanRange(exa);
        assertThat(ha, hasSize(6));
        SortedSet<Integer> unavailableVlans = new TreeSet<Integer>();
        unavailableVlans.add(5);
        unavailableVlans.add(15);
        unavailableVlans.add(21);
        assertThat(ha, hasSize(6));
        Set<Integer> availableVlans = new HashSet<Integer>(ha);
        assertThat(ha, hasSize(6));
        availableVlans.removeAll(unavailableVlans);
        assertThat(ha, hasSize(6));

        String targetA = "16,20,22";
        VlanRange targetHa = new VlanRange(targetA);
        assertThat(targetHa, hasSize(3));

        ha.retainAll(availableVlans);
        assertThat(targetHa, equalTo(ha));
    }

    @Test
    public void testCollectionConstructor() {
        String exa = "5,10,15-16,20-22,28-35,50,100-101";
        VlanRange a = new VlanRange(exa);
        VlanRange b = new VlanRange(new ArrayList<Integer>(a));
        List<Integer> l = Arrays.asList(5,10,15,16,20,21,22,28,29,30,31,32,33,34,35,50,100,101);
        VlanRange c = new VlanRange(l);

        assertThat(a, equalTo(b));
        assertThat(a, equalTo(c));
    }

    @Test
    public void testCollectionConstructor2() {
        String exa = "5,10,15-16,20-22,28-35,50,100-101";
        VlanRange a = new VlanRange(exa);
        VlanRange aa = new VlanRange(exa);
        VlanRange b = new VlanRange(a);
        List<Integer> l = Arrays.asList(5,10,15,16,20,21,22,28,29,30,31,32,33,34,35,50,100,101);
        VlanRange c = new VlanRange(b);
        List<Integer> l2 = new ArrayList<Integer>(a);

        assertThat(l, equalTo(l2));
        assertThat(a, equalTo(aa));
        assertThat(a, equalTo(b));
        assertThat(a, equalTo(c));
    }
    @Test
    public void testCollectionConstructor3() {
        String exa = "197,300-303,305,750-755";
        VlanRange a = new VlanRange(exa);
        VlanRange aa = new VlanRange(exa);
        VlanRange b = new VlanRange(a);
        List<Integer> l = Arrays.asList(197,300,301,302,303,305,750,751,752,753,754,755);
        VlanRange c = new VlanRange(b);
        List<Integer> l2 = new ArrayList<Integer>(a);

        assertThat(l, equalTo(l2));
        assertThat(a, equalTo(aa));
        assertThat(a, equalTo(b));
        assertThat(a, equalTo(c));
    }

    @Test
    public void testVlanRangeHelperSplitComplex() {
        String exa = "5,7,10,15-16,20-21,25-26,28-29,30-32,40-42,50-52,130-132,140-142,150-152,160-162,1000-2000";

        VlanRange ha = new VlanRange(exa);
        SortedSet<Integer> unavailableVlans = new TreeSet<Integer>();
        unavailableVlans.add(5);
        unavailableVlans.add(10);
        unavailableVlans.add(15);
        unavailableVlans.add(21);
        unavailableVlans.add(28);
        unavailableVlans.add(29);
        unavailableVlans.add(30);
        unavailableVlans.add(41);
        unavailableVlans.add(52);
        unavailableVlans.add(130);
        unavailableVlans.add(131);
        unavailableVlans.add(141);
        unavailableVlans.add(142);
        unavailableVlans.add(150);
        unavailableVlans.add(152);
        unavailableVlans.add(160);
        unavailableVlans.add(161);
        unavailableVlans.add(162);
        unavailableVlans.add(1000);
        unavailableVlans.add(1500);
        unavailableVlans.add(1600);
        unavailableVlans.add(1700);
        unavailableVlans.add(2000);

        String targetA = "7,16,20,25-26,31-32,40,42,50-51,132,140,151,1001-1499,1501-1599,1601-1699,1701-1999";
        VlanRange targetHa = new VlanRange(targetA);

        ha.removeAll(unavailableVlans);
        Assert.assertEquals(targetHa, ha, "VlanRangeHelper must be equal");
    }

    @Test
    public void testVlanRangeHelper() {
        String exa = "3726-3732,3747-3749";
        String exb = "3726-3732,3747";
        String exc = "670,3726-3750";
        String exd = "2-4094";
        String exe = "300";
        String exf = "580,722";
        String exg = "580,722,1024,18-30";

        VlanRange ha = new VlanRange(exa);
        VlanRange hb = new VlanRange(exb);
        VlanRange hc = new VlanRange(exc);
        VlanRange hd = new VlanRange(exd);
        VlanRange he = new VlanRange(exe);
        VlanRange hf = new VlanRange(exf);
        VlanRange hg = new VlanRange(exg);

        Assert.assertEquals(ha.getRanges().size(), ha.getRanges().size());
        Assert.assertEquals(hb.getRanges().size(), hb.getRanges().size());
        Assert.assertEquals(hc.getRanges().size(), hc.getRanges().size());
        Assert.assertEquals(hd.getRanges().size(), hd.getRanges().size());
        Assert.assertEquals(he.getRanges().size(), he.getRanges().size());
        Assert.assertEquals(hf.getRanges().size(), hf.getRanges().size());
        Assert.assertEquals(hg.getRanges().size(), hg.getRanges().size());

        Assert.assertEquals(ha.getRanges(), ha.getRanges());
        Assert.assertEquals(hb.getRanges(), hb.getRanges());
        Assert.assertEquals(hc.getRanges(), hc.getRanges());
        Assert.assertEquals(hd.getRanges(), hd.getRanges());
        Assert.assertEquals(he.getRanges(), he.getRanges());
        Assert.assertEquals(hf.getRanges(), hf.getRanges());
        Assert.assertEquals(hg.getRanges(), hg.getRanges());

        Assert.assertEquals(ha.getRanges().size(), 2);
        Assert.assertEquals(hb.getRanges().size(), 2);
        Assert.assertEquals(hc.getRanges().size(), 2);
        Assert.assertEquals(hd.getRanges().size(), 1);
        Assert.assertEquals(he.getRanges().size(), 1);
        Assert.assertEquals(hf.getRanges().size(), 2);
        Assert.assertEquals(hg.getRanges().size(), 4);

        List<VlanRange.Range> rangesa = new ArrayList<VlanRange.Range>();
        List<VlanRange.Range> rangesb = new ArrayList<VlanRange.Range>();
        List<VlanRange.Range> rangesc = new ArrayList<VlanRange.Range>();
        List<VlanRange.Range> rangesd = new ArrayList<VlanRange.Range>();
        List<VlanRange.Range> rangese = new ArrayList<VlanRange.Range>();
        List<VlanRange.Range> rangesf = new ArrayList<VlanRange.Range>();
        List<VlanRange.Range> rangesg = new ArrayList<VlanRange.Range>();
        rangesa.add(new VlanRange.Range(3726, 3732));
        rangesa.add(new VlanRange.Range(3747, 3749));
        rangesb.add(new VlanRange.Range(3726, 3732));
        rangesb.add(new VlanRange.Range(3747));
        rangesc.add(new VlanRange.Range(670));
        rangesc.add(new VlanRange.Range(3726, 3750));
        rangesd.add(new VlanRange.Range(2, 4094));
        rangese.add(new VlanRange.Range(300));
        rangesf.add(new VlanRange.Range(580));
        rangesf.add(new VlanRange.Range(722));
        rangesg.add(new VlanRange.Range(580));
        rangesg.add(new VlanRange.Range(722));
        rangesg.add(new VlanRange.Range(1024));
        rangesg.add(new VlanRange.Range(18, 30));

        Assert.assertEquals(ha.getRanges(), rangesa);
        Assert.assertEquals(hb.getRanges(), rangesb);
        Assert.assertEquals(hc.getRanges(), rangesc);
        Assert.assertEquals(hd.getRanges(), rangesd);
        Assert.assertEquals(he.getRanges(), rangese);
        Assert.assertEquals(hf.getRanges(), rangesf);
        Assert.assertEquals(hg.getRanges(), rangesg);

        Iterator<Integer> itA = ha.iterator();
        Assert.assertTrue(itA.hasNext());
        Assert.assertEquals(itA.next(), new Integer(3726));
        Assert.assertTrue(itA.hasNext());
        Assert.assertEquals(itA.next(), new Integer(3727));
        Assert.assertTrue(itA.hasNext());
        Assert.assertEquals(itA.next(), new Integer(3728));

        Iterator<Integer> itC = hc.iterator();
        Assert.assertTrue(itC.hasNext());
        Assert.assertEquals(itC.next(), new Integer(670));
        Assert.assertTrue(itC.hasNext());
        Assert.assertEquals(itC.next(), new Integer(3726));
        Assert.assertTrue(itC.hasNext());
        Assert.assertEquals(itC.next(), new Integer(3727));

        Iterator<Integer> itF = hf.iterator();
        Assert.assertTrue(itF.hasNext());
        Assert.assertEquals(itF.next(), (Integer) 580);
        Assert.assertTrue(itF.hasNext());
        Assert.assertEquals(itF.next(), (Integer) 722);
        Assert.assertFalse(itF.hasNext());

        Iterator<Integer> itG = hg.iterator();
        Assert.assertTrue(itG.hasNext());
        Assert.assertEquals(itG.next(), (Integer) 580);
        Assert.assertTrue(itG.hasNext());
        Assert.assertEquals(itG.next(), (Integer) 722);
        Assert.assertTrue(itG.hasNext());
        Assert.assertEquals(itG.next(), (Integer) 1024);
        Assert.assertTrue(itG.hasNext());
        Assert.assertEquals(itG.next(), (Integer)18);
        for (Integer i = 19; i <= 30; i++) {
            Assert.assertTrue(itG.hasNext());
            Assert.assertEquals(itG.next(), i);
        }
        Assert.assertFalse(itG.hasNext());
    }
}
