local c=require(script.Parent.Parent.TrelloHttp)local V=require(script.Parent.Parent.Commons)local l={customFields=false,card_pluginData=false,fields={"\110\097\109\101","\100\101\115\099";"\100\101\115\099\068\097\116\097","\099\108\111\115\101\100","\112\114\101\102\115"}}local z={RemoteId="\105\100";Name="\110\097\109\101",Description="\100\101\115\099";Closed="\099\108\111\115\101\100";Public={"\112\114\101\102\115","\112\101\114\109\105\115\115\105\111\110\076\101\118\101\108";mut=function(c)return c=="\112\117\098\108\105\099"end}}local H=V.generateMeta("\084\114\101\108\108\111\066\111\097\114\100")local Q local S={}function S.new(V,l,z)if not z or getmetatable(z)~="\084\114\101\108\108\111\067\108\105\101\110\116"then error("\091\084\114\101\108\108\111\066\111\097\114\100\046\110\101\119\093\058 \073\110\118\097\108\105\100 \099\108\105\101\110\116\033",0)elseif not V or V==""or V:len()>16384 then error("\091\084\114\101\108\108\111\066\111\097\114\100\046\110\101\119\093\058 \073\110\118\097\108\105\100 \110\097\109\101\033 \077\097\107\101 \115\117\114\101 \116\104\097\116 \116\104\101 \110\097\109\101 \105\115 \097 \110\111\110-\101\109\112\116\121 \115\116\114\105\110\103 \119\105\116\104 \108\101\115\115 \116\104\097\110 \049\054\051\056\052 \099\104\097\114\097\099\116\101\114\115\046",0)end local H=z:MakeURL("\047\098\111\097\114\100\115",{name=V,defaultLabels=false;defaultLists=false,prefs_selfJoin=false;prefs_cardCovers=false,prefs_permissionLevel=l and"\112\117\098\108\105\099"or"\112\114\105\118\097\116\101"})local S=c.RequestInsist(H,c.HttpMethod.POST,"\123\125",true)return Q(z,S.Body)end function S.fromRemote(V,z)if not z or getmetatable(z)~="\084\114\101\108\108\111\067\108\105\101\110\116"then error("\091\084\114\101\108\108\111\066\111\097\114\100\046\102\114\111\109\082\101\109\111\116\101\093\058 \073\110\118\097\108\105\100 \099\108\105\101\110\116\033",0)elseif not V or V==""then error("\091\084\114\101\108\108\111\066\111\097\114\100\046\102\114\111\109\082\101\109\111\116\101\093\058 \073\110\118\097\108\105\100 \098\111\097\114\100 \105\100\033",0)end local H=z:MakeURL("\047\098\111\097\114\100\115\047"..V,l)local S=c.RequestInsist(H,c.HttpMethod.GET,nil,true)return Q(z,S.Body)end function S.fetchAllFrom(V)if not V or getmetatable(V)~="\084\114\101\108\108\111\067\108\105\101\110\116"then error("\091\084\114\101\108\108\111\066\111\097\114\100\046\102\114\111\109\082\101\109\111\116\101\093\058 \073\110\118\097\108\105\100 \099\108\105\101\110\116\033",0)end local l=V:MakeURL("\047\109\101\109\098\101\114\115\047\109\101\047\098\111\097\114\100\115",{filter="\111\112\101\110";fields={"\110\097\109\101","\100\101\115\099";"\100\101\115\099\068\097\116\097","\099\108\111\115\101\100","\112\114\101\102\115"},lists="\097\108\108",memberships="\110\111\110\101";organization=false,organization_fields=""})local z=c.RequestInsist(l,c.HttpMethod.GET,nil,true)local H=z.Body local S={}for c,l in pairs(H)do table.insert(S,Q(V,l))end return S end Q=function(Q,S)if not S then return nil end local i={}local G={}local N={Loaded=false,Client=Q}for c,l in pairs(z)do local H=V.getValue(S,c,z)N[c]=H i[c]=H end N._pkg={}function N._pkg.appendLabel(c)if G[c.RemoteId]then error("\068\117\112\108\105\099\097\116\101 \108\097\098\101\108 \105\100\033")end G[c.RemoteId]=c end function N.Pull(S,H)local G=Q:MakeURL("\047\098\111\097\114\100\115\047"..S.RemoteId,l)local Y=(c.RequestInsist(G,c.HttpMethod.GET,nil,true)).Body if not Y then N=nil S=nil error("\079\079\070\033 \067\097\114\100 \104\097\115 \098\101\101\110 \100\101\108\101\116\101\100\033")end for c,l in pairs(z)do local Q=V.getValue(Y,c,z)if H or S[c]==i[c]then S[c]=Q end i[c]=Q end end function N.Push(l,V)local z=0 local H={}for c,Q in pairs(i)do if Q~=l[c]or V then H[c]=l[c]z=z+1 end end if z==0 then warn("\091\084\114\101\108\108\111\047\066\111\097\114\100\046\067\111\109\109\105\116\093\058 \078\111\116\104\105\110\103 \116\111 \099\104\097\110\103\101\046 \083\107\105\112\112\105\110\103")end local S=Q:MakeURL("\047\098\111\097\114\100\115\047"..l.RemoteId,{name=H.Name,desc=H.Description,closed=H.Closed;prefs=H.Public~=nil and{permissionLevel=H.Public and"\112\117\098\108\105\099"or"\112\114\105\118\097\116\101"}or nil})c.RequestInsist(S,c.HttpMethod.PUT,"\123\125",true)for c,V in pairs(H)do i[c]=V end end function N.Delete(V)local l=Q:MakeURL("\047\098\111\097\114\100\115\047"..V.RemoteId)c.RequestInsist(l,c.HttpMethod.DELETE,nil,true)N=nil end return setmetatable(N,H)end return{Public=S,Make=Q}
--[[
    Name: Board.lua
    From roblox-trello v2

    Description: Constructor for Trello Boards.


    Copyright (c) 2019 Luis, David Duque

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.
--]]

