
-- Prints a single value as lua global variable
local function print_value(name, value, file, comma)
    -- Special types
    if type(value) == 'string' then value = "\""..value.."\""
    elseif type(value) == 'boolean' then value = tostring(value) end
    -- Adds a comma before newline
    if comma then file:write(name .. " = " .. value .. ",\n")
    else file:write(name .. " = " .. value .. "\n") end
end

-- Prints a continuous table of values (iTable) in the format of a lua variable
local function print_iTable(name, table, file, comma)
    file:write(name .. " = { ")
    for i = 1, #table do
        if type(table[i]) == 'string' then temp = "\""..table[i].."\", "
        elseif type(table[i]) == 'boolean' then temp = tostring(table[i])..","
        else temp = table[i]..", " end
        file:write(temp)
    end
    if comma then file:write(" },\n")
    else file:write(" }\n\n") end
end

-- Prints a regular table (name and value) in the format of a lua variable
local function print_fTable(name, table, file, comma)
    file:write(name .. " = { ")
    for i, j in pairs(table) do
        if type(j) == 'string' then temp = "\"" .. j.. "\", "
        else temp = j .. ", " end
        file:write(i .. " = " .. temp)
    end
    if comma then file:write(" },\n")
    else file:write(" }\n\n") end
end



-- flux_matrix  => raw matrix, from species
-- Data consists of line (no the same length)
local function print_frame(header, data, fileName, isFloat)
    if isFloat == nil then
        isFloat = true
    end

    local file = assert(io.open(fileName, "a"))
    -- Header
    file:write("# ")
    for i  = 1, #header do
        file:write(header[i])
        file:write(" ")
    end
    file:write("\n")
    -- Frame body
    for i = 1, #data do
        for j = 1, #data[i] do
            if isFloat then
                file:write(string.format("%f ", data[i][j]))
            else
                file:write(string.format("%i ", data[i][j]))
            end
            file:write(" ")
        end
        file:write("\n")
    end
    file:write("\n")
    file:close()
end

-- Print of flux matrix data for a species
local function print_fluxMatrix(spe, fileName)
    local fm = spe.fluxMatrix
    --Iterate on sexes
    for propagule, tFrames in pairs(fm) do
        -- Iterate on frames
        for time, data in pairs(tFrames) do
            local header = {"flux_matrix", spe.id, propagule, time }
            print_frame(header, data, fileName)
        end
    end
end


-- User data in map format (Zopt, envEff, selInt)
local function print_map(frames, dataType, traitId, fileName)
    for time, data in pairs(frames) do
        local header = { dataType, traitId, time }
        print_frame(header, data, fileName)
    end
end


-- LocTypes
local function print_ltypes(ltypes, traitId, fileTrait, fileNameAE)
    fileTrait:write("ltypes = {\n")
    for _, ltype in ipairs(ltypes) do
        fileTrait:write("    {\n")
        print_value( "        id", ltype.id, fileTrait, true)
        print_iTable("        lociList", ltype.lociList, fileTrait, true)
        print_value( "        phi", ltype.phi, fileTrait, true)
        print_value( "        pow", ltype.pow, fileTrait, true)
        fileTrait:write(  "    },\n")

        -- Allelic effects
        local header = { "allelic_effects", traitId, ltype.id }
        print_frame(header, ltype.allelicEff, fileNameAE)
    end
    fileTrait:write("}\n")


end


-- Trait
local function print_trait(trait, dir)
    local fileName = dir .. "trait_" .. trait.id .. ".lua"
    local file = assert(io.open(fileName, "w"))

    -- Regular fields
    print_value("fileType", "trait", file)
    print_value("id", trait.id, file)
    print_value("species", trait.species, file)
    print_value("varLociWeights", trait.varLociWeights, file)
    if not trait.isGE then
        print_value("nhpp", trait.nhpp, file)
        print_value("h2", trait.h2, file)
    --print_value("initTotVa", trait.initTotVa, file)
    end

    -- Loc Types
    local fileNameAE =  dir .. "allEff.txt"
    print_ltypes(trait.ltypes, trait.id, file, fileNameAE)
    file:close()

    -- User data fields
    -- Selection Intensity : specific parameters of generation
    print_map(trait.selInt, "selection_intensity", trait.id, dir .. "sel_int.txt")
    -- E : specific parameters of generation
    print_map(trait.envEff, "e", trait.id, dir .. "e.txt")
    -- Zopt : specific parameters of generation
    print_map(trait.zopt, "zopt", trait.id, dir .. "zopt.txt")

