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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
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.Month;
import java.time.Year;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.EnumSet;
import org.xbib.files.ftp.parser.NetwareFTPEntryParser;

public class NetwareFTPEntryParserTest {

    private static final String[] badsamples = {
            "a [-----F--] SCION_SYS                         512 Apr 13 23:52 SYS",
            "d [----AF--]          0                        512 10-04-2001 _ADMIN"
    };

    private static final String[] goodsamples = {
            "d [-----F--] SCION_SYS                         512 Apr 13 23:52 SYS",
            "d [----AF--]          0                        512 Feb 22 17:32 _ADMIN",
            "d [-W---F--] SCION_VOL2                        512 Apr 13 23:12 VOL2",
            "- [RWCEAFMS] rwinston                        19968 Mar 12 15:20 Executive Summary.doc",
            "d [RWCEAFMS] rwinston                          512 Nov 24  2005 Favorites"
    };

    @Test
    public void testBadListing() {
        NetwareFTPEntryParser parser = new NetwareFTPEntryParser();
        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) {
        if (f == null) {
            return null;
        }
        if (f.getTimestamp() == null) {
            return null;
        }
        return f;
    }

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

    @Test
    public void testParseFieldsOnDirectory() throws Exception {
        NetwareFTPEntryParser parser = new NetwareFTPEntryParser();
        String reply = "d [-W---F--] testUser                        512 Apr 13 23:12 testFile";
        FTPFile f = parser.parseFTPEntry(reply);
        assertNotNull(f, "Could not parse file");
        assertEquals("testFile", f.getName());
        assertEquals(512L, f.getSize());
        assertEquals("testUser", f.getUser());
        assertTrue(f.isDirectory(), "Directory flag is not set!");
        ZonedDateTime zonedDateTime = ZonedDateTime.of(Year.now().getValue(),
                Month.APRIL.getValue(), 13, 23, 12, 0, 0, ZoneId.of("UTC"));
        if (zonedDateTime.isAfter(ZonedDateTime.now())) {
            zonedDateTime = zonedDateTime.minusYears(1);
        }
        assertEquals(zonedDateTime, f.getTimestamp());
    }

    @Test
    public void testParseFieldsOnFile() throws Exception {
        NetwareFTPEntryParser parser = new NetwareFTPEntryParser();
        String reply = "- [R-CEAFMS] rwinston                        19968 Mar 12 15:20 Document name with spaces.doc";
        FTPFile f = parser.parseFTPEntry(reply);
        assertNotNull(f, "Could not parse file");
        assertEquals("Document name with spaces.doc", f.getName());
        assertEquals(19968L, f.getSize());
        assertEquals("rwinston", f.getUser());
        assertTrue(f.isFile(), "File flag is not set!");
        assertTrue(f.hasPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION));
        assertFalse(f.hasPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION));
    }

    @Test
    public void testDefaultPrecision() {
        testPrecision("d [RWCEAFMS] rwinston                          512 Nov 24  2005 Favorites",
                EnumSet.of(ChronoUnit.DAYS));
    }

    @Test
    public void testRecentPrecision() {
        testPrecision("- [RWCEAFMS] rwinston                        19968 Mar 12 15:20 Executive Summary.doc",
                EnumSet.of(ChronoUnit.MINUTES, ChronoUnit.HOURS, ChronoUnit.DAYS));
    }

    private void testPrecision(String listEntry, EnumSet<ChronoUnit> units) {
        NetwareFTPEntryParser parser = new NetwareFTPEntryParser();
        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);
        }
    }
}