local HTTP = require(script.Parent.Parent.TrelloHttp)
local commons = require(script.Parent.Parent.Commons)

local fetchTable = {
    customFields = false,
    card_pluginData = false,
    fields = {"name","desc","descData","closed","prefs"},
}
local indexDictionary = {
    RemoteId = "id",
    Name = "name",
    Description = "desc",
    Closed = "closed",
    Public = {"prefs", "permissionLevel", mut = function(p) return p == "public" end}
}

-- TrelloBoard Metatable
local TrelloBoardMeta = commons.generateMeta("TrelloBoard")

-- Local function prototype to make a board based on a body dump
local makeBoard

local TrelloBoard = {}

--[[**
    Creates a new board, that is then also created on Trello.

    @param [t:String] name The Board's name. Must to be a non-empty string with a maximum of 16384 characters.
    @param [t:Boolean] public Whether the board is public or not. If this field is not provided, the board will be private.
    @param [t:TrelloClient] client The client the board will be assigned to.

    @returns [t:TrelloBoard] A new TrelloBoard that was freshly created.
**--]]
function TrelloBoard.new(name, public, client)
    if not client or getmetatable(client) ~= "TrelloClient" then
        error("[TrelloBoard.new]: Invalid client!", 0)
    elseif not name or name == "" or name:len() > 16384 then
        error("[TrelloBoard.new]: Invalid name! Make sure that the name is a non-empty string with less than 16384 characters.", 0)
    end

    local commitURL = client:MakeURL("/boards", {
        name = name,
        defaultLabels = false,
        defaultLists = false,
        prefs_selfJoin = false,
        prefs_cardCovers = false,
        prefs_permissionLevel = public and "public" or "private"
    })

    local result = HTTP.RequestInsist(commitURL, HTTP.HttpMethod.POST, "{}", true)

    return makeBoard(client, result.Body)
end

--[[**
    Fetches a board from Trello (includes lists, cards, etc.).

    @param [t:String] name The Board's ID.
    @param [t:TrelloClient] client The client the board will be assigned to.

    @returns [t:Variant<TrelloBoard,nil>] The Trello Board fetched. Returns nil if the board doesn't exist.
**--]]
function TrelloBoard.fromRemote(remoteId, client)
    if not client or getmetatable(client) ~= "TrelloClient" then
        error("[TrelloBoard.fromRemote]: Invalid client!", 0)
    elseif not remoteId or remoteId == "" then
        error("[TrelloBoard.fromRemote]: Invalid board id!", 0)
    end

    local commitURL = client:MakeURL("/boards/" .. remoteId, fetchTable)

    local result = HTTP.RequestInsist(commitURL, HTTP.HttpMethod.GET, nil, true)

    return makeBoard(client, result.Body)
