Index: pages/api/poker/index.js
===================================================================
--- pages/api/poker/index.js	(revision b13f93b3ae8e02def0043ff767c69e28939b36ff)
+++ pages/api/poker/index.js	(revision 3a783f24e1a3132486ae1fca341b141c7b327563)
@@ -11,6 +11,8 @@
     creator: '',
     started: false,
+    ended: false,
     round: 0,
-    turnIdx: 0,
+    turnIdx: -1,
+    pot: 0,
     lastBet: 0,
     turnsSinceLastBet: 0,
@@ -18,4 +20,7 @@
     deck: [],
     cardsOnTable: [],
+    winners: [],
+    splitWinners: false,
+    turnTimeout: null,
 }
 
@@ -26,8 +31,14 @@
     displayName: '',
     cards: [],
+    hand: {
+        hand: '',
+        highCard: 0,
+    },
     betAmount: 0,
     isSatDown: false,
     isCoordinator: false,
     isFolded: false,
+    isGhost: false,
+    credits: 0,
 }
 
@@ -45,6 +56,8 @@
                     "DA", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DX", "DJ", "DQ", "DK"    ];
 
+const deck = [...singleDeck];
+
 /* We are using 5 decks */
-const deck = singleDeck.concat(singleDeck).concat(singleDeck).concat(singleDeck).concat(singleDeck);
+// const deck = singleDeck.concat(singleDeck).concat(singleDeck).concat(singleDeck).concat(singleDeck);
 
 /**
@@ -81,5 +94,5 @@
 }
 
-function setNextPlayerIdx(tableId) {
+function getMaxBet(tableId) {
     const tableIdx = tables.map(e=>e.id).indexOf(tableId);
 
@@ -87,11 +100,54 @@
         const table = tables[tableIdx];
 
+        let maxBet = 0;
+        table.players.forEach(player => {
+            if (player.betAmount > maxBet) {
+                maxBet = player.betAmount;
+            }
+        })
+        
+        return maxBet;
+    }
+    
+    return 0;
+}
+
+function setNextPlayerIdx(tableId) {
+    const tableIdx = tables.map(e=>e.id).indexOf(tableId);
+
+    if (tables[tableIdx] !== undefined) {
+        const table = tables[tableIdx];
+
+        if (table.turnTimeout !== null) clearTimeout(table.turnTimeout);
+
+        let counter = 10;
+
         while (true) {
+            counter--;
+
             table.turnIdx++;
             table.turnIdx %= table.players.length;
             
             if (table.players[table.turnIdx] !== undefined && table.players[table.turnIdx].isSatDown && !table.players[table.turnIdx].isFolded) {
+                if (table.round >= 2 && table.players[table.turnIdx].credits === 0) continue;
+
+                let prevTurnIdx = table.turnIdx;
+                table.turnTimeout = setTimeout(() => {
+                    if (prevTurnIdx === table.turnIdx) {
+                        if (table.players[table.turnIdx] !== undefined) {
+                            table.players[table.turnIdx].isFolded = true;
+
+                            setNextPlayerIdx(table.id);
+                        }
+                    }
+                }, 30000);
+
+                table.lastBet = getMaxBet(table.id) - table.players[table.turnIdx].betAmount;
+                if (table.round === 1 && getMaxBet(table.id) <= 20) table.lastBet = 20;
+
                 return ;
             }
+
+            if (counter <= 0) return ;
         }
     }
@@ -113,4 +169,170 @@
             }
         }
+        else if (table.round > 2) {
+            const card = drawASingleCard(table.id);
+                            
+            if (card !== undefined) {
+                table.cards.push(card);
+            }
+        }
+    }
+}
+
+function resetGame(tableId) {
+    const tableIdx = tables.map(e=>e.id).indexOf(tableId);
+
+    if (tables[tableIdx] !== undefined) {
+        const table = tables[tableIdx];
+
+        table.started = false;
+        table.ended = false;
+        table.round = 0;
+        table.turnIdx = 0;
+        table.turnTimeout = null;
+        table.pot = 0;
+        table.lastBet = 20;
+        table.turnsSinceLastBet = 0;
+        table.deck = [...deck];
+
+        table.players = table.players.filter(e=>e.isGhost === false);
+
+        table.players.forEach(player => {
+            player.credits = 0;
+            player.cards = [];
+            player.isFolded = false;
+            player.betAmount = 0;
+            player.wonAmount = 0;
+            player.hand = {
+                hand: '',
+                highCard: 0,
+            }
+        })
+        table.winners = [];
+        table.splitWinners = false;
+        table.cards = [];
+    }
+}
+
+function giveMoneyToTheWinners(tableId) {
+    const tableIdx = tables.map(e=>e.id).indexOf(tableId);
+
+    if (tables[tableIdx] !== undefined) {
+        const table = tables[tableIdx];
+
+        const satDownPlayers = table.players.filter(e => e.isSatDown === true);
+        const satDownCount = satDownPlayers.length;
+
+        table.players.forEach(player => {
+            let winnings = 0;
+            if (table.winners.indexOf(player) !== -1) {
+                // winner
+                winnings = 0;
+                table.players.forEach(tmpPlayer => {
+                    winnings += Math.min(tmpPlayer.betAmount, player.betAmount);
+                })
+
+                axios.get(`${process.env.HOME_URL}/api/postgre/?action=add_credits&session_id=${player.id}&credits=${winnings}&game=poker&outcome=won`).then(postgreRes => {
+                    if (postgreRes.data?.success) {
+                        player.credits = postgreRes.data?.credits;
+                    }
+                });
+            }
+            else {
+                // loser
+                winnings = player.betAmount;
+                table.players.forEach(tmpPlayer => {
+                    if (table.winners.indexOf(tmpPlayer) !== -1) {
+                        winnings -= tmpPlayer.betAmount;
+                    }
+                })
+
+                axios.get(`${process.env.HOME_URL}/api/postgre/?action=add_credits&session_id=${player.id}&credits=${winnings}&game=poker&outcome=lost`).then(postgreRes => {
+                    if (postgreRes.data?.success) {
+                        player.credits = postgreRes.data?.credits;
+                    }
+                });
+            }
+
+            player.wonAmount = winnings;
+        })
+
+        setTimeout(() => {
+            resetGame(table.id);
+        }, 15000);
+    }
+}
+
+function setWinner(tableId) {
+    const tableIdx = tables.map(e=>e.id).indexOf(tableId);
+
+    if (tables[tableIdx] !== undefined) {
+        const table = tables[tableIdx];
+
+        table.turnIdx = -1;
+
+        table.players.forEach(player => {
+            if (player.isSatDown && !player.isFolded) {
+                player.hand = getHandDetails(player.cards.concat(table.cards))
+            }
+        })
+
+        hands.forEach(hand => {
+            const playerHands = table.players.filter(e=>e.hand.hand === hand);
+
+            if (table.winners.length === 0) {
+                if (playerHands.length === 1) {
+                    table.winners.push(playerHands[0])
+                }
+                else if (playerHands.length > 1) {
+                    let tmp = playerHands[0].hand.highCard;
+                    let tmpWinners = [];
+
+                    playerHands.forEach(player => {
+                        if (player.hand.highCard > tmp) {
+                            tmp = player.hand.highCard;
+                        }
+                    })
+
+                    playerHands.forEach(player => {
+                        if (player.hand.highCard === tmp) {
+                            tmpWinners.push(player);
+                        }
+                    })
+
+                    if (tmpWinners.length > 1) table.splitWinners = true;
+                    table.winners = [...tmpWinners];
+                }
+            }
+        })
+
+        giveMoneyToTheWinners(table.id);
+    }
+}
+
+function progressRoundIfNeeded(tableId) {
+    const tableIdx = tables.map(e=>e.id).indexOf(tableId);
+
+    if (tables[tableIdx] !== undefined) {
+        const table = tables[tableIdx];
+
+        const satDownPlayers = table.players.filter(e=>e.isSatDown === true);
+        const remainingPlayers = satDownPlayers.filter(e=>e.isFolded === false);
+
+        if (table.turnsSinceLastBet === remainingPlayers.length) {
+            table.round++;
+            table.lastBet = 0;
+            table.turnsSinceLastBet = 0;
+
+            if (table.round <= 4) {
+                getCardsOnTable(table.id);
+            }
+            else {
+                table.ended = true;
+            }
+
+            if (table.ended && table.winners.length === 0) {
+                setWinner(table.id);
+            }
+        }
     }
 }
@@ -129,6 +351,8 @@
         creator: playerName,
         started: false,
+        ended: false,
         round: 0,
-        turnIdx: 0,
+        turnIdx: -1,
+        pot: 0,
         lastBet: 20,
         turnsSinceLastBet: 0,
@@ -137,12 +361,21 @@
             id: playerId,
             table: tableId,
+            credits: 0,
             status: '_1_just_entered',
             displayName: playerName,
             cards: [],
             betAmount: 0,
+            wonAmount: 0,
             isSatDown: false,
             isCoordinator: true,
             isFolded: false,
+            isGhost: false,
+            hand: {
+                hand: '',
+                highCard: 0,
+            },
         }],
+        winners: [],
+        splitWinners: false,
         cards: [],
     }
@@ -167,8 +400,20 @@
         });
 
+        let tmpWinners = [];
+        table.winners.forEach(winner => {
+            tmpWinners.push({
+                ...winner,
+                id: '',
+                table: '',
+                cards: '',
+            })
+        });
+
         let tmp = {
             ...table,
             deck: [],
             players: tmpPlayers,
+            winners: tmpWinners,
+            turnTimeout: null,
         }
 
@@ -201,12 +446,32 @@
                     id: '',
                     table: '',
-                    cards: player.cards.length > 0 ? ['back', 'back'] : '',
+                    cards: table.ended ? player.cards : player.cards.length > 0 ? ['back', 'back'] : '',
                 })
             }
         });
 
+        let tmpWinners = [];
+        table.winners.forEach(winner => {
+            if (winner.id === session_id) {
+                tmpWinners.push({
+                    ...winner,
+                    id: '',
+                    table: '',
+                })
+            }
+            else {
+                tmpWinners.push({
+                    ...winner,
+                    id: '',
+                    table: '',
+                    cards: table.ended ? winner.cards : winner.cards.length > 0 ? ['back', 'back'] : '',
+                })
+            }
+        });
         result = {
             ...table,
             players: tmpPlayers,
+            winners: tmpWinners,
+            turnTimeout: null,
         }
     }
@@ -227,5 +492,5 @@
 function getTableAndPlayer(session_id) {
     for (let tableIdx = 0; tableIdx < tables.length; tableIdx++) {
-        const playerIdx = tables[tableIdx].players.map(e=>e.id).indexOf(session_id);
+        const playerIdx = tables[tableIdx].players.filter(e=>e.isGhost === false).map(e=>e.id).indexOf(session_id);
 
         if (playerIdx !== -1) {
@@ -269,5 +534,5 @@
             const { success, table, player } = getTableAndPlayer(req.query.session_id)
 
-            if (success && table.started) {
+            if (success && table.started && !table.ended && player.isSatDown && !player.isFolded) {
                 if (table.players.map(e=>e.id).indexOf(req.query.session_id) !== table.turnIdx) {
                     res.end();
@@ -277,27 +542,53 @@
                 let okayToGo = false;
 
-                const satDownPlayers = table.players.filter(e=>e.isSatDown === true);
-                const remainingPlayers = satDownPlayers.filter(e=>e.folded === false);
-
                 if (req.query.specificAction === 'check') {
-
+                    if (table.lastBet === 0) {
+                        table.turnsSinceLastBet++;
+                        okayToGo = true;
+                        
+                        progressRoundIfNeeded(table.id);
+                    }
                 }
                 else if (req.query.specificAction === 'call') {
-                    player.betAmount += table.lastBet;
-                    table.turnsSinceLastBet++;
+                    await axios.get(`${process.env.HOME_URL}/api/postgre/?action=take_credits&session_id=${req.query.session_id}&credits=${table.lastBet}&takeWhatYouCan=true`).then(postgreRes => {
+                        if (postgreRes.data?.success) {
+                            player.credits = postgreRes.data?.credits;
+
+                            if (player.credits >= table.lastBet)
+                                player.betAmount += table.lastBet;
+                            else
+                                player.betAmount += player.credits;
+                                
+                            table.pot += table.lastBet;
+                            table.turnsSinceLastBet++;
+                            okayToGo = true;
+        
+                            progressRoundIfNeeded(table.id);
+                        }
+                    });
+                }
+                else if (req.query.specificAction === 'raise') {
+                    const betAmount = parseInt(req.query.betAmount);
+
+                    if (betAmount >= table.lastBet) {
+                        await axios.get(`${process.env.HOME_URL}/api/postgre/?action=take_credits&session_id=${req.query.session_id}&credits=${betAmount}&takeWhatYouCan=true`).then(postgreRes => {
+                            if (postgreRes.data?.success) {
+                                player.credits = postgreRes.data?.credits;
+
+                                player.betAmount += betAmount;
+                                table.pot += betAmount;
+                                table.turnsSinceLastBet = 1;
+                                okayToGo = true;
+                                
+                                progressRoundIfNeeded(table.id);
+                            }
+                        });
+                    }
+                }
+                else if (req.query.specificAction === 'fold') {
+                    player.isFolded = true;
                     okayToGo = true;
 
-                    if (table.turnsSinceLastBet === remainingPlayers.length) {
-                        table.round++;
-                        table.lastBet = 0;
-
-                        getCardsOnTable(table.id);
-                    }
-                }
-                else if (req.query.specificAction === 'raise') {
-                    
-                }
-                else if (req.query.specificAction === 'fold') {
-                    player.folded = true;
+                    progressRoundIfNeeded(table.id);
                 }
 
@@ -320,10 +611,17 @@
 
             if (success && !table.started) {
+                table.players.forEach(player => {
+                    axios.get(`${process.env.HOME_URL}/api/postgre/?action=check_if_logged_in&session_id=${player.id}`).then(postgreRes => {
+                        if (postgreRes.data?.success) {
+                            player.credits = postgreRes.data?.credits;
+                        }
+                    });
+                })
+
                 table.started = true;
                 table.round = 1;
 
-                const satDownPlayers = table.players.filter(e=>e.isSatDown === true);
-
-                table.turnIdx = Math.floor(Math.random(0, satDownPlayers.length))
+                table.turnIdx = Math.floor(Math.random(0, table.players.length))
+                setNextPlayerIdx(table.id);
 
                 table.players.forEach(player => {
@@ -363,4 +661,25 @@
          * /---------------------- GET ----------------------/
          * Creates the table and enters the user inside
+         * @action leave_table
+         * @param session_id
+         */
+         if (req.query.action === 'leave_table' && req.query?.session_id) {
+            const { success, table, player } = getTableAndPlayer(req.query.session_id);
+
+            if (success) {
+                player.isGhost = true;
+                player.isFolded = true;
+
+                if (table.players[table.turnIdx] !== undefined && table.players[table.turnIdx] === player) {
+                    setNextPlayerIdx(table.id);
+                }
+            }
+
+            res.end();
+        }
+
+        /**
+         * /---------------------- GET ----------------------/
+         * Creates the table and enters the user inside
          * @action join_a_table
          * @param session_id
@@ -375,5 +694,5 @@
                     const table = getTable(req.query.tableId)
 
-                    if (!table.started) {
+                    if (table !== undefined && !table.started) {
                         table.players.push({
                             ...samplePlayer,
@@ -459,2 +778,88 @@
  * ********************* END OF REQUEST HANDLER *********************
  */
