-- Search Assistant
-- made by:         Chr1Z
-- original by:     Tikatoy
-- description:     search the top X cards of your deck
information = {
    version = "1.4",
    last_updated = "12.11.2022"
}

MAT_GUIDS = { "8b081b", "bd0ff4", "383d8b", "0840d5" }

-- common parameters
local buttonParameters          = {}
buttonParameters.function_owner = self
buttonParameters.font_size      = 125
buttonParameters.width          = 650
buttonParameters.height         = 225

local inputParameters          = {}
inputParameters.function_owner = self
inputParameters.input_function = "updateSearchNumber"
inputParameters.tooltip        = "number of cards to search"
inputParameters.label          = "#"
inputParameters.font_size      = 175
inputParameters.width          = 400
inputParameters.height         = inputParameters.font_size + 23
inputParameters.position       = { 0, 0.11, 0 }
inputParameters.alignment      = 3
inputParameters.validation     = 2

function onSave() return JSON.encode(playerColor) end

function onLoad(save_state)
    if save_state ~= nil then
        playerColor = JSON.decode(save_state)
    end

    if playerColor == nil then
        playerColor = Player.getAvailableColors()[1]
    end

    normalView()

    self.addContextMenuItem("More Information", function()
        printToAll("------------------------------", "White")
        printToAll("Search Assistant v" .. information["version"] .. " by Chr1Z", "Orange")
        printToAll("last updated: " .. information["last_updated"], "White")
        printToAll("original concept by Tikatoy", "White")
    end)
end

-- regular view with search box and color switcher
function normalView()
    self.clearButtons()
    self.clearInputs()

    createSearchButton()
    changeColor("initialize")
    self.createInput(inputParameters)
end

-- view during a search with "done" buttons
function searchView()
    self.clearButtons()
    self.clearInputs()

    createDoneButton(true)
    createDoneButton(false)
end

-- change color (or initialize button)
function changeColor(arg, _, isRightClick)
    if arg ~= "initialize" then
        -- update table with colors
        COLORS = Player.getAvailableColors()
        local pos = indexOf(COLORS, playerColor)

        if isRightClick then
            if pos == nil or pos == 1 then pos = #COLORS
            else pos = pos - 1 end
        else
            if pos == nil or pos == #COLORS then pos = 1
            else pos = pos + 1 end
        end

        -- update playerColor
        playerColor = COLORS[pos]

        -- remove button and recreate it afterwards
        self.removeButton(1)
    end

    buttonParameters.click_function = "changeColor"
    buttonParameters.tooltip        = "change color"
    buttonParameters.position       = { 0, 0.11, -0.65 }
    buttonParameters.label          = playerColor
    buttonParameters.color          = Color.fromString(playerColor)
    buttonParameters.hover_color    = buttonParameters.color
    self.createButton(buttonParameters)
end

-- create the search button
function createSearchButton()
    buttonParameters.click_function = "startSearch"
    buttonParameters.tooltip        = "start the search"
    buttonParameters.position       = { 0, 0.11, 0.65 }
    buttonParameters.label          = "Search"
    buttonParameters.color          = Color.fromString("White")
    buttonParameters.hover_color    = nil
    self.createButton(buttonParameters)
end

-- create the done buttons (with and without shuffle)
function createDoneButton(arg)
    if arg then
        buttonParameters.click_function = "endSearch1"
        buttonParameters.tooltip        = "Done (Shuffle)"
        buttonParameters.position       = { 0, 0.11, -0.65 }
        buttonParameters.label          = "Shuffle"
    else
        buttonParameters.click_function = "endSearch2"
        buttonParameters.tooltip        = "Done (No Shuffle)"
        buttonParameters.position       = { 0, 0.11, 0.65 }
        buttonParameters.label          = "No Shuffle"
    end

    buttonParameters.color       = Color.fromString("White")
    buttonParameters.hover_color = nil
    self.createButton(buttonParameters)
end

-- get the draw deck from the player mat
function getDrawDeck()
    mat.call("getDrawDiscardDecks")
    return mat.getVar("drawDeck")
end

-- input_function to get number of cards to search
function updateSearchNumber(_, _, input)
    inputParameters.value = tonumber(input)
end

-- start the search (change UI, set hand aside, draw cards)
function startSearch(_, color)
    if inputParameters.value == nil then
        printToColor("Enter the number of cards to search in the textbox.", color, "Orange")
        return
    end

    local hand_data = Player[playerColor].getHandTransform()

    -- make distinction between players based on hand position
    if hand_data.position.x < -30 then
        if hand_data.position.z > 0 then
            playerNumber = 1
        else
            playerNumber = 2
        end
    else
        if hand_data.position.z > 0 then
            playerNumber = 3
        else
            playerNumber = 4
        end
    end

    mat = getObjectFromGUID(MAT_GUIDS[playerNumber])
    local zoneID = mat.getVar("zoneID")

    drawDeck = getDrawDeck()
    if drawDeck == nil then
        printToColor("Draw pile could not be found!", color, "Red")
        return
    end

    drawDeckPos = drawDeck.getPosition()
    printToColor("Place target(s) of search on set aside hand.", color, "Green")

    -- get position for set aside cards
    local hand = Player[playerColor].getHandObjects()
    deck_rotation = { hand_data.rotation.x, hand_data.rotation.y + 180, 180 }

    -- for left players (p1 and p3) move to the left, for right players (p2 and p4) to the right
    if playerNumber == 1 or playerNumber == 3 then
        set_aside_pos = hand_data.position - 15 * hand_data.right
    else
        set_aside_pos = hand_data.position + 15 * hand_data.right
    end

    for i = #hand, 1, -1 do
        hand[i].setPosition(set_aside_pos - Vector(0, i * 0.3, 0))
        hand[i].setRotation(deck_rotation)
    end

    searchView()

    -- handling for Norman Withers
    for _, object in ipairs(getObjectFromGUID(zoneID).getObjects()) do
        local pos = self.positionToLocal(object.getPosition())
        if pos.z < -0.5 and object.tag == "Card" and not object.is_face_down then
            object.flip()
            Wait.time(function() drawDeck = getDrawDeck() end, 1)
            break
        end
    end

    Wait.time(function() drawDeck.deal(inputParameters.value, playerColor) end, 1)
end

-- place hand back into deck and optionally shuffle
function endSearch1() endSearch(true) end

function endSearch2() endSearch(false) end

function endSearch(shuffle)
    local hand = Player[playerColor].getHandObjects()

    for i = #hand, 1, -1 do
        hand[i].setPosition(drawDeckPos + Vector(0, 6 - i * 0.3, 0))
        hand[i].setRotation(deck_rotation)
    end

    if shuffle then
        Wait.time(function()
            local deck = getDrawDeck()
            if deck ~= nil then
                deck.shuffle()
            end
        end, 2)
    end

    -- draw set aside cards (from the ground!)
    local objs = Physics.cast({
        origin = set_aside_pos - Vector(0, 5, 0),
        direction = { 0, 1, 0 },
        type = 3,
        size = { 2, 2, 2 },
        max_distance = 0
    })

    for _, v in ipairs(objs) do
        local obj = v.hit_object
        if obj.tag == "Deck" then
            Wait.time(function()
                obj.deal(#obj.getObjects(), playerColor)
            end, 1)
            break
        elseif obj.tag == "Card" then
            obj.setPosition(Player[playerColor].getHandTransform().position)
            obj.flip()
            break
        end
    end

    normalView()
end

-- helper to search array
function indexOf(array, value)
    for i, v in ipairs(array) do
        if v == value then return i end
    end
end