package de.duehl.basics.regex;

/*
 * Copyright 2024 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

import static org.junit.Assert.*;

import java.util.regex.Pattern;

import org.junit.Test;

public class RangeToRegexTest {

    @Test (expected = IllegalArgumentException.class)
    public void fromTooLowInt() {
        int from = -1;
        int to = 3;
        new RangeToRegex(from, to);
    }

    @Test (expected = IllegalArgumentException.class)
    public void toTooLowInt() {
        int from = 0;
        int to = -1;
        new RangeToRegex(from, to);
    }

    @Test (expected = IllegalArgumentException.class)
    public void toLowerAsFromInt() {
        int from = 17;
        int to = 12;
        new RangeToRegex(from, to);
    }

    @Test (expected = IllegalArgumentException.class)
    public void fromTooLowString() {
        String from = "-1";
        String to = "3";
        new RangeToRegex(from, to);
    }

    @Test (expected = IllegalArgumentException.class)
    public void toTooLowString() {
        String from = "0";
        String to = "-1";
        new RangeToRegex(from, to);
    }

    @Test (expected = IllegalArgumentException.class)
    public void toLowerAsFromString() {
        String from = "17";
        String to = "12";
        new RangeToRegex(from, to);
    }

    @Test (expected = RuntimeException.class)
    public void canNotParseFromString() {
        String from = "12 und ein paar Zerquetschte";
        String to = "17";
        new RangeToRegex(from, to);
    }

    @Test (expected = RuntimeException.class)
    public void canNotParseToString() {
        String from = "12";
        String to = "17 und ein paar Zerquetschte";
        new RangeToRegex(from, to);
    }

    @Test
    public void compiles10to13() {
        int from = 10;
        int to = 13;
        RangeToRegex rangeToRegex = new RangeToRegex(from, to);
        String regex = rangeToRegex.createRegexFullMatch();
        Pattern.compile(regex);
    }

    @Test
    public void doesTheRightThing10to13() {
        int from = 10;
        int to = 13;
        createRegexCompileAndTestRange(from, to);
    }

    @Test
    public void doesTheRightThing0to99() {
        int from = 0;
        int to = 99;
        createRegexCompileAndTestRange(from, to);
    }

    @Test
    public void doesTheRightThing9to101() {
        int from = 9;
        int to = 101;
        createRegexCompileAndTestRange(from, to);
    }

    @Test
    public void doesTheRightThing9to201() {
        //System.out.println(Integer.MAX_VALUE);
        int from = 9;
        int to = 201;
        createRegexCompileAndTestRange(from, to);
    }

    @Test
    public void doesTheRightThing273to548() {
        int from = 273;
        int to = 548;
        createRegexCompileAndTestRange(from, to);
    }

    private void createRegexCompileAndTestRange(int from, int to) {
        RangeToRegex rangeToRegex = new RangeToRegex(from, to);
        String regex = rangeToRegex.createRegexFullMatch();
        //System.out.println(regex);
        Pattern pattern = Pattern.compile(regex);

        for (int number = 0; number < 10000; ++number) {
            boolean matches = pattern.matcher(Integer.toString(number)).matches();
            if (matches && number < from) {
                fail("Zahl unter from matcht! from = " + from + ", number = " + number);
            }
            if (matches && number > to) {
                fail("Zahl über to matcht! to = " + to + ", number = " + number);
            }
            if (!matches && from <= number && number <= to) {
                fail("Zahl im Bereich matcht nicht! from = " + from + ", to = " + to + ", number = "
                        + number);
            }
        }
    }

    @Test
    public void wholeLine() {
        int from = 9;
        int to = 12;
        RangeToRegex rangeToRegex = new RangeToRegex(from, to);
        String regex = rangeToRegex.createRegexFullMatch();
        //System.out.println(regex);
        Pattern pattern = Pattern.compile(regex);
        assertFalse(pattern.matcher("8910111213").find());
        assertFalse(pattern.matcher("8 9 10 11 12 13").find());
        assertTrue(pattern.matcher("9").find());
        assertTrue(pattern.matcher("10").find());
        assertTrue(pattern.matcher("12").find());
        assertFalse(pattern.matcher("13").find());
        assertFalse(pattern.matcher("foo 12 bar bar 13").find());
    }

    @Test
    public void wholeWord() {
        int from = 9;
        int to = 12;
        RangeToRegex rangeToRegex = new RangeToRegex(from, to);
        String regex = rangeToRegex.createRegexWholeWordMatch();
        //System.out.println(regex);
        Pattern pattern = Pattern.compile(regex);
        assertFalse(pattern.matcher("8910111213").find());
        assertTrue(pattern.matcher("8 9 10 11 12 13").find());
        assertTrue(pattern.matcher("9").find());
        assertTrue(pattern.matcher("10").find());
        assertTrue(pattern.matcher("12").find());
        assertFalse(pattern.matcher("13").find());
        assertTrue(pattern.matcher("foo 12 bar bar 13").find());
    }

    @Test
    public void anyPart() {
        int from = 9;
        int to = 12;
        RangeToRegex rangeToRegex = new RangeToRegex(from, to);
        String regex = rangeToRegex.createRegexPartMatch();
        //System.out.println(regex);
        Pattern pattern = Pattern.compile(regex);
        assertTrue(pattern.matcher("8910111213").find());
        assertTrue(pattern.matcher("8 9 10 11 12 13").find());
        assertTrue(pattern.matcher("9").find());
        assertTrue(pattern.matcher("10").find());
        assertTrue(pattern.matcher("12").find());
        assertFalse(pattern.matcher("13").find());
        assertTrue(pattern.matcher("foo 12 bar bar 13").find());
    }

    @Test
    public void anyPartWithoutQuestionMark() {
        int from = 9;
        int to = 12;
        RangeToRegex rangeToRegex = new RangeToRegex(from, to);
        rangeToRegex.useNormalBreaks();
        String regex = rangeToRegex.createRegexPartMatch();
        //System.out.println(regex);
        Pattern pattern = Pattern.compile(regex);
        assertTrue(pattern.matcher("8910111213").find());
        assertTrue(pattern.matcher("8 9 10 11 12 13").find());
        assertTrue(pattern.matcher("9").find());
        assertTrue(pattern.matcher("10").find());
        assertTrue(pattern.matcher("12").find());
        assertFalse(pattern.matcher("13").find());
        assertTrue(pattern.matcher("foo 12 bar bar 13").find());
    }

}
