Example #1
0
        /// <summary>
        /// Imports and processes the input CSV file, i.e. fills the internal MetaCard hash tables and fetches product info from MKM if necessary.
        /// Intended to run in a separate thread.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        private void importRun(string filePath, string defaultFoil, string defaultPlayset, string defaultSigned, string defaultAltered,
                               string defaultCondition, string defaultExpansion, string defaultLanguageID)
        {
            DataTable dt;

            try
            {
                dt = MKMCsvUtils.ConvertCSVtoDataTable(filePath);
            }
            catch (Exception eError)
            {
                LogError("importing file " + filePath, eError.Message, true);
                return;
            }
            importedColumns = dt.Columns;
            MainView.Instance.LogMainWindow("Loaded file with " + dt.Rows.Count + " articles, processing...");

            importedAll.Clear();
            importedValidOnly.Clear();
            int counter = 0, failed = 0, hasPriceGuide = 0;
            // if we search for products based on their locName, we have to make a product query for each of them - store the result to reuse in case there are more of those cards later in the list
            Dictionary <string, string> locNameProducts = new Dictionary <string, string>();

            foreach (DataRow row in dt.Rows)
            {
                MKMMetaCard mc = new MKMMetaCard(row);
                importedAll.Add(mc); // add it no matter if it can be correctly processed or not so that we can export it
                counter++;
                string productID  = mc.GetAttribute(MCAttribute.ProductID);
                string name       = mc.GetAttribute(MCAttribute.Name);
                string languageID = mc.GetAttribute(MCAttribute.LanguageID);
                if (languageID == "" && defaultLanguageID != "")
                {
                    languageID = defaultLanguageID;
                    mc.SetLanguageID(languageID);
                }
                if (name == "" && productID == "") // we have neither name or productID - we have to hope we have locName and language
                {
                    string locName = mc.GetAttribute(MCAttribute.LocName).ToLower();
                    if (locName == "" || languageID == "")
                    {
                        LogError("importing line #" + (counter + 1) + ", article will be ignored",
                                 "Neither product ID, English name, or localized name + language was found, cannot identify the card.", false);
                        failed++;
                        continue;
                    }
                    // have to use search on MKM to get the English name
                    string hash = "" + locName + languageID;          // technically it is unlikely that two different languages would have the same name, but could happen
                    if (!locNameProducts.TryGetValue(hash, out name)) // we haven't had a product like this in the list yet, use MKM API to find it
                    {
                        int            start = 0;
                        List <XmlNode> found = new List <XmlNode>();
                        try
                        {
                            XmlNodeList products;
                            do
                            {
                                XmlDocument doc = MKMInteract.RequestHelper.findProducts(locName, languageID, start);
                                products = doc.GetElementsByTagName("product");
                                // we still want to insert empty string in the hash table - this way we know in the future that this name is invalid
                                locNameProducts[hash] = "";
                                foreach (XmlNode product in products)
                                {
                                    // only take exact matches, otherwise we get all kinds of garbage like sleeves etc. that use the name of the card
                                    if (product["locName"].InnerText.ToLower() == locName)
                                    {
                                        found.Add(product);
                                    }
                                }
                                start += products.Count;
                            } while (products.Count == 100);
                        }
                        catch (Exception eError)
                        {
                            LogError("importing line #" + (counter + 1) + ", trying to find product by its localized name "
                                     + locName + ", article will be ignored", eError.Message, false);
                            failed++;
                            continue;
                        }
                        if (found.Count < 1)
                        {
                            LogError("importing line #" + (counter + 1) + ", trying to find product by its localized name "
                                     + locName + ", article will be ignored", "No article called " + locName + " in "
                                     + mc.GetAttribute(MCAttribute.Language) + " language found on MKM.", false);
                            failed++;
                            continue;
                        }
                        locNameProducts[hash] = name = found[0]["enName"].InnerText;
                        mc.SetAttribute(MCAttribute.Name, name);
                    }
                    else if (name != "")
                    {
                        mc.SetAttribute(MCAttribute.Name, name);
                    }
                    else
                    {
                        LogError("importing line #" + (counter + 1) + ", trying to find product by its localized name "
                                 + locName + ", article will be ignored", "" + locName + " is not a valid name", false);
                        failed++;
                        continue;
                    }
                }
                // process foil and condition now as it can be useful in determining expansion
                string temp = mc.GetAttribute(MCAttribute.Foil);
                Bool3  isFoil;
                if (temp == "")
                {
                    mc.SetBoolAttribute(MCAttribute.Foil, defaultFoil);
                    isFoil = ParseBool3(mc.GetAttribute(MCAttribute.Foil));
                }
                else
                {
                    isFoil = ParseBool3(temp);
                }

                string condition = mc.GetAttribute(MCAttribute.Condition);
                if (condition == "")
                {
                    condition = defaultCondition;
                    mc.SetCondition(condition);
                }

                if (productID == "")                                         // we now know we have the name, but we have to find out which expansion it is from to get the productID
                {
                    string expID = mc.GetAttribute(MCAttribute.ExpansionID); // if the Expansion would be set, ExpansionID would be set as well in constructor of MKMMetaCard
                    if (expID == "")                                         // we have to determine the expansion
                    {
                        var all = MKMDbManager.Instance.GetCardByName(name);
                        // options are: Latest, Oldest, Cheapest, Median Price, Most Expensive
                        if (all.GetEnumerator().MoveNext())
                        {
                            // used for prices based on price guide (cheapest, median, most expensive):
                            // for non-foil, compare the LOWEX+ for EX+ items, LOW for worse conditions, for foil compare the LOWFOIL, for "any foil" compare SELL
                            string priceGuidePrice;
                            if (isFoil == Bool3.True)
                            {
                                priceGuidePrice = "LOWFOIL";
                            }
                            else if (isFoil == Bool3.Any)
                            {
                                priceGuidePrice = "SELL";
                            }
                            else
                            {
                                if (IsBetterOrSameCondition(condition, "EX"))
                                {
                                    priceGuidePrice = "LOWEX+";
                                }
                                else
                                {
                                    priceGuidePrice = "LOW";
                                }
                            }
                            switch (defaultExpansion)
                            {
                            // for latest and oldest, we can just check local database
                            case "Latest":
                                DateTime latestTime = new DateTime(0);
                                foreach (DataRow dr in all)
                                {
                                    string tempExpID   = dr[MKMDbManager.InventoryFields.ExpansionID].ToString();
                                    string releaseDate = MKMDbManager.Instance.GetExpansionByID(
                                        tempExpID)[MKMDbManager.ExpansionsFields.ReleaseDate].ToString();
                                    DateTime rel = DateTime.Parse(releaseDate, CultureInfo.InvariantCulture);
                                    if (latestTime < rel)
                                    {
                                        latestTime = rel;
                                        expID      = tempExpID;
                                    }
                                }
                                mc.SetAttribute(MCAttribute.ExpansionID, expID);
                                mc.SetAttribute(MCAttribute.Expansion,
                                                MKMDbManager.Instance.GetExpansionByID(expID)[MKMDbManager.ExpansionsFields.Name].ToString());
                                break;

                            case "Oldest":
                                DateTime oldestTime = DateTime.Now;
                                foreach (DataRow dr in all)
                                {
                                    string tempExpID   = dr[MKMDbManager.InventoryFields.ExpansionID].ToString();
                                    string releaseDate = MKMDbManager.Instance.GetExpansionByID(
                                        tempExpID)[MKMDbManager.ExpansionsFields.ReleaseDate].ToString();
                                    DateTime rel = DateTime.Parse(releaseDate, CultureInfo.InvariantCulture);
                                    if (oldestTime > rel)
                                    {
                                        latestTime = rel;
                                        expID      = tempExpID;
                                    }
                                }
                                mc.SetAttribute(MCAttribute.ExpansionID, expID);
                                mc.SetAttribute(MCAttribute.Expansion,
                                                MKMDbManager.Instance.GetExpansionByID(expID)[MKMDbManager.ExpansionsFields.Name].ToString());
                                break;

                            // for the others we have to do product queries for each possibility
                            case "Cheapest":
                                XmlNode cheapestProduct = null;     // we know all has at least one item so this will either get assigned or an exception is thrown and caught inside the foreach cycle
                                double  cheapestPrice   = double.MaxValue;
                                foreach (DataRow dr in all)
                                {
                                    try
                                    {
                                        // there should always be exactly one product in the list
                                        XmlNode product = MKMInteract.RequestHelper.getProduct(
                                            dr[MKMDbManager.InventoryFields.ProductID].ToString()).GetElementsByTagName("product")[0];
                                        double price = double.Parse(product["priceGuide"][priceGuidePrice].InnerText);
                                        if (price < cheapestPrice)
                                        {
                                            cheapestPrice   = price;
                                            cheapestProduct = product;
                                        }
                                    }
                                    catch (Exception eError)
                                    {
                                        LogError("importing line #" + (counter + 1) + ", could not identify cheapest expansion for " + name + ", article will be ignored",
                                                 eError.Message, false);
                                        failed++;
                                        continue;
                                    }
                                }
                                mc.FillProductInfo(cheapestProduct);
                                hasPriceGuide++;
                                break;

                            case "Median Price":
                                SortedList <double, XmlNode> prices = new SortedList <double, XmlNode>();
                                foreach (DataRow dr in all)
                                {
                                    try
                                    {
                                        // there should always be exactly one product in the list
                                        XmlNode product = MKMInteract.RequestHelper.getProduct(
                                            dr[MKMDbManager.InventoryFields.ProductID].ToString()).GetElementsByTagName("product")[0];
                                        double price = double.Parse(product["priceGuide"][priceGuidePrice].InnerText);
                                        prices.Add(price, product);
                                    }
                                    catch (Exception eError)
                                    {
                                        LogError("importing line #" + (counter + 1) + ", could not identify median price expansion for " + name + ", article will be ignored",
                                                 eError.Message, false);
                                        failed++;
                                        continue;
                                    }
                                }
                                mc.FillProductInfo(prices.Values[prices.Count / 2]);
                                hasPriceGuide++;
                                break;

                            case "Most Expensive":
                                XmlNode mostExpProduct = null;     // we know all has at least one item so this will either get assigned or an exception is thrown and caught inside the foreach cycle
                                double  highestPrice   = double.MinValue;
                                foreach (DataRow dr in all)
                                {
                                    try
                                    {
                                        // there should always be exactly one product in the list
                                        XmlNode product = MKMInteract.RequestHelper.getProduct(
                                            dr[MKMDbManager.InventoryFields.ProductID].ToString()).GetElementsByTagName("product")[0];
                                        double price = double.Parse(product["priceGuide"][priceGuidePrice].InnerText);
                                        if (price > highestPrice)
                                        {
                                            highestPrice   = price;
                                            mostExpProduct = product;
                                        }
                                    }
                                    catch (Exception eError)
                                    {
                                        LogError("importing line #" + (counter + 1) + ", could not identify cheapest expansion for " + name + ", article will be ignored",
                                                 eError.Message, false);
                                        failed++;
                                        continue;
                                    }
                                }
                                mc.FillProductInfo(mostExpProduct);
                                hasPriceGuide++;
                                break;
                            }
                        }
                        else
                        {
                            LogError("importing line #" + (counter + 1) + ", identifying expansion for " + name + ", article will be ignored",
                                     "No card with this name found.", false);
                            failed++;
                            continue;
                        }
                        // TODO - determine whether the expansion is foil only / cannot be foil and based on the isFoil flag of the current article choose the correct set
                    }
                    // now we have expID and English name -> we can determine the product ID
                    string[] ids = MKMDbManager.Instance.GetCardProductID(name, mc.GetAttribute(MCAttribute.ExpansionID));
                    if (ids.Length == 0)
                    {
                        LogError("importing line #" + (counter + 1) + ", article will be ignored",
                                 "The specified " + name + " and expansion ID " + expID + " do not match - product cannot be identified.", false);
                        failed++;
                        continue;
                    }
                    else if (ids.Length > 1)
                    {
                        string cardNumber = mc.GetAttribute(MCAttribute.CardNumber);
                        if (cardNumber == "")
                        {
                            LogError("importing line #" + (counter + 1) + ", article will be ignored", "The specified " + name +
                                     " and expansion ID " + expID + " match multiple products - please provide Card Number to identify which one it is.", false);
                            failed++;
                            continue;
                        }
                        // search for the matching item
                        int start = 0;
                        try
                        {
                            XmlNodeList products;
                            do
                            {
                                XmlDocument doc = MKMInteract.RequestHelper.findProducts(name, "1", start);
                                products = doc.GetElementsByTagName("product");
                                string expansion = mc.GetAttribute(MCAttribute.Expansion);
                                foreach (XmlNode product in products)
                                {
                                    if (product["number"].InnerText == cardNumber && product["expansionName"].InnerText == expansion)
                                    {
                                        productID = product["idProduct"].InnerText;
                                        // since we already have it, why not fill the product info in the MetaCard
                                        mc.FillProductInfo(product);
                                        break;
                                    }
                                }
                                start += products.Count;
                            } while (products.Count == 100 && productID == "");
                        }
                        catch (Exception eError)
                        {
                            LogError("importing line #" + (counter + 1) + ", trying to find product ID for "
                                     + name + " based on its card number and expansion, article will be ignored", eError.Message, false);
                            failed++;
                            continue;
                        }
                        if (productID == "")
                        {
                            LogError("importing line #" + (counter + 1) + ", article will be ignored", "The specified " + name +
                                     " and expansion ID " + expID
                                     + " match multiple products, Card Number was used to find the correct article, but no match was found, verify the data is correct.", false);
                            failed++;
                            continue;
                        }
                    }
                    else
                    {
                        productID = ids[0];
                    }
                    mc.SetAttribute(MCAttribute.ProductID, productID);
                }

                // if the defaults are "Any", there is not point in checking whether that attribute has been set or not
                if (defaultPlayset != "")
                {
                    temp = mc.GetAttribute(MCAttribute.Playset);
                    if (temp == "")
                    {
                        mc.SetBoolAttribute(MCAttribute.Playset, defaultPlayset);
                    }
                }
                if (defaultSigned != "")
                {
                    temp = mc.GetAttribute(MCAttribute.Signed);
                    if (temp == "")
                    {
                        mc.SetBoolAttribute(MCAttribute.Signed, defaultSigned);
                    }
                }
                if (defaultAltered != "")
                {
                    temp = mc.GetAttribute(MCAttribute.Altered);
                    if (temp == "")
                    {
                        mc.SetBoolAttribute(MCAttribute.Altered, defaultAltered);
                    }
                }
                // rarity might not be present in some cases, check it and get it from database, or worst case from MKM
                var rarity = mc.GetAttribute(MCAttribute.Rarity);
                if (rarity == "")
                {
                    var dataRow = MKMDbManager.Instance.GetSingleCard(productID);
                    rarity = dataRow[MKMDbManager.InventoryFields.Rarity].ToString();
                    if (rarity == "")
                    {
                        try
                        {
                            var productDoc = MKMInteract.RequestHelper.getProduct(productID);
                            rarity = productDoc["response"]["product"]["rarity"].InnerText;
                            dataRow[MKMDbManager.InventoryFields.Rarity] = rarity;
                        }
                        catch (Exception eError)
                        {
                            LogError("getting rarity for product " + productID, eError.Message, false);
                        }
                    }
                    mc.SetAttribute(MCAttribute.Rarity, rarity);
                }

                importedValidOnly.Add(mc);
                if (checkBoxImportLog.Checked)
                {
                    MainView.Instance.LogMainWindow("Imported line #" + (counter + 1) + ", " + name);
                }
            }

            MainView.Instance.LogMainWindow("Card list " + filePath + " imported. Successfully imported " + importedValidOnly.Count +
                                            " articles, failed to import: " + failed + ", articles that include MKM Price Guide: " + hasPriceGuide);
            if (hasPriceGuide > 0)
            {
                priceGuidesGenerated = true;
            }
        }