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.ZonedDateTime;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.EnumSet;
import org.xbib.files.ftp.parser.EnterpriseUnixFTPEntryParser;

/**
 * Tests the EnterpriseUnixFTPEntryParser
 */
public class EnterpriseUnixFTPEntryParserTest {

    private static final String[] BADSAMPLES =
            {
                    "zrwxr-xr-x   2 root     root         4096 Mar  2 15:13 zxbox",
                    "dxrwr-xr-x   2 root     root         4096 Aug 24  2001 zxjdbc",
                    "drwxr-xr-x   2 root     root         4096 Jam  4 00:03 zziplib",
                    "drwxr-xr-x   2 root     99           4096 Feb 23 30:01 zzplayer",
                    "drwxr-xr-x   2 root     root         4096 Aug 36  2001 zztpp",
                    "-rw-r--r--   1 14       staff       80284 Aug 22  zxJDBC-1.2.3.tar.gz",
                    "-rw-r--r--   1 14       staff      119:26 Aug 22  2000 zxJDBC-1.2.3.zip",
                    "-rw-r--r--   1 ftp      no group    83853 Jan 22  2001 zxJDBC-1.2.4.tar.gz",
                    "-rw-r--r--   1ftp       nogroup    126552 Jan 22  2001 zxJDBC-1.2.4.zip",
                    "-rw-r--r--   1 root     root       111325 Apr -7 18:79 zxJDBC-2.0.1b1.tar.gz",
                    "drwxr-xr-x   2 root     root         4096 Mar  2 15:13 zxbox",
                    "drwxr-xr-x 1 usernameftp 512 Jan 29 23:32 prog",
                    "drwxr-xr-x   2 root     root         4096 Aug 24  2001 zxjdbc",
                    "drwxr-xr-x   2 root     root         4096 Jan  4 00:03 zziplib",
                    "drwxr-xr-x   2 root     99           4096 Feb 23  2001 zzplayer",
                    "drwxr-xr-x   2 root     root         4096 Aug  6  2001 zztpp",
                    "-rw-r--r--   1 14       staff       80284 Aug 22  2000 zxJDBC-1.2.3.tar.gz",
                    "-rw-r--r--   1 14       staff      119926 Aug 22  2000 zxJDBC-1.2.3.zip",
                    "-rw-r--r--   1 ftp      nogroup     83853 Jan 22  2001 zxJDBC-1.2.4.tar.gz",
                    "-rw-r--r--   1 ftp      nogroup    126552 Jan 22  2001 zxJDBC-1.2.4.zip",
                    "-rw-r--r--   1 root     root       111325 Apr 27  2001 zxJDBC-2.0.1b1.tar.gz",
                    "-rw-r--r--   1 root     root       190144 Apr 27  2001 zxJDBC-2.0.1b1.zip",
                    "drwxr-xr-x   2 root     root         4096 Aug 26  20 zztpp",
                    "drwxr-xr-x   2 root     root         4096 Aug 26  201 zztpp",
                    "drwxr-xr-x   2 root     root         4096 Aug 26  201O zztpp", // OH not zero
            };
    private static final String[] GOODSAMPLES =
            {
                    "-C--E-----FTP B QUA1I1      18128       41 Aug 12 13:56 QUADTEST",
                    "-C--E-----FTP A QUA1I1      18128       41 Aug 12 13:56 QUADTEST2",
                    "-C--E-----FTP A QUA1I1      18128       41 Apr 1 2014 QUADTEST3"
            };

    @Test
    public void testBadListing() {
        EnterpriseUnixFTPEntryParser parser = new EnterpriseUnixFTPEntryParser();
        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() {
        EnterpriseUnixFTPEntryParser parser = new EnterpriseUnixFTPEntryParser();
        for (String test : GOODSAMPLES) {
            FTPFile f = parser.parseFTPEntry(test);
            assertNotNull(f, "Failed to parse " + test);
        }
    }

    @Test
    public void testRecentPrecision() {
        testPrecision("-C--E-----FTP B QUA1I1      18128       5000000000 Aug 12 13:56 QUADTEST",
                EnumSet.of(ChronoUnit.MINUTES, ChronoUnit.HOURS, ChronoUnit.DAYS, ChronoUnit.YEARS));
    }

    @Test
    public void testDefaultPrecision() {
        testPrecision("-C--E-----FTP B QUA1I1      18128       5000000000 Aug 12 2014 QUADTEST",
                EnumSet.of(ChronoUnit.DAYS));
    }

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

    @Test
    public void testParseFieldsOnFile() throws Exception {
        EnterpriseUnixFTPEntryParser parser = new EnterpriseUnixFTPEntryParser();
        FTPFile file = parser.parseFTPEntry("-C--E-----FTP B QUA1I1      18128       5000000000 Aug 12 13:56 QUADTEST");
        int year = ZonedDateTime.now().getYear();
        assertTrue(file.isFile());
        assertEquals("QUADTEST", file.getName());
        assertEquals(5000000000L, file.getSize());
        assertEquals("QUA1I1", file.getUser());
        assertEquals("18128", file.getGroup());
        if (ZonedDateTime.now().getMonth().getValue() < Month.AUGUST.getValue()) {
            --year;
        }
        ZonedDateTime timestamp = file.getTimestamp();
        assertEquals(year, timestamp.getYear());
        assertEquals(Month.AUGUST, timestamp.getMonth());
        assertEquals(12, timestamp.getDayOfMonth());
        assertEquals(13, timestamp.getHour());
        assertEquals(56, timestamp.getMinute());
        assertEquals(0, timestamp.getSecond());
        checkPermisions(file);
    }

    private void checkPermisions(FTPFile dir) {
        assertFalse(dir.hasPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION), "Owner should not have read permission.");
        assertFalse(dir.hasPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION), "Owner should not have write permission.");
        assertFalse(dir.hasPermission(FTPFile.USER_ACCESS, FTPFile.EXECUTE_PERMISSION), "Owner should not have execute permission.");
        assertFalse(dir.hasPermission(FTPFile.GROUP_ACCESS, FTPFile.READ_PERMISSION), "Group should not have read permission.");
        assertFalse(dir.hasPermission(FTPFile.GROUP_ACCESS, FTPFile.WRITE_PERMISSION), "Group should not have write permission.");
        assertFalse(dir.hasPermission(FTPFile.GROUP_ACCESS, FTPFile.EXECUTE_PERMISSION), "Group should not have execute permission.");
        assertFalse(dir.hasPermission(FTPFile.WORLD_ACCESS, FTPFile.READ_PERMISSION), "World should not have read permission.");
        assertFalse(dir.hasPermission(FTPFile.WORLD_ACCESS, FTPFile.WRITE_PERMISSION), "World should not have write permission.");
        assertFalse(dir.hasPermission(FTPFile.WORLD_ACCESS, FTPFile.EXECUTE_PERMISSION), "World should not have execute permission.");
    }
}
