public int InsertNewCardEditionWithFakeGathererId(int idEdition, int idCard, int idRarity, string url)
        {
            using (new WriterLock(_lock))
            {
                IEdition edition = _editions.FirstOrDefault(e => e.Id == idEdition);
                IRarity  rarity  = _rarities.Values.FirstOrDefault(r => r.Id == idRarity);
                ICard    card    = _cardsbyId.GetOrDefault(idCard);

                if (rarity == null || card == null || edition == null)
                {
                    throw new ApplicationDbException("Data are not filled correctedly");
                }
                if (!edition.IsNoneGatherer())
                {
                    throw new ApplicationDbException("InsertNewCardEditionWithFakeGathererId could only used for NoneGatherer edition");
                }
                int existingIdGatherer = GetIdGatherer(card, edition);
                if (existingIdGatherer != 0)
                {
                    // could have been inserted by another thread
                    return(existingIdGatherer);
                }

                int idGatherer = GetNextFakeGathererId();

                CardEdition cardEdition = new CardEdition
                {
                    IdCard     = idCard,
                    IdGatherer = idGatherer,
                    IdEdition  = idEdition,
                    IdRarity   = idRarity,
                    Url        = url
                };

                AddToDbAndUpdateReferential(cardEdition, InsertInReferential);

                return(idGatherer);
            }
        }
        internal DeckInfo ParseDeckPage(string html)
        {
            string htmltext = WebUtility.HtmlDecode(html);
            Match  m        = _deckNameRegex.Match(htmltext);

            if (!m.Success)
            {
                throw new ParserException("Could not find Title");
            }

            string deckName = m.Groups["name"].Value;

            m = _deckEditionRegex.Match(htmltext);
            if (!m.Success)
            {
                throw new ParserException("Could not find edition");
            }

            if (string.IsNullOrWhiteSpace(deckName))
            {
                return(null);
            }

            IEdition deckEdition = GetEdition(deckName, m);

            if (deckEdition == null)
            {
                throw new ParserException("Could not find edition with name " + deckName);
            }
            if (MagicDatabase.GetPreconstructedDeck(deckEdition.Id, deckName) != null)
            {
                return(null);
            }

            //Split in block
            IList <DeckCardInfo> cards = new List <DeckCardInfo>();

            string[] tokens = htmltext.Split(new string[] { CardSplitter }, StringSplitOptions.RemoveEmptyEntries);

            //Start at 1 because cards start by CardSplitter
            for (int i = 1; i < tokens.Length; i++)
            {
                string[] lines = tokens[i].Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

                if (!int.TryParse(lines[0], out int number))
                {
                    throw new ParserException("Could not find Number");
                }

                foreach (string line in lines)
                {
                    m = _cardInfoRegex.Match(line);
                    if (m.Success)
                    {
                        ICard    card    = GetCard(m);
                        IEdition edition = GetEdition(deckName, m);

                        if (edition == null)
                        {
                            throw new ParserException("Could not find edition for card in " + deckName);
                        }

                        int idGatherer = MagicDatabase.GetIdGatherer(card, edition);
                        if (idGatherer == 0)
                        {
                            //It is not a gatherer edition, we will add the card to it
                            if (edition.IsNoneGatherer() && _getExtraInfo != null)
                            {
                                Tuple <string, IRarity> t = ExtractExtraInfo(m.Groups["url"].Value);
                                cards.Add(new DeckCardInfo(edition.Id, card.Id, number, t.Item2.Id, t.Item1));
                                break;
                            }

                            throw new ParserException(string.Format("Could not find card with idCard {0} and idEdition {1}", card.Id, edition.Id));
                        }
                        else
                        {
                            cards.Add(new DeckCardInfo(idGatherer, number));
                            break;
                        }
                    }
                }
            }

            if (cards.Count == 0)
            {
                return(null);
            }
            DeckInfo deckInfo  = new DeckInfo(deckEdition.Id, deckName, cards);
            int      cardCount = deckInfo.Count;

            //  60 Usual
            //  75 Usual with side board
            //  62 Deckmasters
            //  61 Beatdown
            // 100 Commander
            //  15 or 22 or 26 or 30 or 35 or 40 or 41 Welcome Pack / Portal
            //  80 Archenemy
            //  70 Planechase
            //  20 Jumpstart
            if (cardCount != 60 && cardCount != 75 &&
                cardCount != 62 &&
                cardCount != 61 &&
                cardCount != 100 &&
                cardCount != 15 && cardCount != 22 && cardCount != 26 && cardCount != 30 && cardCount != 35 && cardCount != 40 && cardCount != 41 &&
                cardCount != 80 &&
                cardCount != 70 &&
                cardCount != 20
                )
            {
                throw new ParserException(string.Format("Deck {0} contains {1} cards", deckName, cardCount));
            }

            return(deckInfo);
        }