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

import static org.junit.jupiter.api.Assertions.assertEquals;
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.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.xbib.files.ftp.parser.MVSFTPEntryParser;

public class MVSFTPEntryParserTest {

    private static final String[] goodsamplesDatasetList = {
            /* Note, if the string begins with SAVE, the parsed entry is stored in the List saveftpfiles */
            //  "Volume Unit    Referred Ext Used Recfm Lrecl BlkSz Dsorg Dsname",
            "SAVE00 3390   2004/06/23  1    1  FB     128  6144  PS    INCOMING.RPTBM023.D061704",
            "SAVE01 3390   2004/06/23  1    1  FB     128  6144  PO    INCOMING.RPTBM024.D061704",
            "SAVE02 3390   2004/06/23  1    1  FB     128  6144  PO-E  INCOMING.RPTBM025.D061704",
            "PSMLC1 3390   2005/04/04  1    1  VB   27994 27998  PS    file3.I",
            "PSMLB9 3390   2005/04/04  1    1  VB   27994 27998  PS    file4.I.BU",
            "PSMLB6 3390   2005/04/05  1    1  VB   27994 27998  PS    file3.I.BU",
            "PSMLC6 3390   2005/04/05  1    1  VB   27994 27998  PS    file6.I",
            "PSMLB7 3390   2005/04/04  1    1  VB   27994 27998  PS    file7.O",
            "PSMLC6 3390   2005/04/05  1    1  VB   27994 27998  PS    file7.O.BU",
            "FPFS49 3390   2004/06/23  1    1  FB     128  6144  PO-E  INCOMING.RPTBM026.D061704",
            "FPFS41 3390   2004/06/23  1    1  FB     128  6144  PS    INCOMING.RPTBM056.D061704",
            "FPFS25 3390   2004/06/23  1    1  FB     128  6144  PS    INCOMING.WTM204.D061704",
            "PEX26F 3390   2017/07/03  115807  FB   29600 29600  PS    INCOMING.FIN.D170630.T160630",
    };

    private static final String[] goodsamplesMemberList = {
            /* Note, if the string begins with SAVE, the parsed entry is stored in the List saveftpfiles */
            "Name      VV.MM   Created       Changed      Size  Init   Mod   Id",
            "SAVE03    01.03 2002/09/12 2002/10/11 09:37    11    11     0 KIL001",
            "SAVE04                                                              ", // no statistics
            "TBSHELF1  01.03 2002/09/12 2002/10/11 09:37    11    11     0 KIL001",
            "TBSHELF2  01.03 2002/09/12 2002/10/11 09:37    11    11     0 KIL001",
            "TBSHELF3  01.03 2002/09/12 2002/10/11 09:37    11    11     0 KIL001",
            "TBSHELF4  01.03 2002/09/12 2002/10/11 09:37    11    11     0 KIL001",};

    private static final String[] goodsamplesJES1List = { /* no header for JES1 (JES Interface level 1) */
            /* Note, if the string begins with SAVE, the parsed entry is stored in the List saveftpfiles */
            "IBMUSER1  JOB01906  OUTPUT    3 Spool Files",};

    private static final String[] goodsamplesJES2List = { /* JES2 (JES Interface level 2) */
            /* Note, if the string begins with SAVE, the parsed entry is stored in the List saveftpfiles */
            //"JOBNAME  JOBID    OWNER    STATUS CLASS",
            "IBMUSER2 JOB01906 IBMUSER  OUTPUT A        RC=0000 3 spool files",
            "IBMUSER  TSU01830 IBMUSER  OUTPUT TSU      ABEND=522 3 spool files",};

    private static final String[] goodsamplesUnixList = {
            "total 1234",
            "-rwxr-xr-x   2 root     root         4096 Mar  2 15:13 zxbox",
            "drwxr-xr-x   2 root     root         4096 Aug 24  2001 zxjdbc",
    };

    private static final String[] badsamples = {
            "MigratedP201.$FTXPBI1.$CF2ITB.$AAB0402.I",
            "PSMLC133902005/04/041VB2799427998PSfile1.I", "file2.O",};

    @Test
    public void testFirstGoodListing() {
        MVSFTPEntryParser parser = new MVSFTPEntryParser();
        parser.setType(MVSFTPEntryParser.FILE_LIST_TYPE);
        parser.setRegex(MVSFTPEntryParser.FILE_LIST_REGEX);
        for (String test : goodsamplesDatasetList) {
            FTPFile f = parser.parseFTPEntry(test);
            assertNotNull(f, "Failed to parse " + test);
            doAdditionalGoodTests(test, f);
        }
    }

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

    @Test
    public void testMemberListing() {
        MVSFTPEntryParser parser = new MVSFTPEntryParser();
        parser.setType(MVSFTPEntryParser.MEMBER_LIST_TYPE);
        parser.setRegex(MVSFTPEntryParser.MEMBER_LIST_REGEX);
        for (String test : goodsamplesMemberList) {
            FTPFile f = parser.parseFTPEntry(test);
            assertNotNull(f, "Failed to parse " + test);
            doAdditionalGoodTests(test, f);
        }
    }

