package csv4cj

import std.unittest.*
import std.unittest.testmacro.*
import std.collection.*

@Test
public class CSVParserTest {
    @TestCase
    public func testHeader(): Unit {
        let csvContent = ###"# Comment before header
author,title,publishDate
Dan Simmons,Hyperion,"1989""###
        let format = CSVParseFormat.DEFAULT.setFirstLineAsHeader(true)
        let csvReader = CSVReader(StringStream(csvContent))
        let csvParser = CSVParser(csvReader, format)
        let commentList = csvParser.getHeaderComment()
        @Assert(commentList.size,1)
        @Expect(commentList[0]," Comment before header")

        let headDict = csvParser.getHeaderDict()
        @Assert(headDict.size,3)
        @Assert(headDict.keys().containsAll(["author","title","publishDate"]))

        @Expect(headDict["author"],0)
        @Expect(headDict["title"],1)
        @Expect(headDict["publishDate"],2)
    }

    @TestCase
    public func testNextRecord(): Unit {
        let csvContent = 
            ###"Dan Simmons,Hyperion,"1989"
# Comment Line 1
# Comment Line 2
# Comment Line 3
Douglas Adams,The Hitchhiker's "Guide" to the Galaxy,1979
Douglas John,The Hitchhiker's "Guide" to the Mars,1979"###

        let format = CSVParseFormat.DEFAULT
        let csvReader = CSVReader(StringStream(csvContent))
        let csvParser = CSVParser(csvReader, format)

        //The first record
        var csvRecord = csvParser.nextRecord()        
        @Assert(csvRecord.isSome())
        var realRecord = csvRecord.getOrThrow()
        @Assert( realRecord.size(),3)
        @Expect(realRecord.getValues()[0],"Dan Simmons")
        @Expect(realRecord.getValues()[1],"Hyperion")
        @Expect(realRecord.getValues()[2],"1989")

        //The second record
        csvRecord = csvParser.nextRecord()
        @Assert(csvRecord.isSome())
        realRecord = csvRecord.getOrThrow()
        @Assert(realRecord.getComment().getOrThrow().contains("Comment Line 3"))
        @Assert(realRecord.size(),3)
        @Expect(realRecord.getValues()[1],"The Hitchhiker's \"Guide\" to the Galaxy")

        //The third record
        csvRecord = csvParser.nextRecord()
        @Assert(csvRecord.isSome())
        realRecord = csvRecord.getOrThrow()
        @Assert(realRecord.size(),3)
        @Expect(realRecord.getValues()[2],"1979")
    }

    @TestCase
    public func testParseRecordsToEnd(): Unit {
        let csvContent = 
            ###"Dan Simmons,Hyperion,"1989"            
# Comment Line 1
# Comment Line 2
# Comment Line 3
Douglas Adams,The Hitchhiker's "Guide" to the Galaxy,1979
Douglas John,The Hitchhiker's "Guide" to the Mars,1979"###

        let format = CSVParseFormat.DEFAULT
        let csvReader = CSVReader(StringStream(csvContent))
        let csvParser = CSVParser(csvReader, format)
        var csvRecordList = csvParser.parseRecordsToEnd()

        @Assert(csvRecordList.size,3)

        csvRecordList = csvParser.getRecords()
        @Assert(csvRecordList.size,3)

        @Expect(csvRecordList[0].getValues()[0],"Dan Simmons")
        @Expect(csvRecordList[0].getValues()[1],"Hyperion")
        @Expect(csvRecordList[0].getValues()[2],"1989")
    }

    @TestCase
    public func testEmptyLineRecord(): Unit {
        let csvContent = 
            ###"Dan Simmons,Hyperion,"1989"            

Douglas Adams,The Hitchhiker's "Guide" to the Galaxy,1979"###

        let format = CSVParseFormat.DEFAULT.setIgnoreEmptyLines(false)
        let csvReader = CSVReader(StringStream(csvContent))
        let csvParser = CSVParser(csvReader, format)
        var csvRecord = csvParser.nextRecord()
        csvRecord = csvParser.nextRecord()
        @Assert(csvRecord.isSome())
        var realRecord = csvRecord.getOrThrow()
        @Expect(realRecord.getRecordNumber(),2)
        @Assert( realRecord.size(),0)
    }

