package org.xbib.files.ftp.test.parser;

import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import org.xbib.files.ftp.FTPFile;
import java.time.ZonedDateTime;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.EnumSet;
import org.xbib.files.ftp.parser.MLSxEntryParser;

public class MLSxEntryParserTest {

    private static final String[] badsamples = {
            "Type=cdir;Modify=20141022065101;UNIX.mode=0775;/no/space", // no space between facts and name
            "Type=cdir;Modify=20141022065103;UNIX.mode=0775;", // no name or space
            "/no/leading/space",
            "", //empty
            "Type=cdir;Modify=20141022065102;UNIX.mode=0775; ", // no name
            "Type=dir;Size; missing =size",
            "Type=dir missing-semicolon",
            "Type= missing value and semicolon",
            " ", // no path
            //"Modify=2014; Short stamp",
            "Type=pdir;Modify=20141205180002Z; /trailing chars in Modify",
            "Type=dir;Modify=2014102206510x2.999;UNIX.mode=0775; modify has spurious chars",
    };

    private static final String[] goodsamples = {
            "Type=cdir;Modify=20141022065102;UNIX.mode=0775; /commons/net",
            "Type=pdir;Modify=20141205180002;UNIX.mode=0775; /commons",
            "Type=file;Size=431;Modify=20130303210732;UNIX.mode=0664; HEADER.html",
            "Type=file;Size=1880;Modify=20130611172748;UNIX.mode=0664; README.html",
            "Type=file;Size=2364;Modify=20130611170131;UNIX.mode=0664; RELEASE-NOTES.txt",
            "Type=dir;Modify=20141022065102;UNIX.mode=0775; binaries",
            // TODO(jprante) re-add this pattern
            //"Type=dir;Modify=20141022065102.999;UNIX.mode=0775; source",
            " /no/facts", // no facts
            "Type=; /empty/fact",
            "Size=; /empty/size",
            " Type=cdir;Modify=20141022065102;UNIX.mode=0775; /leading/space", // leading space before facts => it's a file name!
            "  ", // pathname of space
    };

    @Test
    public void testBadListing() {
        MLSxEntryParser parser = new MLSxEntryParser();
        for (String test : badsamples) {
            try {
                FTPFile f = parser.parseFTPEntry(test);
                assertNull(nullFileOrNullDate(f), "Should have Failed to parse <" + test + ">");
            } catch (DateTimeParseException e) {
                //
            }
        }
    }

    private FTPFile nullFileOrNullDate(FTPFile f) {
        return f;
    }

    @Test
    public void testGoodListing() {
        MLSxEntryParser parser = new MLSxEntryParser();
        for (String test : goodsamples) {
            FTPFile f = parser.parseFTPEntry(test);
            assertNotNull(f, "Failed to parse " + test);
        }
    }

    @Test
    public void testDefaultPrecision() {
        testPrecision("Type=dir;Modify=20141022065102;UNIX.mode=0775; source",
                EnumSet.of(ChronoUnit.SECONDS, ChronoUnit.MINUTES, ChronoUnit.HOURS, ChronoUnit.DAYS));
    }

    @Test
    public void testRecentPrecision() {
        testPrecision("Type=dir;Modify=20141022065102.999;UNIX.mode=0775; source",
                EnumSet.of(ChronoUnit.MILLIS));
    }

    private void testPrecision(String listEntry, EnumSet<ChronoUnit> units) {
        MLSxEntryParser parser = new MLSxEntryParser();
        FTPFile file = parser.parseFTPEntry(listEntry);
        assertNotNull(file, "Could not parse " + listEntry);
        ZonedDateTime zonedDateTime = file.getTimestamp();
        assertNotNull(zonedDateTime, "Failed to parse time in " + listEntry);
        for (ChronoUnit unit : units) {
            assertTrue(zonedDateTime.isSupported(unit), "Expected set " + unit + " in " + listEntry);
        }
    }
}
