package com.capgemini.reports.definition.r26report;

import org.testng.annotations.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

public class RangesTest {


  @Test
  public void oneRangeShouldReturnTheRange() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("A", 1, 10));
    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("A")).isEqualTo("1-10");
  }

  @Test
  public void oneRangeWithSameBornInfBorneSupShouldReturnTheRange() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("A", 10, 10));
    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("A")).isEqualTo("10");
  }

  @Test
  public void twoExcludedRangeShouldReturnTwoRange() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("A", 1, 10));
    rangesList.add(new Range("A", 20, 30));

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("A")).isEqualTo("1-10;20-30");
  }

  @Test
  public void twoExcludedRangeShouldReturnTwoRange2() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("A", 1, 10));
    rangesList.add(new Range("A", 20, 30));
    rangesList.add(new Range("B", 40, 60));

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("A")).isEqualTo("1-10;20-30");
    assertThat(ranges.toString("B")).isEqualTo("40-60");
  }

  @Test
  public void twoExcludedRangeShouldReturnTwoRange3() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("A", 1, 10));
    rangesList.add(new Range("A", 20, 30));
    rangesList.add(new Range("B", 40, 50));
    rangesList.add(new Range("B", 60, 80));

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("A")).isEqualTo("1-10;20-30");
    assertThat(ranges.toString("B")).isEqualTo("40-50;60-80");
  }

  @Test
  public void twoPartiallyIncludedRangeShouldReturnTwoRange() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("A", 1, 20));
    rangesList.add(new Range("A", 10, 30));

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("A")).isEqualTo("1-30");
  }

  @Test
  public void secondeRangeRangeShouldBeFirstRange() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("A", 1, 100));
    rangesList.add(new Range("A", 200, 400));

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("A")).isEqualTo("1-100;200-400");
  }

  @Test
  public void twoTotallyIncludedRangeWithSameBorneIfBorneSupShouldReturnThreeRange() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("A", 1, 20));
    rangesList.add(new Range("B", 10, 10));

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("A")).isEqualTo("1-9;11-20");
    assertThat(ranges.toString("B")).isEqualTo("10");
  }

  @Test
  public void twoTotallyIncludedRangeShouldReturnThreeRange() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("A", 1, 20));
    rangesList.add(new Range("B", 10, 15));

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("A")).isEqualTo("1-9;16-20");
    assertThat(ranges.toString("B")).isEqualTo("10-15");
  }

  @Test
  public void twoTotallyIncludedWithUpRangeShouldReturnTwoRange() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("A", 1, 2147483646));
    rangesList.add(new Range("B", 10, 2147483646));

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("A")).isEqualTo("1-9");
    assertThat(ranges.toString("B")).isEqualTo("10-UP");
  }

  @Test
  public void multipleRangeShouldReturnEightRange() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("A", 1, 2147483646)); // 1-UP
    rangesList.add(new Range("B", 1, 2147483646)); // 1-UP
    rangesList.add(new Range("C", 100, 150)); // 1-99;100-150;151-UP
    rangesList.add(new Range("B", 150, 2147483646)); // 1-149;150-UP
    rangesList.add(new Range("C", 250, 250)); // 1-99;100-150;151-249;250;251-299;300-UP
    rangesList.add(new Range("C", 300, 2147483646)); // 1-99;100-150;151-299;300-UP
    rangesList.add(new Range("D", 500, 500)); // 1-99;100-150;151-249;250;251-299;300-499;500;501-UP

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("A")).isEmpty();
    assertThat(ranges.toString("B")).isEqualTo("1-99;150-249;251-299");
    assertThat(ranges.toString("C")).isEqualTo("100-149;250;300-499;501-UP");
    assertThat(ranges.toString("D")).isEqualTo("500");
  }

  @Test
  public void multipleRangeShouldReturnSevenRange() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("A", 1, 2147483646)); // 1-UP
    rangesList.add(new Range("B", 1, 2147483646)); // 1-UP
    rangesList.add(new Range("C", 100, 160)); // 1-99;100-149;150-160;161-UP
    rangesList.add(new Range("B", 150, 2147483646)); // 1-149;150-UP
    rangesList.add(new Range("C", 150, 2147483646)); // 1-99;100-149;150-UP
    rangesList.add(new Range("C", 250, 250)); // 1-99;100-149;150-249;250;251-UP
    rangesList.add(new Range("D", 500, 500)); // 1-99;100-149;150-249;250;251-499;500;501-UP

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("A")).isEmpty();
    assertThat(ranges.toString("B")).isEqualTo("1-99;150");
    assertThat(ranges.toString("C")).isEqualTo("100-149;151-499;501-UP");
    assertThat(ranges.toString("D")).isEqualTo("500");
  }

  @Test
  public void twoTotallyIncludedWithUpRangeShouldReturnThreeRange() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("B", 20, 300)); // 20-49;50-199;301-399;400-UP
    rangesList.add(new Range("A", 50, 2147483646)); // 50-UP
    rangesList.add(new Range("B", 200, 2147483646)); // 50-199;200-UP
    rangesList.add(new Range("B", 400, 2147483646)); // 50-199;200-399;400-UP

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("A")).isEqualTo("50-199");
    assertThat(ranges.toString("B")).isEqualTo("20-49;200-UP");
  }

  @Test
  public void twoTotallyIncludedWithUpRangeShouldReturnThreeRange2() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("C", 600, 600)); // 600
    rangesList.add(new Range("G", 650, 800)); // 600;650-800
    rangesList.add(new Range("G", 700, 700)); // 600;700
    rangesList.add(new Range("I", 900, 900)); // 600;650-800;900;1000-UP
    rangesList.add(new Range("G", 1000, 2147483646)); // 600;650-800;1000-UP

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("C")).isEqualTo("600");
    assertThat(ranges.toString("G")).isEqualTo("650-800;1000-UP");
    assertThat(ranges.toString("I")).isEqualTo("900");
  }

  @Test
  public void twoTotallyIncludedWithUpRangeShouldReturnThreeRange3() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("C", 600, 600)); // 600
    rangesList.add(new Range("G", 700, 700)); // 600;700
    rangesList.add(new Range("I", 900, 900)); // 600;700;900;1000-UP
    rangesList.add(new Range("G", 1000, 2147483646)); // 600;700;1000-UP

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("C")).isEqualTo("600");
    assertThat(ranges.toString("G")).isEqualTo("700;1000-UP");
    assertThat(ranges.toString("I")).isEqualTo("900");
  }

  @Test
  public void twoTotallyIncludedWithUpRangeShouldReturnThreeRange4() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("C", 600, 600)); // 600
    rangesList.add(new Range("G", 650, 850)); // 600;650-850
    rangesList.add(new Range("G", 700, 700)); // 600;700
    rangesList.add(new Range("G", 800, 800)); // 600;700;800
    rangesList.add(new Range("I", 900, 900)); // 600;650-850;900;1000-UP
    rangesList.add(new Range("G", 1000, 2147483646)); // 600;650-850;1000-UP

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("C")).isEqualTo("600");
    assertThat(ranges.toString("G")).isEqualTo("650-850;1000-UP");
    assertThat(ranges.toString("I")).isEqualTo("900");
  }

  @Test
  public void twoTotallyIncludedWithUpRangeShouldReturnThreeRange5() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("G", 1, 2147483646)); // 1-UP
    rangesList.add(new Range("G", 300, 300)); // 300;700
    rangesList.add(new Range("G", 700, 700)); // 700

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("G")).isEqualTo("1-UP");
  }

  @Test
  public void twoTotallyIncludedWithUpRangeShouldReturnThreeRange6() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("A", 600, 600)); // 600
    rangesList.add(new Range("B", 700, 700)); // 600;700
    rangesList.add(new Range("E", 800, 2147483646)); // 600;700;800-899;900;901-999;1000-1099;1100;1101-UP
    rangesList.add(new Range("C", 900, 900)); // 600;700;900;1000-UP
    rangesList.add(new Range("B", 1000, 2147483646)); // 600;700;1000-UP
    rangesList.add(new Range("D", 1100, 1100)); // 600;700;900;1000-1099;1100;1101-UP

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("A")).isEqualTo("600");
    assertThat(ranges.toString("B")).isEqualTo("700;1000-1099;1101-UP");
    assertThat(ranges.toString("C")).isEqualTo("900");
    assertThat(ranges.toString("D")).isEqualTo("1100");
    assertThat(ranges.toString("E")).isEqualTo("800-899;901-999");
  }

  @Test
  public void twoTotallyIncludedWithUpRangeShouldReturnThreeRange7() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("F", 1, 2147483646)); // 600;700;800-UP
    rangesList.add(new Range("A", 600, 600)); // 600
    rangesList.add(new Range("G", 600, 600)); // 600;700;800-UP
    rangesList.add(new Range("B", 700, 700)); // 600;700
    rangesList.add(new Range("E", 800, 2147483646)); // 600;700;800-UP
    rangesList.add(new Range("C", 900, 900)); // 600;700;900;1000-UP
    rangesList.add(new Range("B", 1000, 2147483646)); // 600;700;1000-UP
    rangesList.add(new Range("D", 1100, 1100)); // 600;700;900;1000-1099;1100;1101-UP

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("A")).isEmpty();
    assertThat(ranges.toString("B")).isEqualTo("700;1000-1099;1101-UP");
    assertThat(ranges.toString("C")).isEqualTo("900");
    assertThat(ranges.toString("D")).isEqualTo("1100");
    assertThat(ranges.toString("E")).isEqualTo("800-899;901-999");
    assertThat(ranges.toString("F")).isEqualTo("1-599;601-699;701-799");
    assertThat(ranges.toString("G")).isEqualTo("600");
  }

  @Test
  public void twoTotallyIncludedWithUpRangeShouldReturnThreeRange8() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("B", 5, 2147483646)); // 5-9;10-UP
    rangesList.add(new Range("A", 10, 2147483646)); // 10-UP
    rangesList.add(new Range("C", 20, 2147483646)); // 5-9;10-19;20-UP
    rangesList.add(new Range("D", 30, 2147483646)); // 5-9;10-19;20-29;30-UP

    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("A")).isEqualTo("10-19");
    assertThat(ranges.toString("B")).isEqualTo("5-9");
    assertThat(ranges.toString("C")).isEqualTo("20-29");
    assertThat(ranges.toString("D")).isEqualTo("30-UP");
  }

  @Test
  public void twoTotallyIncludedWithUpRangeShouldReturnThreeRange9() {
    List<Range> rangesList = new ArrayList<>();
    rangesList.add(new Range("A", 600, 600)); // 1-599;600;601-UP
    rangesList.add(new Range("B", 700, 700)); // 1-599;600;601-699;700;701-UP
    rangesList.add(new Range("B", 1000, 2147483646));// 1-599;600;601-699;700;701-799;800-849;850-899;900;901-999;1000-UP
    rangesList.add(new Range("C", 900, 900)); // 1-599;600;601-699;700;701-799;800-849;850-899;900;901-UP
    rangesList.add(new Range("D", 1100, 1100));// 1-599;600;601-699;700;701-799;800-849;850-899;900;901-999;1000-1099;1100;1101-UP
    rangesList.add(new Range("E", 800, 2147483646)); // 1-599;600;601-699;700;701-799;800-UP
    rangesList.add(new Range("F", 1, 2147483646)); // 1-UP
    rangesList.add(new Range("G", 600, 600)); // 1-599;600;601-UP
    rangesList.add(new Range("H", 850, 900)); // 1-599;600;601-699;700;701-799;800-849;850-900;901-UP
    Collections.sort(rangesList, new Comparator<Range>() {
      public int compare(Range r1, Range r2) {
        return Integer.compare(r1.borneInf(), r2.borneInf());
      }
    });
    Ranges ranges = new Ranges(rangesList);
    assertThat(ranges.toString("A")).isEmpty();
    assertThat(ranges.toString("B")).isEqualTo("700;1000-1099;1101-UP");
    assertThat(ranges.toString("C")).isEqualTo("900");
    assertThat(ranges.toString("D")).isEqualTo("1100");
    assertThat(ranges.toString("E")).isEqualTo("800-849;901-999");
    assertThat(ranges.toString("F")).isEqualTo("1-599;601-699;701-799");
    assertThat(ranges.toString("G")).isEqualTo("600");
    assertThat(ranges.toString("H")).isEqualTo("850-899");
  }
}