#@name chinese_checkers
@inputs 
@outputs 
@persist [Pattern Files Ranks]:string Holo Offsets:array Colors:table Clicked PrevClicked Players:string Game:table MoveList:string MoveStack:array
@trigger none
@model models/hunter/plates/plate2x2.mdl


if (first()) {
    
    Players = "[GO]"
    
    Colors = table(
        "G" = vec(38, 166, 91),
        "B" = vec(89, 171, 227),
        "R" = vec(210, 77, 87),
        "Y" = vec(244, 208, 63),
        "P" = vec(42, 68, 173),
        "O" = vec(235, 149, 50),
        "W" = vec(218, 223, 225)
    )
    
    Offsets = array(
        1 = 6,
        2 = 6,
        3 = 6,
        4 = 6,
        5 = 2,
        6 = 3,
        7 = 4,
        8 = 5,
        9 = 6,
        10 = 6,
        11 = 6,
        12 = 6,
        13 = 6,
        14 = 11,
        15 = 12,
        16 = 13,
        17 = 14
    )
    
    Pattern = "
               G             
              G G            
             G G G           
            G G G G          
    B B B B W W W W W R R R R
     B B B W W W W W W R R R 
      B B W W W W W W W R R  
       B W W W G G W W W R   
        W W W W W W W W W    
       Y W W W G W W W W P   
      Y Y W W G W W W W P P  
     Y Y Y W W W W W W P P P 
    Y Y Y Y W W W W W P P P P
             O O O O         
              O O O          
               O O           
                O            ":replaceRE("%s+", "")
    
    Files = "
                A
               B B
              C C C
             D D D D
    E E E E E E E E E E E E E
     F F F F F F F F F F F F
      G G G G G G G G G G G
       H H H H H H H H H H
        I I I I I I I I I
       J J J J J J J J J J
      K K K K K K K K K K K
     L L L L L L L L L L L L
    M M M M M M M M M M M M M
             N N N N
              O O O
               P P
                Q             ":replaceRE("%s+", "")
    
    Ranks = "
                A
               A B
              A B C
             A B C D
    A B C D E F G H I J K L M
     A B C D E F G H I J K L
      A B C D E F G H I J K
       A B C D E F G H I J
        A B C D E F G H I
       A B C D E F G H I J
      A B C D E F G H I J K
     A B C D E F G H I J K L
    A B C D E F G H I J K L M
             A B C D
              A B C
               A B
                A            ":replaceRE("%s+", "")
    
    
    function number getMaxRank(File) {
        return toByte( "ABCDMLKJIJKLMDCBA"[File] ) - 64
    }
    function number getRank(Index) {
        return toByte(Ranks[Index]) - 64
    }
    
    function number getFile(Index) {
        return toByte(Files[Index]) - 64
    }
    
    function array getNeighbors(Index) {
        local Array = array()
        
        local File = getFile(Index)

        if (File == getFile(Index + 1)) { Array[1, number] = Index + 1 } #up
        if (File == getFile(Index - 1)) { Array[2, number] = Index - 1 } #down
        
        local Diff = getMaxRank(File + 1) - getMaxRank(File)
        if (abs(Diff) > 1) {
            local Next = Index + abs(Diff)
            
            if (abs(File - getFile(Next - 0)) == 1) { Array[3, number] = Next - 0 } #top right
            if (abs(File - getFile(Next - 1)) == 1) { Array[5, number] = Next - 1 } #bot right
        }
        else {
            local Next = Index + getMaxRank(File) + max(0, Diff)
            
            if (abs(File - getFile(Next - 0)) == 1) { Array[3, number] = Next - 0 } #top right
            if (abs(File - getFile(Next - 1)) == 1) { Array[5, number] = Next - 1 } #bot right
        }
        
        local Diff = getMaxRank(File - 1) - getMaxRank(File)
        if (abs(Diff) > 1) {
            local Next = Index - abs(Diff)
            
            if (abs(File - getFile(Next + 1)) == 1) { Array[4, number] = Next + 1 } #top left
            if (abs(File - getFile(Next - 0)) == 1) { Array[6, number] = Next - 0 } #bot left
        }
        else {
            local Next = Index - getMaxRank(File) - max(0, Diff)
            
            if (abs(File - getFile(Next + 1)) == 1) { Array[4, number] = Next + 1 } #top left
            if (abs(File - getFile(Next - 0)) == 1) { Array[6, number] = Next - 0 } #bot left           
        }
        
        return Array
    }

    function vector linePlaneIntersection( Player:entity, PlanePos:vector, Normal:vector ) {
        local LineP1 = Player:shootPos()
        local LineP2 = LineP1 + Player:eye()
    
        local X = Normal:dot(PlanePos - LineP1) / Normal:dot(LineP2 - LineP1)
        return LineP1 + X*(LineP2 - LineP1)
    }


    function string table:get_possible_moves(Index) {
        local List = ""
        local Stack = array()

        foreach (D, N:number = This[Index, table]["neighbors", array]) {
            local NPiece = This[N, table]["piece_type", string]
            if (NPiece != "W") {
                foreach (D2, N2:number = This[N, table]["neighbors", array]) {
                    if (This[N2, table]["piece_type", string] == "W" & D == D2) {
                        List += format("%03d%03d", Index, N2)
                    }
                }
            }
        }

        return List
    }


    entity():setAlpha(0)
    entity():setAng(ang())
}