end

local function refresh_matrix_trait(trait, dir)
    -- User data fields
    -- Selection Intensity : specific parameters of generation
    print_map(trait.selInt, "selection_intensity", trait.id, dir .. "sel_int.txt")
    -- E : specific parameters of generation
    print_map(trait.envEff, "e", trait.id, dir .. "e.txt")
    -- Zopt : specific parameters of generation
    print_map(trait.zopt, "zopt", trait.id, dir .. "zopt.txt")
end


-- Species
local function print_species(spe, dir)
    local fileName = dir .. "spe_" .. spe.id .. ".lua"
    local file = assert(io.open(fileName, "w"))

    -- Print fields
    print_value("fileType", "species", file)
    print_value("id", spe.id, file)
    print_iTable("traitsId", spe.traitsId, file)
    print_iTable("ageClasses", spe.ageClasses, file)
    print_value("nLocus", spe.nLocus, file)
    print_value("genomeSize", spe.genomeSize, file)
    print_value("assortMating", spe.assortMating, file)
    --print_value("maxAge", spe.maxAge, file)
    print_value("selfingRate", spe.selfingRate, file)
    print_fTable("fluxSource", spe.fluxSource, file)
    --print_value("ms", spe.ms, file)  -- TODO
    --print_value("mp", spe.mp, file) -- TODO
    print_value("Nm", spe.Nm, file)
    --print_value("cap", spe.cap, file) -- TODO
    --print_value("growth", spe.growth, file) -- TODO
    --print_value("initDemo", spe.initDemo.npop, file)
    print_iTable("nAllpLoci", spe.nAllpLoci, file)
    print_iTable("ploidy", spe.ploidy, file)
    print_iTable("nAllInit", spe.nAllInit, file)
    print_iTable("crossingRate", spe.crossingRate, file)
    print_iTable("mutationRate", spe.mutationRate, file)

    file:write("inheritance = { \n          ")
    print_iTable("female", spe.inheritance.female, file, true)
    file:write("          ")
    print_iTable("male", spe.inheritance.male, file, true)
    file:write("}\n")
    file:close()

    -- Print User Data
    print_fluxMatrix(spe, dir.."fluxMat.txt")

    -- Print traits
    for traitId, trait in pairs(spe.traits) do
        print_trait(trait, dir)
    end
end


local function refresh_matrix(spe, dir)
    -- Print User Data
    print_fluxMatrix(spe, dir.."fluxMat.txt")

    local header = {"demography", spe.id }
    if spe.initDemo.source ~= "injection" then
      print_frame(header, spe.generatedDemo, dir .. "demo.txt", false)
    end
    -- Print traits
    for traitId, trait in pairs(spe.traits) do
        refresh_matrix_trait(trait, dir)
    end
end


-- individuals  => raw matrix
local function print_individuals(allInds, fileName)
    -- Open file
    local file = assert(io.open(fileName, "a"))
    -- Iterate on species
    for speId, allPops in pairs(allInds) do
        -- Print header
        file:write("# individuals " .. speId .."\n")
        -- Iterate on pops
        for popId = 1, #allPops do
            local pop = allPops[popId]
            -- Iterate on individuals
            for indId = 1, #pop do
                local ind = pop[indId]
                --print("output:", indId)
                file:write(popId .. " " .. ind.age .. " ")
                for i = 1, #ind.genome do file:write(ind.genome[i] .. " ") end
                file:write("\n")
            end
        end
    end
    file:close()
end
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

local module = {}
module.print_species = print_species
module.refresh_matrix = refresh_matrix
module.print_individuals = print_individuals
return module
