-- This file is generated by the neblua bundler
-- https://github.com/Tsukina-7mochi/neblua

local alreadyInstalled = _ENV.__NEBLUA_INSTALLED
_ENV.__NEBLUA_INSTALLED = true

package.bundleLoader = {}

package.bundleLoader["./entry/lcdFilter.lua"] = {
    line = debug.getinfo(1).currentline,
    loader = function(...)

package.manifest = {
    name = "aseprite-scripts/lcd-pixel-filter",
    description = "Applies filter like LCD.",
    version = "v0.1.1",
    author = "Mooncake Sugar",
    license = "MIT",
    homepage = "https://github.com/Tsukina-7mochi/aseprite-scripts/blob/master/lcd-pixel-filter/"
}

if not app then return end

-- function alias
local pc = app.pixelColor

-- duplicate sprite
if not app.activeSprite then
    return app.alert("No active sprite.")
end

-- config
local colorTable = {
    R = "G",
    G = "B",
    B = "K",
    K = "R"
}
local buttons = { "R", "G", "B", "R", "G", "B", "R", "G", "B" }

local dialog = Dialog("LCD Pixel Filter")

for i = 1, #buttons do
    dialog:button {
        id = "button" .. i,
        text = buttons[i],
        onclick = function()
            buttons[i] = colorTable[buttons[i]]
            dialog:modify {
                id = "button" .. i,
                text = buttons[i]
            }
        end
    }

    if i % 3 == 0 then
        dialog:newrow()
    end
end

dialog:button {
    id = "ok",
    text = "&OK",
    focus = true
}:button {
    id = "cancel",
    text = "&Cancel"
}

dialog:show()


if not dialog.data.ok then return end


local sprite = Sprite(app.activeSprite)
sprite:flatten()

local cel     = sprite.cels[1]
local image   = cel.image
local sBounds = sprite.bounds
local iBounds = cel.bounds

if not cel then
    return app.alert("No valid cel.")
end
if not image then
    return app.alert("No valid image.")
end

-- create image data array
imgData = {}

for i = 1, #sprite.cels do
    cel = sprite.cels[i]
    image = cel.image

    if not image then
        imgData[i] = nil
    else
        -- scan image
        local data = {}
        for y = 0, iBounds.height - 1 do
            local arr = {}
            for x = 0, iBounds.width - 1 do
                local pVal = image:getPixel(x, y)
                arr[#arr + 1] = pVal
            end
            data[#data + 1] = arr
        end

        imgData[i] = data
    end
end

-- scale
sprite:resize(iBounds.width * 3, iBounds.height * 3)


-- draw
for i = 1, #sprite.cels do
    cel = sprite.cels[i]
    image = cel.image

    for y = 0, iBounds.height - 1 do
        for x = 0, iBounds.width - 1 do
            local colors = {
                R = pc.rgba(pc.rgbaR(imgData[i][y + 1][x + 1]), 0, 0),
                G = pc.rgba(0, pc.rgbaG(imgData[i][y + 1][x + 1]), 0),
                B = pc.rgba(0, 0, pc.rgbaB(imgData[i][y + 1][x + 1])),
                K = pc.rgba(0, 0, 0)
            }
            image:drawPixel(x * 3 + 0, y * 3 + 0, colors[buttons[1]])
            image:drawPixel(x * 3 + 1, y * 3 + 0, colors[buttons[2]])
            image:drawPixel(x * 3 + 2, y * 3 + 0, colors[buttons[3]])
            image:drawPixel(x * 3 + 0, y * 3 + 1, colors[buttons[4]])
            image:drawPixel(x * 3 + 1, y * 3 + 1, colors[buttons[5]])
            image:drawPixel(x * 3 + 2, y * 3 + 1, colors[buttons[6]])
            image:drawPixel(x * 3 + 0, y * 3 + 2, colors[buttons[7]])
            image:drawPixel(x * 3 + 1, y * 3 + 2, colors[buttons[8]])
            image:drawPixel(x * 3 + 2, y * 3 + 2, colors[buttons[9]])
        end
    end
end


    end
    }


-- sentinel value for error message replacement
package.bundleLoader[debug.getinfo(1).short_src] = {
    line = 0,
    loader = nil,
}

---Splits a string by a search string
---@param str string
---@param searchStr string
---@return string[]
local function split(str, searchStr)
    if #str == 0 then
        return { str }
    end

    local result = {}
    local pos = 1

    while true do
        local startPos, endPos = str:find(searchStr, pos)

        if startPos == nil then
            break
        end

        table.insert(result, str:sub(pos, startPos - 1))
        pos = endPos + 1
    end

    if pos <= #str then
        table.insert(result, str:sub(pos))
    else
        table.insert(result, "")
    end

    return result
end

local config = split(package.config, "\n")
local pathSeparator = config[1]
local templateSeparator = config[2]
local substitutionPoint = config[3]
local internalPathSeparator = "/"

--- Resolves a given path using the specified path separator
---@param path string The path to resolve
---@return string
local function resolvePath(path)
    local segments = split(path, internalPathSeparator)
    local resultSegments = {}

    if segments[1] == "." then
        table.insert(resultSegments, ".")
    end
    if segments[1] == "" then
        table.insert(resultSegments, "")
    end
    if segments[1] == ".." then
        error("Cannot go above root directory")
    end

    for _, seg in ipairs(segments) do
        if seg == "." or seg == "" then
            -- Do nothing
        elseif seg == ".." then
            table.remove(resultSegments)
        else
            table.insert(resultSegments, seg)
        end
    end

    if segments[#segments] == "" then
        table.insert(resultSegments, "")
    end

    return table.concat(resultSegments, internalPathSeparator)
end

--- Searches for a module in the `package.bundleLoader`
---@param moduleName string
---@return function
---@return string
---@overload fun(moduleName: string): nil
local function bundlerSearcher(moduleName)
    moduleName = moduleName:gsub("%.", internalPathSeparator)

    local templates = split(package.path, templateSeparator)
    for _, template in ipairs(templates) do
        local path = template:gsub(pathSeparator, internalPathSeparator):gsub(substitutionPoint, moduleName)
        local resolvedPath = resolvePath(path)
        local loader = package.bundleLoader[resolvedPath]
        if loader ~= nil and loader.loader ~= nil then
            return loader.loader, path
        end
    end

    return nil
end

if not alreadyInstalled then
    --- Register the bundler searcher at the highest priority
    table.insert(package.searchers, 1, bundlerSearcher)

    -- Replace dofile
    local originalDoFile = dofile
    ---@diagnostic disable-next-line: duplicate-set-field
    _ENV.dofile = function(path)
        local loader = package.bundleLoader[path]
        if loader ~= nil and loader.loader ~= nil then
            return loader.loader()
        else
            return originalDoFile(path)
        end
    end

    -- Replace loadfile
    local originalLoadFile = loadfile
    ---@diagnostic disable-next-line: duplicate-set-field
    _ENV.loadfile = function(path, ...)
        local loader = package.bundleLoader[path]
        if loader ~= nil and loader.loader ~= nil then
            return loader.loader
        else
            return originalLoadFile(path, ...)
        end
    end
end

local loaderLineOffset = -2
---Error handler for xpcall
---@param err any
---@return any
local errorHandler = function(err)
    local srcName = debug.getinfo(1).short_src:gsub("[^%w]", "%%%0")
    local pattern = srcName .. ":(%d+):"

    local message = debug.traceback(err, 2):gsub(pattern, function(line)
        local lineNumber = tonumber(line)

        local loaderLine = -1
        local loaderName = nil
        for name, loader in pairs(package.bundleLoader) do
            if loader.line ~= nil and loaderLine < loader.line and loader.line < lineNumber then
                loaderLine = loader.line
                loaderName = name
            end
        end

        return loaderName .. ":" .. (lineNumber - loaderLine + loaderLineOffset) .. ":"
    end)

    return message
end

local fallbackStderr = true

local loader = bundlerSearcher("entry.lcdFilter")
if loader == nil then
    error("Cannot find entry point: " .. "entry.lcdFilter")
end

local result = table.pack(xpcall(loader, errorHandler, "entry.lcdFilter", ...))
local success = result[1]
-- print error to stdout and re-throw
if not success then
    if fallbackStderr then
        print(result[2])
    else
        io.stderr:write(result[2])
    end
    error("Error occurred in bundled file.")
end

return table.unpack(result, 2)