Entity = entity()
Radius = 24

if (Holo < 121) {
    interval(15)

    while (perf() & (holoRemainingSpawns() > 1) & Holo < 121) {
        Holo++
        
        local File = getFile(Holo)
        local Rank = getRank(Holo)
        
        local MeshX = Radius*0.5*sqrt(3)
        local MeshY = Radius*0.75
        
        local Pos = vec(-MeshX*6.5 + Offsets[File, number]*MeshX, MeshY*9, sqrt(Radius))
        Pos = Pos + vec(Rank*MeshX - File*MeshX*0.5, -File*MeshY, 0)
        
        holoCreate(Holo, Entity:toWorld(Pos), vec(Radius - 0.25):setZ(sqrt(Radius))/12, Entity:angles())
        holoModel(Holo, "hexagon")
        holoMaterial(Holo, "phoenix_storms/fender_white")
        holoParent(Holo, Entity)
        
        Game[Holo, table] = table(
            "neighbors" = getNeighbors(Holo),
            "piece_type" = "W"
        )
        
        local Piece = Pattern[Holo]
        if (Piece:findRE(Players)) {
            holoColor(Holo, Colors[Pattern[Holo], vector])

            local Index = Holo + 1000
            
            holoCreate(Index)
            holoParent(Index, Entity)
            holoModel(Index, "models/props_phx/games/chess/black_pawn.mdl")
            holoMaterial(Index, "phoenix_storms/fender_white")
            holoColor(Index, Colors[Piece, vector])
            holoPos(Index, holoEntity(Holo):toWorld(vec(0, 0, sqrt(Radius)/2)))
            
            Game[Holo, table]["piece_holo", number] = Index
            Game[Holo, table]["piece_type", string] = Piece
            Game[Holo, table]["piece_goal", string] = Piece
        }
        else {
            holoColor(Holo, Colors["W", vector])
        }
        
        findIncludeEntity(holoEntity(Holo))
    }
}
else {
    
    if (findCanQuery()) {
        
        local ClickPos = linePlaneIntersection(owner(), Entity:toWorld(vec(0, 0, sqrt(Radius))), Entity:up())

        findClipToClass("gmod_wire_hologram")
        findInSphere(ClickPos, Radius*0.5)
        findSortByDistance(ClickPos)
        
        Clicked = holoIndex(find())

    }
    interval(90)

    if (changed(Clicked)) {
        for (I = 1, MoveList:length(), 6) {
            local Sub = MoveList:sub(I + 3, I + 5):toNumber()
            holoColor(Sub, Colors[Game[Sub, table]["piece_type", string], vector])
        }  
        
        MoveList = ""
        if (Game[Clicked, table]["piece_type", string] != "W") {
            MoveStack:pushNumber(Clicked)
        }
    }
    
    while (perf(95) & MoveStack:count()) {
        local MoveIndex = MoveStack:popNumber()
        local MoveNeighbors = Game[MoveIndex, table]["neighbors", array]
        
        foreach (D, N:number = MoveNeighbors) {
            local NextPiece = Game[N, table]["piece_type", string]
            if (NextPiece != "W") {
                foreach (D2, N2:number = Game[N, table]["neighbors", array]) {
                    if (Game[N2, table]["piece_type", string] == "W" & D == D2) {
                        local A = format("%03d%03d", MoveIndex, N2)
                        local B = format("%03d%03d", N2, MoveIndex)
                        
                        if (MoveList:find(A)) { continue } 
                        if (MoveList:find(B)) { continue }
                        
                        MoveStack:pushNumber(N2)
                        MoveList += format("%03d%03d", MoveIndex, N2)
                    }
                } 
            }
        }
        
        if (!MoveStack:count()) {
            for (I = 1, MoveList:length(), 6) {
                local Sub = MoveList:sub(I + 3, I + 5):toNumber()
                holoColor(Sub, vec(255, 0, 0))
            } 
        }
    }
}



#[        for (I = 1, MoveList:length(), 6) {
            local Sub = MoveList:sub(I + 3, I + 5):toNumber()
            holoColor(Sub, Colors[Game[Sub, table]["piece_type", string], vector])
            #print(Sub)
        }
        
        MoveList = Game:get_possible_moves(Clicked)

        for (I = 1, MoveList:length(), 6) {
            local Sub = MoveList:sub(I + 3, I + 5):toNumber()
            holoColor(Sub, vec(255, 0, 0))
        }        ]#
    
    
#[    if (changed(Clicked)) {
        foreach (K, N:number = Game[PrevClicked, table]["neighbors", array]) {
            holoColor(N, Colors[Game[N, table]["piece_type", string], vector])
        }
        
        holoColor(PrevClicked, vec(255, 255, 255))
        holoColor(Clicked, vec(255, 255, 0))
        
        PrevClicked = Clicked
        
        foreach (K, N:number = Game[Clicked, table]["neighbors", array]) {
            holoColor(N, vec(255, 0, 0))
        }   
            
    }]#