    @TestCase
    func testUseIgnoreEmptyLines02(): Unit {
        var content01 = "姓名,性别,籍贯,学校,年龄\n\n"
        var exp01 = ArrayList<Array<String>>(
            [
                Array<String>(["姓名", "性别", "籍贯", "学校", "年龄"]),
                Array<String>()
            ]
        )
        var cpf = CSVParseFormat.DEFAULT.setIgnoreEmptyLines(false)
        var ss01 = StringStream(content01)
        var csvreader01 = CSVReader(ss01)
        var csvparser01 = CSVParser(csvreader01, cpf)
        for (i in 0..2) {
            var act = csvparser01.nextRecord().getOrThrow().getValues()
            @Assert(act,exp01[i])
        }

        var expFlag = 1
        try {
            csvparser01.nextRecord().getOrThrow()
        } catch (e: NoneValueException) {
            expFlag = 0
        }
        @Assert(expFlag,0)
    }

    @TestCase
    public func testGetValueWithHeader(): Unit {
        let csvContent = 
            ###"# Comment before header
author,title,publishDate
Dan Simmons,Hyperion,"1989"
# Comment Line 1
Douglas Adams,The Hitchhiker's "Guide" to the Galaxy,1979
Douglas John,The Hitchhiker's "Guide" to the Mars,1979"###
        let format = CSVParseFormat.DEFAULT.setFirstLineAsHeader(true)
        let csvReader = CSVReader(StringStream(csvContent))
        let csvParser = CSVParser(csvReader, format)

        var csvRecord = csvParser.nextRecord()

        @Assert(csvRecord.isSome())

        var realRecord = csvRecord.getOrThrow()
        @Assert( realRecord.size(),3)

        @Expect(realRecord.get("author",csvParser.getHeaderDict()),"Dan Simmons")
        @Expect(realRecord.get("title",csvParser.getHeaderDict()),"Hyperion")
        @Expect(realRecord.get("publishDate",csvParser.getHeaderDict()),"1989")
    }

    @TestCase
    public func testTrimContent(): Unit {
        let csvContent = ###" Douglas Adams  ,The Hitchhiker's "Guide" to the Galaxy,    1979  "###
        var format = CSVParseFormat.DEFAULT.setIgnoreSurroundingSpaces(false)
        var csvReader = CSVReader(StringStream(csvContent))
        var csvParser = CSVParser(csvReader, format)

        var csvRecord = csvParser.nextRecord()

        @Assert(csvRecord.isSome())

        var realRecord = csvRecord.getOrThrow()
        @Assert( realRecord.size(),3)

        @Expect(realRecord.get(0)," Douglas Adams  ")
        @Expect(realRecord.get(2),"    1979  ")

        format = CSVParseFormat.DEFAULT.setIgnoreSurroundingSpaces(true)
        csvReader = CSVReader(StringStream(csvContent))
        csvParser = CSVParser(csvReader, format)

        realRecord = csvParser.nextRecord().getOrThrow()
        @Expect(realRecord.get(0),"Douglas Adams")
        @Expect(realRecord.get(2),"1979")
    }

    @TestCase
    public func testTrailingDelimiter(): Unit {
        let csvContent = 
            ###"姓名,  性   别,籍  贯,学校,  年 龄,
张三,男,陕 西 省,  北京     大学  ,25,
李四,女,江西省,三峡大学,24,"###
        var format = CSVParseFormat.DEFAULT
        var csvReader = CSVReader(StringStream(csvContent))
        var csvParser = CSVParser(csvReader, format)

        for (index in 1..=3) {
            var csvRecord = csvParser.nextRecord()
            @Assert(csvRecord.isSome())
            var realRecord = csvRecord.getOrThrow()
            @Assert( realRecord.size(),6)
            @Assert( realRecord.get(5),"")
        }

        format = CSVParseFormat.DEFAULT.setTrailingDelimiter(true)
        csvReader = CSVReader(StringStream(csvContent))
        csvParser = CSVParser(csvReader, format)

        for (index in 1..=3) {
            var realRecord = csvParser.nextRecord().getOrThrow()
            @Assert( realRecord.size(),5)
        }
    }
}