public void CancelledHand_FullParse()
        {
            HandHistory expectedHand = new HandHistory()
            {
                Cancelled = true,
                GameDescription = new GameDescriptor()
                {
                    PokerFormat = PokerFormat.CashGame,
                    GameType = GameType.PotLimitOmaha,
                    Limit = Limit.FromSmallBlindBigBlind(5m, 10m, Currency.USD),
                    SeatType = SeatType.FromMaxPlayers(6),
                    Site = SiteName.PokerStars,
                    TableType = TableType.FromTableTypeDescriptions(TableTypeDescription.Regular),
                },
                DateOfHandUtc = new DateTime(2014, 1, 16, 12, 17, 20),
                DealerButtonPosition = 6,
                HandId = 110222853693,
                NumPlayersSeated = 1,
                TableName = "Idelsonia III"
            };

            HandHistory actualHand = TestFullHandHistory(expectedHand, "CancelledHand");

            Assert.IsFalse(actualHand.Players["lautie"].hasHoleCards);
            Assert.IsTrue(actualHand.Cancelled);
        }
 public void SetUp()
 {
     _handHistory = new HandHistory()
                        {
                            ComumnityCards =
                                BoardCards.ForFlop(Card.GetCardFromIntValue(5), Card.GetCardFromIntValue(14),
                                                   Card.GetCardFromIntValue(40)),
                            DateOfHandUtc = new DateTime(2012, 3, 20, 12, 30, 44),
                            DealerButtonPosition = 5,
                            FullHandHistoryText = "some hand text",
                            GameDescription =
                                new GameDescriptor(PokerFormat.CashGame,
                                                   SiteName.PartyPoker,
                                                   GameType.NoLimitHoldem,
                                                   Limit.FromSmallBlindBigBlind(10, 20, Currency.USD),
                                                   TableType.FromTableTypeDescriptions(TableTypeDescription.Regular),
                                                   SeatType.FromMaxPlayers(6)),
                            HandActions = new List<HandAction>()
                                              {
                                                  new HandAction("Player1", HandActionType.POSTS, 0.25m, Street.Preflop)
                                              },
                            HandId = 141234124,
                            NumPlayersSeated = 2,
                            Players = new PlayerList()
                                          {
                                              new Player("Player1", 1000, 1),
                                              new Player("Player2", 300, 5),
                                          },
                            TableName = "Test Table",
                        };
 }
        public void PotCalculatorTest_2()
        {
            HandHistory hand = new HandHistory();

            hand.HandActions = new List<HandAction>
            {
                new HandAction("P1", HandActionType.SMALL_BLIND, 0.1m, Objects.Cards.Street.Preflop),
                new HandAction("P2", HandActionType.BIG_BLIND, 0.2m, Objects.Cards.Street.Preflop),
                new HandAction("P1", HandActionType.CALL, 0.1m, Objects.Cards.Street.Preflop),
                new HandAction("P2", HandActionType.CHECK, 0m, Objects.Cards.Street.Preflop),

                new HandAction("P1", HandActionType.CHECK, 0m, Objects.Cards.Street.Flop),
                new HandAction("P2", HandActionType.CHECK, 0m, Objects.Cards.Street.Flop),

                new HandAction("P1", HandActionType.BET, 0.2m, Objects.Cards.Street.Turn),
                new HandAction("P2", HandActionType.CALL, 0.2m, Objects.Cards.Street.Turn),

                new HandAction("P1", HandActionType.CHECK, 0m, Objects.Cards.Street.River),
                new HandAction("P2", HandActionType.CHECK, 0m, Objects.Cards.Street.River),

                new WinningsAction("P1", HandActionType.WINS, 0.8m, 0),
            };

            TestPotCalculator(0.8m, hand);
        }
        public static decimal CalculateRake(HandHistory hand)
        {
            var totalCollected = hand.HandActions
                .Where(p => p.IsWinningsAction)
                .Sum(p => p.Amount);

            return hand.TotalPot.Value - totalCollected;
        }
        public override bool Equals(object obj)
        {
            HandHistory hand = obj as HandHistory;

            if (hand == null)
            {
                return(false);
            }

            return(ToString().Equals(hand.ToString()));
        }
        public static decimal CalculateTotalPot(HandHistory hand)
        {
            var sum = hand.HandActions.Where(p => !p.IsWinningsAction).Sum(a => a.Amount);

            return Math.Abs(sum);

            /*
            var gameActions = hand.HandActions
                .Where(p => p.IsGameAction ||
                    p.IsBlinds ||
                    p.HandActionType == HandActionType.ANTE ||
                    p.HandActionType == HandActionType.POSTS)
                .ToList();

            Dictionary<string, decimal> amounts = new Dictionary<string, decimal>();

            foreach (var action in gameActions)
            {
                if (!amounts.ContainsKey(action.PlayerName))
                {
                    amounts.Add(action.PlayerName, action.Amount);
                }
                else
                {
                    amounts[action.PlayerName] += action.Amount;
                }
            }

            var maxValue = amounts
                .Min(p => p.Value);

            var maxCount = amounts
                .Count(p => p.Value == maxValue);

            var Pot = amounts
                .Sum(p => p.Value);

            if (maxCount == 1)
            {
                var values = amounts
                    .Select(p => p.Value)
                    .OrderBy(p => p)
                    .ToList();

                var uncalledBet = values[0] - values[1];

                Pot -= uncalledBet;
            }

            return Math.Abs(Pot);*/
        }
        public void PotCalculatorTest_CallAllIn()
        {
            HandHistory hand = new HandHistory();

            hand.HandActions = new List<HandAction>
            {
                new HandAction("P1", HandActionType.SMALL_BLIND, 1m, Street.Preflop),
                new HandAction("P2", HandActionType.BIG_BLIND, 2m, Street.Preflop),
                new HandAction("P1", HandActionType.RAISE, 10m, Street.Preflop),
                new HandAction("P2", HandActionType.RAISE, 60m, Street.Preflop, true),
                new HandAction("P1", HandActionType.CALL, 29m, Street.Preflop, true),
                new HandAction("P2", HandActionType.UNCALLED_BET, 22, Street.Preflop),

                new WinningsAction("P2", HandActionType.WINS, 80m, 0),
            };

            TestPotCalculator(80m, hand);
        }
        public void PotCalculatorTest_1()
        {
            HandHistory hand = new HandHistory();

            hand.HandActions = new List<HandAction>
            {
                new HandAction("P1", HandActionType.SMALL_BLIND, 0.1m, Objects.Cards.Street.Preflop),
                new HandAction("P2", HandActionType.BIG_BLIND, 0.2m, Objects.Cards.Street.Preflop),
                new HandAction("P1", HandActionType.CALL, 0.1m, Objects.Cards.Street.Preflop),
                new HandAction("P2", HandActionType.CHECK, 0m, Objects.Cards.Street.Preflop),

                new HandAction("P1", HandActionType.CHECK, 0m, Objects.Cards.Street.Flop),
                new HandAction("P2", HandActionType.BET, 0.1m, Objects.Cards.Street.Flop),
                new HandAction("P1", HandActionType.FOLD, 0m, Objects.Cards.Street.Flop),
                new HandAction("P2", HandActionType.UNCALLED_BET, 0.1m, Objects.Cards.Street.Flop),
            };

            TestPotCalculator(0.4m, hand);
        }
 public string CompressHandHistory(HandHistory parsedHandHistory)
 {
     return CompressHandHistory(parsedHandHistory.FullHandHistoryText);
 }
        public void MucksHand()
        {
            HandHistory expectedHand = new HandHistory()
            {
                GameDescription = new GameDescriptor()
                {
                    PokerFormat = PokerFormat.CashGame,
                    GameType = GameType.PotLimitOmahaHiLo,
                    Limit = Limit.FromSmallBlindBigBlind(0.05m, 0.10m, Currency.USD),
                    SeatType = SeatType.FromMaxPlayers(6),
                    Site = SiteName.PokerStars,
                    TableType = TableType.FromTableTypeDescriptions(TableTypeDescription.Regular)
                },
                DateOfHandUtc = new DateTime(2012, 9, 11, 7, 51, 48),
                DealerButtonPosition = 4,
                HandId = 86008517721,
                NumPlayersSeated = 6,
                TableName = "Muscida V 40-100 bb"
            };

            HandHistory actualHand = TestFullHandHistory(expectedHand, "MucksHand");
        }
        private HandHistory TestFullHandHistory(HandHistory expectedHand, string fileName)
        {
            string handText = SampleHandHistoryRepository.GetHandExample(PokerFormat.CashGame, Site, "ExtraHands", fileName);

            HandHistory actualHand = GetParser().ParseFullHandHistory(handText, true);

            Assert.AreEqual(expectedHand.GameDescription, actualHand.GameDescription);
            Assert.AreEqual(expectedHand.DealerButtonPosition, actualHand.DealerButtonPosition);
            Assert.AreEqual(expectedHand.DateOfHandUtc, actualHand.DateOfHandUtc);
            Assert.AreEqual(expectedHand.HandId, actualHand.HandId);
            Assert.AreEqual(expectedHand.NumPlayersSeated, actualHand.NumPlayersSeated);
            Assert.AreEqual(expectedHand.TableName, actualHand.TableName);

            return actualHand;
        }
        public void ShowsDownSingleCard()
        {
            HandHistory expectedHand = new HandHistory()
            {
                GameDescription = new GameDescriptor()
                {
                    PokerFormat = PokerFormat.CashGame,
                    GameType = GameType.FixedLimitHoldem,
                    Limit = Limit.FromSmallBlindBigBlind(1m, 2m, Currency.USD),
                    SeatType = SeatType.FromMaxPlayers(6),
                    Site = SiteName.PokerStars,
                    TableType = TableType.FromTableTypeDescriptions(TableTypeDescription.Regular)
                },
                DateOfHandUtc = new DateTime(2012, 9, 11, 4, 15, 11),
                DealerButtonPosition = 1,
                HandId = 86005187865,
                NumPlayersSeated = 6,
                TableName = "Stavropolis III 40-100 bb"
            };

            HandHistory actualHand = TestFullHandHistory(expectedHand, "ShowsDownSingleCard");

            Assert.AreEqual(string.Empty, actualHand.Players["Zaza5573"].HoleCards.ToString());
        }
        public void PlayerNameWithSlashesAndSquareBrackets()
        {
            HandHistory expectedHand = new HandHistory()
            {
                GameDescription = new GameDescriptor()
                {
                    PokerFormat = PokerFormat.CashGame,
                    GameType = GameType.CapNoLimitHoldem,
                    Limit = Limit.FromSmallBlindBigBlind(0.25m, 0.50m, Currency.USD),
                    SeatType = SeatType.FromMaxPlayers(6),
                    Site = SiteName.PokerStars,
                    TableType = TableType.FromTableTypeDescriptions(TableTypeDescription.Regular)
                },
                DateOfHandUtc = new DateTime(2012, 9, 11, 12, 39, 12),
                DealerButtonPosition = 3,
                HandId = 86015904171,
                NumPlayersSeated = 4,
                TableName = "Acamar IV CAP, Fast,20-50 bb"
            };

            var expectedActions = new List<HandAction>()
                {
                    new HandAction("vitinja", HandActionType.SMALL_BLIND, 0.25m, Street.Preflop),
                    new HandAction("/\\ntiHer[]", HandActionType.BIG_BLIND, 0.50m, Street.Preflop),
                    new HandAction("Catharina111", HandActionType.CALL, 0.50m, Street.Preflop),
                    new HandAction("Willo2319", HandActionType.CALL, 0.50m, Street.Preflop),
                    new HandAction("vitinja", HandActionType.FOLD, 0m, Street.Preflop),
                    new HandAction("/\\ntiHer[]", HandActionType.CHECK, 0, Street.Preflop),
                     new HandAction("/\\ntiHer[]", HandActionType.BET, 1, Street.Flop),
                    new HandAction("Catharina111", HandActionType.FOLD, 0m, Street.Flop),
                    new HandAction("Willo2319", HandActionType.CALL, 1m, Street.Flop),
                    new HandAction("/\\ntiHer[]", HandActionType.BET, 1.50m, Street.Turn),
                    new HandAction("Willo2319", HandActionType.CALL, 1.50m, Street.Turn),
                    new HandAction("/\\ntiHer[]", HandActionType.CHECK, 0m, Street.River),
                    new HandAction("Willo2319", HandActionType.CHECK, 0m, Street.River),
                    new HandAction("/\\ntiHer[]", HandActionType.SHOW, 0m, Street.Showdown),
                     new HandAction("Willo2319", HandActionType.SHOW, 0m, Street.Showdown),
                    new WinningsAction("Willo2319", HandActionType.WINS, 6.45m, 0),
                };

            HandHistory actualHand = TestFullHandHistory(expectedHand, "PlayerNameWithSlashesAndSquareBrackets");

            Assert.AreEqual(expectedActions, actualHand.HandActions);
        }
 void TestPotCalculator(decimal ExpectedPot, HandHistory hand)
 {
     var calculatedPot = PotCalculator.CalculateTotalPot(hand);
     Assert.AreEqual(ExpectedPot, calculatedPot);
 }
        public HandHistory ParseFullHandHistory(string handText, bool rethrowExceptions = false)
        {
            try
            {
                string[] lines = SplitHandsLines(handText);

                if (IsValidHand(lines) == false)
                {
                    throw new InvalidHandException(handText ?? "NULL");
                }

                string[] handLines = SplitHandsLines(handText);

                HandHistory handHistory = new HandHistory
                        {
                            DateOfHandUtc = ParseDateUtc(handLines),
                            GameDescription = ParseGameDescriptor(handLines),
                            HandId = ParseHandId(handLines),
                            TableName = ParseTableName(handLines),
                            DealerButtonPosition = ParseDealerPosition(handLines),
                            FullHandHistoryText = string.Join("\r\n", handLines),
                            ComumnityCards = ParseCommunityCards(handLines),
                        };

                handHistory.Players = ParsePlayers(handLines);
                handHistory.NumPlayersSeated = handHistory.Players.Count;

                if (handHistory.Players.Count(p => p.IsSittingOut == false) <= 1)
                {
                    throw new PlayersException(handText, "Only found " + handHistory.Players.Count + " players with actions.");
                }

                handHistory.HandActions = ParseHandActions(handLines, handHistory.GameDescription.GameType);

                if (RequiresActionSorting)
                {
                    handHistory.HandActions = OrderHandActions(handHistory.HandActions);
                }
                if (RequresAdjustedRaiseSizes)
                {
                   handHistory.HandActions = AdjustRaiseSizes(handHistory.HandActions);
                }
                if (RequiresAllInDetection)
                {
                    handHistory.HandActions = IdentifyAllInActions(handLines, handHistory.HandActions);
                }

                HandAction anteAction = handHistory.HandActions.FirstOrDefault(a => a.HandActionType == HandActionType.ANTE);
                if (anteAction != null)
                {
                    handHistory.GameDescription.Limit.IsAnteTable = true;
                    handHistory.GameDescription.Limit.Ante = Math.Abs(anteAction.Amount);
                }

                try
                {
                    ParseExtraHandInformation(handLines, handHistory);
                }
                catch (Exception)
                {
                    throw new ExtraHandParsingAction(handLines[0]);
                }

                return handHistory;
            }
            catch (Exception ex)
            {
                if (rethrowExceptions)
                {
                    throw;
                }

                logger.Warn("Couldn't parse hand {0} with error {1}", handText, ex.Message);
                return null;
            }
        }
        public void GetStreetActions_Turn()
        {
            var hand = new HandHistory()
            {
                HandActions = TestCase1
            };

            List<HandAction> ExpectedActions = new List<HandAction>()
            {
                new HandAction("Bluf_To_Much", HandActionType.CHECK, 0m, Street.Turn),
                new HandAction("joiso", HandActionType.BET, 600m, Street.Turn),
                new HandAction("LewisFriend", HandActionType.CALL, 600m, Street.Turn),
                new HandAction("Bluf_To_Much", HandActionType.CALL, 600m, Street.Turn)
            };

            AssertStreetActions(ExpectedActions, TestCase1.Street(Street.Turn).ToList());
        }
        protected override List<HandAction> ParseHandActions(string[] handLines, GameType gameType = GameType.Unknown)
        {
            // this is needed for future uncalledbet fixes
            var handHistory = new HandHistory();
            ParseExtraHandInformation(handLines, handHistory);

            int startOfActionsIndex = -1;
            for (int i = 6; i < handLines.Length; i++)
            {
                string handLine = handLines[i];

                if (handLine.StartsWith("Seat ") == false)
                {
                    startOfActionsIndex = i;
                    break;
                }
            }

            if (startOfActionsIndex == -1)
            {
                throw new HandActionException(handLines[0], "Couldnt find the start of the actions");
            }

            List<HandAction> handActions = new List<HandAction>();
            Street currentStreet = Street.Preflop;

            for (int i = startOfActionsIndex; i < handLines.Length; i++)
            {
                string handLine = handLines[i];

                if (handLine.StartsWith("Seat ")) // done with actions once we reach the seat line again
                {
                    break;
                }

                bool isAllIn = handLine.EndsWith("all in]");
                if (isAllIn)
                {
                    handLine = handLine.Substring(0, handLine.Length - 9);
                }

                if (handLine[0] == '-')
                {
                    if (handLine == "---")
                    {
                        continue;
                    }

                    // check for a line such as:
                    //  --- Dealing flop [3d, 8h, 6d]
                    // note: We can have players with - so hence the digit check to check for lines like
                    //   ---ich--- raises $21.42 to $22.92 [all in]
                    if (handLine[handLine.Length - 1] == ']' &&
                        char.IsDigit(handLine[handLine.Length - 2]) == false)
                    {
                        char streetIdentifierChar = handLine[12];
                        switch (streetIdentifierChar)
                        {
                            case 'f':
                                currentStreet = Street.Flop;
                                continue;
                            case 't':
                                currentStreet = Street.Turn;
                                continue;
                            case 'r':
                                currentStreet = Street.River;
                                continue;
                        }
                    }
                }

                //Dealing line may be "Dealing pocket cards"
                //or "Dealing to {PlayerName}: [ Xy, Xy ]"
                if (currentStreet == Street.Preflop &&
                    handLine.StartsWith("Dealing"))
                {
                    continue;
                }

                if (handLine[handLine.Length - 1] == ':') // check for Summary: line
                {
                    currentStreet = Street.Showdown;
                }

                if (currentStreet == Street.Showdown)
                {
                    // Main pot: $2.25 won by zatli74 ($2.14)
                    // Main pot: $710.00 won by alikator21 ($354.50), McCall901 ($354.50)
                    if (handLine.StartsWith("Main pot:"))
                    {
                        var nameStart = handLine.IndexOf(" won by", StringComparison.Ordinal) + 7;
                        var splitted = handLine.Substring(nameStart).Split(',');
                        foreach (var winner in splitted)
                        {
                            int openParenIndex = winner.LastIndexOf('(');
                            decimal amount = decimal.Parse(winner.Substring(openParenIndex + 1, winner.Length - openParenIndex - 2), NumberStyles.AllowCurrencySymbol | NumberStyles.Number, _numberFormatInfo);

                            string playerName = winner.Substring(1, openParenIndex - 2);

                            handActions.Add(new WinningsAction(playerName, HandActionType.WINS, amount, 0));
                        }
                    }
                    // Side pot 1: $12.26 won by iplaymybest ($11.65)
                    // Side pot 2: $11.10 won by zatli74 ($5.20), Hurtl ($5.20)
                    if (handLine.StartsWith("Side pot "))
                    {
                        var nameStart = handLine.IndexOf(" won by", StringComparison.Ordinal) + 7;
                        var splitted = handLine.Substring(nameStart).Split(',');

                        var potNumber = Int32.Parse(handLine[9].ToString());
                        foreach (var winner in splitted)
                        {
                            int openParenIndex = winner.LastIndexOf('(');
                            decimal amount = decimal.Parse(winner.Substring(openParenIndex + 1, winner.Length - openParenIndex - 2), NumberStyles.AllowCurrencySymbol | NumberStyles.Number, _numberFormatInfo);

                            string playerName = winner.Substring(1, openParenIndex - 2);

                            handActions.Add(new WinningsAction(playerName, HandActionType.WINS_SIDE_POT, amount, potNumber));
                        }

                    }

                    continue;
                }

                if (handLine[handLine.Length - 1] == ')' && currentStreet != Street.Showdown)
                {
                    // small-blind & big-blind lines ex:
                    //  GlassILass posts small blind ($0.25)
                    //  EvilJihnny99 posts big blind ($0.25)
                    //  19kb72 posts big blind ($6.50) [all in]

                    int openParenIndex = handLine.LastIndexOf('(');
                    decimal amount = decimal.Parse(handLine.Substring(openParenIndex + 1, handLine.Length - openParenIndex - 2), NumberStyles.AllowCurrencySymbol | NumberStyles.Number, _numberFormatInfo);

                    char blindIdentifier = handLine[openParenIndex - 10];
                    if (blindIdentifier == 'b') // big blind
                    {
                        string playerName = handLine.Substring(0, openParenIndex - 17);
                        handActions.Add(new HandAction(playerName, HandActionType.BIG_BLIND, amount, Street.Preflop));
                        continue;
                    }
                    else if (blindIdentifier == 'a')  // small-blind
                    {
                        string playerName = handLine.Substring(0, openParenIndex - 19);
                        handActions.Add(new HandAction(playerName, HandActionType.SMALL_BLIND, amount, Street.Preflop));
                        continue;
                    }
                    else if (blindIdentifier == 'e') // posts - dead
                    {
                        string playerName = handLine.Substring(0, openParenIndex - 18);
                        handActions.Add(new HandAction(playerName, HandActionType.POSTS, amount, Street.Preflop));
                        continue;
                    }

                    throw new HandActionException(handLine, "Unknown hand-line: " + handLine);
                }

                // Check for folds & checks
                if (handLine[handLine.Length - 1] == 's')
                {
                    if (handLine[handLine.Length - 2] == 'd') // folds
                    {
                        string playerName = handLine.Substring(0, handLine.Length - 6);
                        handActions.Add(new HandAction(playerName, HandActionType.FOLD, 0, currentStreet));
                    }
                    else if (handLine[handLine.Length - 2] == 'k') // checks
                    {
                        string playerName = handLine.Substring(0, handLine.Length - 7);
                        handActions.Add(new HandAction(playerName, HandActionType.CHECK, 0, currentStreet));
                    }
                    continue;
                }
                else
                {
                    //Old format
                    //{playername} calls $18.00

                    //New format
                    //{playername} calls $13

                    int currencyIndex = handLine.IndexOf(_numberFormatInfo.CurrencySymbol, StringComparison.Ordinal);

                    int valueEndIndex = handLine.IndexOf(' ', currencyIndex);
                    if (valueEndIndex == -1)
                    {
                        valueEndIndex = handLine.Length;
                    }

                    char actionIdentifier = handLine[currencyIndex - 3];

                    var amountstr = handLine.Substring(currencyIndex, valueEndIndex - currencyIndex);
                    string playerName;
                    decimal amount = decimal.Parse(amountstr, NumberStyles.AllowCurrencySymbol | NumberStyles.Number, _numberFormatInfo);
                    switch (actionIdentifier)
                    {
                        case 'l': // calls
                            playerName = handLine.Substring(0, currencyIndex - 7);
                            if (isAllIn)
                            {
                                handActions.Add(new AllInAction(playerName, amount, currentStreet, false));
                            }
                            else
                            {
                                handActions.Add(new HandAction(playerName, HandActionType.CALL, amount, currentStreet));
                            }
                            break;
                        case 'e': // raises
                            // ex: zatli74 raises $1.00 to $1.00
                            playerName = handLine.Substring(0, currencyIndex - 8);
                            if (isAllIn)
                            {
                                handActions.Add(new AllInAction(playerName, amount, currentStreet, true));
                            }
                            else
                            {
                                handActions.Add(new HandAction(playerName, HandActionType.RAISE, amount, currentStreet));
                            }
                            break;
                        case 't': // bets
                            playerName = handLine.Substring(0, currencyIndex - 6);
                            if (isAllIn)
                            {
                                handActions.Add(new AllInAction(playerName, amount, currentStreet, false));
                            }
                            else
                            {
                                handActions.Add(new HandAction(playerName, HandActionType.BET, amount, currentStreet));
                            }
                            break;
                    }
                    continue;
                }

                throw new HandActionException(handLine, "Unknown hand-line: " + handLine);
            }

            return FixUncalledBets(handActions, handHistory.TotalPot, handHistory.Rake);
        }
        protected override List<HandAction> ParseHandActions(string[] handLines, GameType gameType = GameType.Unknown)
        {
            // this is needed for future uncalledbet fixes
            var handHistory = new HandHistory();
            ParseExtraHandInformation(handLines, handHistory);

            var actions = new List<HandAction>(handLines.Length);
            // TODO: implement
            int startIndex = FindHandActionsStart(handLines);

            startIndex = ParseBlindActions(handLines, ref actions, startIndex);

            Street currentStreet = Street.Preflop;

            for (int i = startIndex; i < handLines.Length; i++)
            {
                var line = handLines[i];

                if (IsChatLine(line))
                {
                    continue;
                }

                if (IsUncalledBetLine(line))
                {
                    actions.Add(ParseUncalledBet(line, currentStreet));
                    ParseShowDown(handLines, ref actions, i + 1, gameType);
                    return FixUncalledBets(actions, handHistory.TotalPot, handHistory.Rake);
                }

                if (line.Contains(" shows ["))
                {
                    ParseShowDown(handLines, ref actions, i, GameType.Unknown);

                    return FixUncalledBets(actions, handHistory.TotalPot, handHistory.Rake);
                }

                var lastChar = line[line.Length - 1];

                HandAction action;

                switch (lastChar)
                {
                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                        action = ParseActionWithAmount(line, currentStreet);
                        if (action != null)
                        {
                            actions.Add(action);
                        }
                        continue;

                    //theking881 calls $138, and is all in
                    //draggstar sits down
                    case 'n':
                        if (line.FastEndsWith("and is all in"))
                        {
                            action = ParseActionWithAmount(line.Remove(line.Length - 15), currentStreet, true);//", and is all in".Length
                            if (action != null)
                            {
                                actions.Add(action);
                            }
                        }
                        continue;

                    case ')':
                        action = ParseWinActionOrStreet(line, ref currentStreet);
                        if (action != null)
                        {
                            actions.Add(action);
                        }
                        break;

                    //jobetzu checks
                    //jobetzu folds
                    //theking881 mucks
                    case 's':
                        action = ParseFoldCheckLine(line, currentStreet);
                        if (action != null)
                        {
                            actions.Add(action);
                        }
                        continue;

                    // 02nina20 calls $0.04, and is capped
                    case 'd':
                        if (line[line.Length - 3] == 'p')
                        {
                            action = ParseActionWithAmount(line.Remove(line.LastIndexOf(',')), currentStreet);
                            if (action != null)
                            {
                                actions.Add(action);
                            }
                        }
                        continue;

                    //*** SHOW DOWN ***
                    //*** SUMMARY ***
                    case '*':
                        ParseShowDown(handLines, ref actions, i, GameType.Unknown);

                        return FixUncalledBets(actions, handHistory.TotalPot, handHistory.Rake);

                    //Dealt to FT_Hero [Qh 5c]
                    //Postrail shows [Qs Ah]
                    case ']':
                        if (line.IndexOf(" shows [", StringComparison.Ordinal) != -1)
                        {
                            ParseShowDown(handLines, ref actions, i, GameType.Unknown);
                            return FixUncalledBets(actions, handHistory.TotalPot, handHistory.Rake);
                        }
                        continue;

                    //Opponent3 has requested TIME
                    //jobetzu has 15 seconds left to act
                    default:
                        continue;
                }
            }

            return FixUncalledBets(actions, handHistory.TotalPot, handHistory.Rake);
        }
 public string CompressHandHistory(HandHistory parsedHandHistory)
 {
     throw new NotImplementedException();
 }
        public HandHistory ParseFullHandHistory(string handText, bool rethrowExceptions = false)
        {
            try
            {
                if (IsValidHand(handText) == false)
                {
                    throw new InvalidHandException(handText ?? "NULL");
                }

                HandHistorySummary handHistorySummary = ParseFullHandSummary(handText, rethrowExceptions);

                HandHistory handHistory = new HandHistory()
                                              {
                                                  DateOfHandUtc = handHistorySummary.DateOfHandUtc,
                                                  GameDescription = handHistorySummary.GameDescription,
                                                  HandId = handHistorySummary.HandId,
                                                  TableName = handHistorySummary.TableName,
                                                  NumPlayersSeated = handHistorySummary.NumPlayersSeated,
                                                  DealerButtonPosition = handHistorySummary.DealerButtonPosition
                                              };

                handHistory.FullHandHistoryText = handText.Replace("\r", "").Replace("\n", "\r\n");

                handHistory.ComumnityCards = ParseCommunityCards(handText);

                List<HandAction> handActions;
                handHistory.Players = ParsePlayers(handText, out handActions);
                handHistory.HandActions = handActions;

                handHistory.Players = SetSittingOutPlayers(handHistory.Players, handHistory.HandActions);

                if (handHistory.Players.Count <= 1)
                {
                    throw new PlayersException(handText, "Only found " + handHistory.Players.Count + " players with actions.");
                }

                return handHistory;
            }
            catch (Exception ex)
            {
                if (rethrowExceptions)
                {
                    throw;
                }

                logger.Warn("Couldn't parse hand {0} with error {1}", handText, ex.Message);
                return null;
            }
        }
        public HandHistory ParseFullHandHistory(string[] handLines, bool rethrowExceptions = false)
        {
            try
            {
                bool isCancelled;
                if (IsValidOrCancelledHand(handLines, out isCancelled) == false)
                {
                    throw new InvalidHandException(string.Join("\r\n", handLines));
                }

                //Set members outside of the constructor for easier performance analysis
                HandHistory handHistory = new HandHistory();

                handHistory.FullHandHistoryText = string.Join("\r\n", handLines);
                handHistory.DateOfHandUtc = ParseDateUtc(handLines);
                handHistory.GameDescription = ParseGameDescriptor(handLines);
                handHistory.HandId = ParseHandId(handLines);
                handHistory.TableName = ParseTableName(handLines);
                handHistory.DealerButtonPosition = ParseDealerPosition(handLines);
                handHistory.ComumnityCards = ParseCommunityCards(handLines);
                handHistory.Cancelled = isCancelled;
                handHistory.Players = ParsePlayers(handLines);
                handHistory.NumPlayersSeated = handHistory.Players.Count;

                string heroName = ParseHeroName(handLines);
                handHistory.Hero = handHistory.Players.FirstOrDefault(p => p.PlayerName == heroName);

                if (handHistory.Cancelled)
                {
                    return handHistory;
                }

                if (handHistory.Players.Count(p => p.IsSittingOut == false) <= 1)
                {
                    throw new PlayersException(string.Join("\r\n", handLines), "Only found " + handHistory.Players.Count + " players with actions.");
                }

                if (SupportRunItTwice)
                {
                    handHistory.RunItTwiceData = ParseRunItTwice(handLines);
                }

                handHistory.HandActions = ParseHandActions(handLines, handHistory.GameDescription.GameType);

                if (RequiresActionSorting)
                {
                    handHistory.HandActions = OrderHandActions(handHistory.HandActions);
                }
                if (RequiresAdjustedRaiseSizes)
                {
                   handHistory.HandActions = AdjustRaiseSizes(handHistory.HandActions);
                }
                if (RequiresAllInDetection)
                {
                    handHistory.HandActions = IdentifyAllInActions(handLines, handHistory.HandActions);
                }
                if (RequiresTotalPotCalculation)
                {
                    handHistory.TotalPot = PotCalculator.CalculateTotalPot(handHistory);
                    handHistory.Rake = PotCalculator.CalculateRake(handHistory);
                }

                HandAction anteAction = handHistory.HandActions.FirstOrDefault(a => a.HandActionType == HandActionType.ANTE);
                if (anteAction != null && handHistory.GameDescription.PokerFormat.Equals(PokerFormat.CashGame))
                {
                    handHistory.GameDescription.Limit.IsAnteTable = true;
                    handHistory.GameDescription.Limit.Ante = Math.Abs(anteAction.Amount);
                }

                try
                {
                    ParseExtraHandInformation(handLines, handHistory);
                }
                catch (Exception)
                {
                    throw new ExtraHandParsingAction(handLines[0]);
                }

                return handHistory;
            }
            catch (Exception ex)
            {
                if (rethrowExceptions)
                {
                    throw;
                }

                logger.Warn("Couldn't parse hand {0} with error {1} and trace {2}", string.Join("\r\n", handLines), ex.Message, ex.StackTrace);
                return null;
            }
        }