    @Test
    public void testJesLevel1Listing() {
        MVSFTPEntryParser parser = new MVSFTPEntryParser();
        parser.setType(MVSFTPEntryParser.JES_LEVEL_1_LIST_TYPE);
        parser.setRegex(MVSFTPEntryParser.JES_LEVEL_1_LIST_REGEX);
        for (String test : goodsamplesJES1List) {
            FTPFile f = parser.parseFTPEntry(test);
            assertNotNull(f, "Failed to parse " + test);
            doAdditionalGoodTests(test, f);
        }
    }

    @Test
    public void testJesLevel2Listing() {
        MVSFTPEntryParser parser = new MVSFTPEntryParser();
        parser.setType(MVSFTPEntryParser.JES_LEVEL_2_LIST_TYPE);
        parser.setRegex(MVSFTPEntryParser.JES_LEVEL_2_LIST_REGEX);
        for (String test : goodsamplesJES2List) {
            FTPFile f = parser.parseFTPEntry(test);
            assertNotNull(f, "Failed to parse " + test);
            doAdditionalGoodTests(test, f);
        }
    }

    @Test
    public void testUnixListings() {
        MVSFTPEntryParser parser = new MVSFTPEntryParser();
        List<String> list = new ArrayList<String>();
        Collections.addAll(list, goodsamplesUnixList);
        parser.preParse(list);
        for (String test : list) {
            FTPFile f = parser.parseFTPEntry(test);
            assertNotNull(f, "Failed to parse " + test);
            assertNotNull(f.getName(), "Failed to parse name " + test);
            assertNotNull(f.getGroup(), "Failed to parse group " + test);
            assertNotNull(f.getUser(), "Failed to parse user " + test);
        }
    }

    @Test
    public void testParseFieldsOnDirectory() throws Exception {
        MVSFTPEntryParser parser = new MVSFTPEntryParser();
        parser.setType(MVSFTPEntryParser.FILE_LIST_TYPE);
        parser.setRegex(MVSFTPEntryParser.FILE_LIST_REGEX);
        FTPFile file = parser.parseFTPEntry("SAVE01 3390   2004/06/23  1    1  FB     128  6144  PO    INCOMING.RPTBM024.D061704");
        assertNotNull(file, "Could not parse entry.");
        assertTrue(file.isDirectory(), "Should have been a directory.");
        assertEquals("INCOMING.RPTBM024.D061704", file.getName());
        file = parser.parseFTPEntry("SAVE02 3390   2004/06/23  1    1  FB     128  6144  PO-E  INCOMING.RPTBM025.D061704");
        assertNotNull(file, "Could not parse entry.");
        assertTrue(file.isDirectory(), "Should have been a directory.");
        assertEquals("INCOMING.RPTBM025.D061704", file.getName());
    }

    @Test
    public void testParseFieldsOnFile() throws Exception {
        FTPFile file ;
        MVSFTPEntryParser parser = new MVSFTPEntryParser();
        parser.setRegex(MVSFTPEntryParser.FILE_LIST_REGEX);
        parser.setType(MVSFTPEntryParser.FILE_LIST_TYPE);
        file = parser.parseFTPEntry("SAVE00 3390   2004/06/23  1    1  FB     128  6144  PS    INCOMING.RPTBM023.D061704");
        assertNotNull(file, "Could not parse entry.");
        assertTrue(file.isFile(), "Should have been a file.");
        assertEquals("INCOMING.RPTBM023.D061704", file.getName());
        assertNull(file.getTimestamp(), "Timestamp should not have been set.");
        parser.setType(MVSFTPEntryParser.MEMBER_LIST_TYPE);
        parser.setRegex(MVSFTPEntryParser.MEMBER_LIST_REGEX);
        file = parser.parseFTPEntry("SAVE03    01.03 2002/09/12 2002/10/11 09:37    11    11     0 KIL001");
        assertNotNull(file, "Could not parse entry.");
        assertTrue(file.isFile(), "Should have been a file.");
        assertEquals("SAVE03", file.getName());
        assertNotNull(file.getTimestamp(), "Timestamp should have been set.");
        file = parser.parseFTPEntry("SAVE04                                                              ");
        assertNotNull(file, "Could not parse entry.");
        assertTrue(file.isFile(), "Should have been a file.");
        assertEquals("SAVE04", file.getName());
        assertNull(file.getTimestamp(), "Timestamp should not have been set.");
    }

    private void doAdditionalGoodTests(String test, FTPFile f) {
        assertNotNull(f.getRawListing(), "Could not parse raw listing in " + test);
        assertNotNull(f.getName(), "Could not parse name in " + test);
        // some tests don't produce any further details
    }
}