+
+const hands = [
+    'Royal Flush',
+    'Straight Flush',
+    'Four of a Kind',
+    'Full House',
+    'Flush',
+    'Straight',
+    'Three of a Kind',
+    'Two Pairs',
+    'Pair',
+    'High Card',
+]
+
+const order = "23456789TJQKA"
+function getHandDetails(hand) {
+    const cards = hand
+    const faces = cards.map(a => String.fromCharCode([77 - order.indexOf(a[1])])).sort()
+    const suits = cards.map(a => a[0]).sort()
+    const counts = faces.reduce(count, {})
+    const duplicates = Object.values(counts).reduce(count, {})
+    const flush = suits[0] === suits[4]
+    const first = faces[0].charCodeAt(1)
+    const straight = faces.every((f, index) => f.charCodeAt(1) - first === index)
+    let rank =
+        (flush && straight && 1) ||
+        (duplicates[4] && 2) ||
+        (duplicates[3] && duplicates[2] && 3) ||
+        (flush && 4) ||
+        (straight && 5) ||
+        (duplicates[3] && 6) ||
+        (duplicates[2] > 1 && 7) ||
+        (duplicates[2] && 8) ||
+        9;
+
+    return { hand: hands[rank], highCard: faces.sort(byCountFirst).join("") }
+
+    function byCountFirst(a, b) {
+        //Counts are in reverse order - bigger is better
+        const countDiff = counts[b] - counts[a]
+        if (countDiff) return countDiff // If counts don't match return
+        return b > a ? -1 : b === a ? 0 : 1
+    }
+
+    function count(c, a) {
+        c[a] = (c[a] || 0) + 1
+        return c
+    }
+}
+
+function getCardCombinations(playerCards, tableCards) {
+    let combinations = [];
+
+    combinations.push([playerCards[0], tableCards[0], tableCards[1], tableCards[2], tableCards[3]])
+    combinations.push([playerCards[0], tableCards[0], tableCards[1], tableCards[2], tableCards[4]])
+
+    combinations.push([playerCards[0], tableCards[0], tableCards[1], tableCards[4], tableCards[3]])
+    combinations.push([playerCards[0], tableCards[0], tableCards[4], tableCards[2], tableCards[3]])
+    combinations.push([playerCards[0], tableCards[4], tableCards[1], tableCards[2], tableCards[3]])
+
+    
+    combinations.push([playerCards[1], tableCards[0], tableCards[1], tableCards[2], tableCards[3]])
+    combinations.push([playerCards[1], tableCards[0], tableCards[1], tableCards[2], tableCards[4]])
+
+    combinations.push([playerCards[1], tableCards[0], tableCards[1], tableCards[4], tableCards[3]])
+    combinations.push([playerCards[1], tableCards[0], tableCards[4], tableCards[2], tableCards[3]])
+    combinations.push([playerCards[1], tableCards[4], tableCards[1], tableCards[2], tableCards[3]])
+
+
+    combinations.push([playerCards[0], playerCards[1], tableCards[0], tableCards[1], tableCards[2]])
+    combinations.push([playerCards[0], playerCards[1], tableCards[0], tableCards[1], tableCards[3]])
+    combinations.push([playerCards[0], playerCards[1], tableCards[0], tableCards[1], tableCards[4]])
+
+    combinations.push([playerCards[0], playerCards[1], tableCards[0], tableCards[2], tableCards[3]])
+    combinations.push([playerCards[0], playerCards[1], tableCards[0], tableCards[2], tableCards[4]])
+    combinations.push([playerCards[0], playerCards[1], tableCards[0], tableCards[3], tableCards[4]])
+
+    combinations.push([playerCards[0], playerCards[1], tableCards[1], tableCards[2], tableCards[3]])
+    combinations.push([playerCards[0], playerCards[1], tableCards[1], tableCards[2], tableCards[4]])
+    combinations.push([playerCards[0], playerCards[1], tableCards[1], tableCards[3], tableCards[4]])
+
+    combinations.push([playerCards[0], playerCards[1], tableCards[2], tableCards[3], tableCards[4]])
+
+
+    return combinations;
+}
