import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.Bidi;
import java.util.ArrayList;
import java.util.List;

public class BidiCharacterTest {

    static int errorCount;

    public static void main( String[] args ) throws IOException {
        List<BidiTestCase> tests = readTests();
        for( BidiTestCase test : tests ) {
            run( test );
        }
        if( errorCount == 0 ) {
            System.out.println( "Bidi test finish without error." );
        } else {
            System.out.println( "Bidi test finish with " + errorCount + " error." );
        }
    }

    static void run( BidiTestCase test ) {
        Bidi bidi = new Bidi( test.testString, test.direction );
        for( int i = 0; i < test.levels.length; i++ ) {
            int expected = test.levels[i];
            if( expected < 0 ) {
                continue; // TODO Java seems not to handle this correctly
            }
            int level = bidi.getLevelAt( i );
            if( level != expected ) {
                System.err.println( "Wrong Bidi level in line: " + test.lineNumber + " at offset: " + i + ". Expected: " + expected + " actual: " + level );
                errorCount++;
                return;
            }
        }
    }

    static List<BidiTestCase> readTests() throws IOException {
        //InputStream input = BidiCharacterTest.class.getResourceAsStream( "BidiCharacterTest.txt" );
        InputStream input = new URL( "https://unicode.org/Public/UCD/latest/ucd/BidiCharacterTest.txt" ).openStream();
        BufferedReader reader = new BufferedReader( new InputStreamReader( input, StandardCharsets.UTF_8 ) );
        List<BidiTestCase> tests = new ArrayList<>();

        int lineNumber = 0;
        while( true ) {
            String line = reader.readLine();
            if( line == null ) {
                return tests;
            }
            lineNumber++;
            if( line.startsWith( "#" ) ) {
                continue;
            }
            line = line.trim();
            if( line.isEmpty() ) {
                continue;
            }
            tests.add( new BidiTestCase( line, lineNumber ) );
        }
    }

    static class BidiTestCase {
        final int lineNumber;

        final String testString;

        final int direction;

        final int[] levels;

        BidiTestCase( String line, int lineNumber ) {
            this.lineNumber = lineNumber;
            String[] lineParts = line.split( ";" );

            //test string
            String[] values = lineParts[0].split( " " );
            int[] codePoints = new int[values.length];
            for( int i = 0; i < values.length; ++i ) {
                codePoints[i] = Integer.valueOf( values[i], 16 );
            }
            testString = new String( codePoints, 0, codePoints.length );

            //paragraph direction
            switch( lineParts[1] ) {
                case "0":
                    direction = Bidi.DIRECTION_LEFT_TO_RIGHT;
                    break;
                case "1":
                    direction = Bidi.DIRECTION_RIGHT_TO_LEFT;
                    break;
                case "2":
                    direction = Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT;
                    break;
                default:
                    throw new RuntimeException( lineParts[1] );
            }

            //expected levels
            values = lineParts[3].split( " " );
            levels = new int[values.length];
            for( int i = 0; i < values.length; i++ ) {
                String level = values[i];
                levels[i] = "x".equals( level ) ? -1 : Integer.valueOf( level );
            }
        }
    }
}