end

--[[**
    Fetches all the boards the provided client has edit access to.

    @param [t:TrelloClient] client The client where to fetch the boards from.

    @returns [t:Array<TrelloBoard>] An array containing zero or more trello boards.
**--]]
function TrelloBoard.fetchAllFrom(client)
    if not client or getmetatable(client) ~= "TrelloClient" then
        error("[TrelloBoard.fromRemote]: Invalid client!", 0)
    end

    local commitURL = client:MakeURL("/members/me/boards", {
        filter = "open",
        fields = {"name","desc","descData","closed","prefs"},
        lists = "all",
        memberships = "none",
        organization = false,
        organization_fields = ""
    })

    local result = HTTP.RequestInsist(commitURL, HTTP.HttpMethod.GET, nil, true)
    local body = result.Body
    local boards = {}

    for _, b in pairs(body) do
        table.insert(boards, makeBoard(client, b))
    end

    return boards
end

-- Prototype implementation
makeBoard = function(client, data)
    if not data then
        return nil
    end

    local tracking = {}
    local labels = {}

    local trelloBoard = {
        Loaded = false,
        Client = client
    }

    for i, _ in pairs(indexDictionary) do
        local val = commons.getValue(data, i, indexDictionary)
        trelloBoard[i] = val
        tracking[i] = val
    end

    -- PACKAGE-PRIVATE METHODS - DO NOT USE
    trelloBoard._pkg = {}

    function trelloBoard._pkg.appendLabel(label)
        if labels[label.RemoteId] then
            error("Duplicate label id!")
        end

        labels[label.RemoteId] = label
    end

    --[[**
        Fetches the metadata from Trello and updates the board's metadata. (Doesn't apply to lists, cards, etc.)

        @param [t:Boolean] hard Whether to overwrite changes that you did not push. (Defaults to false, which will do a soft pull)

        @returns [t:Void]
    **--]]
    function trelloBoard:Pull(hard)
        local commitURL = client:MakeURL("/boards/"..self.RemoteId, fetchTable)

        local updatedData = HTTP.RequestInsist(commitURL, HTTP.HttpMethod.GET, nil, true).Body

        if not updatedData then
            -- FIXME: HANDLE THIS
            trelloBoard = nil
            self = nil
            error("OOF! Card has been deleted!")
        end

        for i, _ in pairs(indexDictionary) do
            local val = commons.getValue(updatedData, i, indexDictionary)
            if hard or self[i] == tracking[i] then
                self[i] = val
            end
            tracking[i] = val
        end
    end

    --[[**
        Pushes all metadata changes to Trello. (Doesn't apply to lists, cards, etc.)

        @param [t:Boolean] force Whether to push all changes to the board even though nothing has been changed.

        @returns [t:Void]
    **--]]
    function trelloBoard:Push(force)
        local count = 0
        local commit = {}

        for i, v in pairs (tracking) do
            if v ~= self[i] or force then
                commit[i] = self[i]
                count = count + 1
            end
        end

        if count == 0 then
            warn("[Trello/Board.Commit]: Nothing to change. Skipping")
        end

        local commitURL = client:MakeURL("/boards/"..self.RemoteId, {
            name = commit.Name,
            desc = commit.Description,
            closed = commit.Closed,
            prefs = (commit.Public ~= nil) and {
                permissionLevel = commit.Public and "public" or "private"
            } or nil
        })

        HTTP.RequestInsist(commitURL, HTTP.HttpMethod.PUT, "{}", true)

        for i, v in pairs(commit) do
            tracking[i] = v
        end
    end

    --[[**
        Deletes this board from Trello. All garbage collection is up to the developer to perform.

        @returns [t:Void]
    **--]]
    function trelloBoard:Delete()
        local commitURL = client:MakeURL("/boards/" .. self.RemoteId)

        HTTP.RequestInsist(commitURL, HTTP.HttpMethod.DELETE, nil, true)

        trelloBoard = nil
    end

    return setmetatable(trelloBoard, TrelloBoardMeta)
end

return {Public = TrelloBoard, Make = makeBoard}
