import au.com.bytecode.opencsv.CSVWriter
import au.com.bytecode.opencsv.CSVReader

/**
 * Provides some csv import/export methods.
 * Requires the opencsv jar to be available which is included in the grails-export plugin.
 */
class CsvService {

    boolean transactional = false

    /**
    * Import an asset tree creating items as required.
    * @param request The http request to run getFile against.
    * Get file should return a csv format file containing the asset tree as per template.
    */
    def importAssetTree(request) {
        def result = [:]

        def megaByteMultiplier = 1000 * 1000
        def fileMaxSize = 10 * megaByteMultiplier //Mb

        def multiPartFile = request.getFile('file')

        InputStreamReader sr = new InputStreamReader(multiPartFile.inputStream)
        CSVReader reader = new CSVReader(sr)

        def fail = { Map m ->
            //status.setRollbackOnly()
            reader.close()
            result.error = [ code: m.code, args: m.args ]
            return result
        }

        if(!multiPartFile || multiPartFile.isEmpty())
            return fail(code: "asset.tree.import.file.not.supplied")

        if (multiPartFile.getSize() > fileMaxSize)
            return fail(code: "asset.tree.import.file.over.max.size", args: [fileMaxSize/megaByteMultiplier])

        def line = reader.readNext()
        def lineNumber = 1

        def header = ["Site", "Section", "Asset", "Sub Asset", "Functional Assembly", "Sub Assembly Group"]

        if(line != header)
            return fail(code: "asset.tree.import.no.header")

        log.info "Import checks passed, start processing asset file."

        // Prepare the first body line.
        line = reader.readNext()
        lineNumber ++

        while(line) {
            def lineSize = line.size()
//             log.info lineNumber+ "(" + lineSize + ")" + " : " + line

            if(line[0]) {
                    if( !Site.findByName(line[0]) )
                        new Site(name: line[0]).save()
            }

            line = reader.readNext()
            lineNumber ++
        } //while(line)

        // Success.
        reader.close()
        return result

    } // end importAssetTree()

    /**
    * Build an asset tree template csv file.
    * This template can then be populated for import.
    * @returns The template as a String in csv format.
    */
    def buildAssetTreeTemplate() {

        StringWriter sw = new StringWriter()
        CSVWriter writer = new CSVWriter(sw)

        //Header
        def header = ["Site", "Section", "Asset", "Sub Asset", "Functional Assembly", "Sub Assembly Group"]
        def blankLine = []
        def noteLine = ["Note: the header is required, start by replacing this line."]

        writer.writeNext(header as String[])
        writer.writeNext(blankLine as String[])
        writer.writeNext(noteLine as String[])

        writer.close()
        return sw.toString()
    }

    /**
    * Build complete asset trees for export.
    * @param assetList The list of assets to build and export trees for.
    * @returns The tree as a String in csv format.
    */
    def buildAssetTree(List assetList) {

        StringWriter sw = new StringWriter()
        CSVWriter writer = new CSVWriter(sw)

        //Header
        def header = ["Site", "Section", "Asset", "Sub Asset", "Functional Assembly", "Sub Assembly Group"]
        writer.writeNext(header as String[])

        //Rows
        def row

        def writeAssetSubItem4 = { assetSubItem ->
            row.add(assetSubItem)
            writer.writeNext(row as String[])
        }

        def writeAssetSubItem3 = { assetSubItem ->
            row.add(assetSubItem)

            if(assetSubItem.subItems.size() > 0) {
                assetSubItem.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { assetSubItem4 ->
                    writeAssetSubItem4(assetSubItem4)
                    row.remove(row.last())
                }
            }
            else {
                writer.writeNext(row as String[])
            }

        }

        def writeAssetSubItem2 = { assetSubItem ->
            row.add(assetSubItem)

            if(assetSubItem.subItems.size() > 0) {
                assetSubItem.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { assetSubItem3 ->
                    writeAssetSubItem3(assetSubItem3)
                    row.remove(row.last())
                }
            }
            else {
                writer.writeNext(row as String[])
            }

        }

        def writeAssetSubItem1 = { assetSubItem ->
            row.add(assetSubItem)

            if(assetSubItem.subItems.size() > 0) {
                assetSubItem.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { assetSubItem2 ->
                    writeAssetSubItem2(assetSubItem2)
                    row.remove(row.last())
                }
            }
            else {
                writer.writeNext(row as String[])
            }

        }

        assetList.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { asset ->
            row = []
            writer.writeNext(row as String[]) //blank row between assets.
            row.add(asset.section.site)
            row.add(asset.section)
            row.add(asset.name)

            if(asset.assetSubItems.size() > 0) {
                asset.assetSubItems.each() { assetSubItem1 ->
                    writeAssetSubItem1(assetSubItem1)
                    row.remove(row.last())
                }
            }
            else {
                writer.writeNext(row as String[])
            }

        }

        writer.close()
        return sw.toString()
    } // end buildAssetTree

} // end class