)>}]
شركة التطبيقات المتكاملة لتصميم وبرمجة البرمجيات الخاصة ش.ش.و.
Integrated Applications Programming Company
Home » Code Library » Default (Ia.Statistics.Cl.Models.LuluHypermarket)

Public general use code classes and xml files that we've compiled and used over the years:

Structure of the lulutypermarket.com website.

    1: using System;
    2: using System.Collections.Generic;
    3: using System.IO;
    4: using System.Linq;
    5: using System.Reflection;
    6: using System.Xml.Linq;
    7: using System.Text.RegularExpressions;
    8: using OpenQA.Selenium;
    9: using OpenQA.Selenium.Chrome;
   10:  
   11: namespace Ia.Statistics.Cl.Models.LuluHypermarket
   12: {
   13:     ////////////////////////////////////////////////////////////////////////////
   14:  
   15:     /// <summary publish="true">
   16:     /// Structure of the lulutypermarket.com website.
   17:     /// </summary>
   18:     /// <remarks> 
   19:     /// Copyright © 2024-2025 Jasem Y. Al-Shamlan (info@ia.com.kw), Integrated Applications - Kuwait. All Rights Reserved.
   20:     ///
   21:     /// This library is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
   22:     /// the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
   23:     ///
   24:     /// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
   25:     /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   26:     /// 
   27:     /// You should have received a copy of the GNU General Public License along with this library. If not, see http://www.gnu.org/licenses.
   28:     /// 
   29:     /// Copyright notice: This notice may not be removed or altered from any source distribution.
   30:     /// </remarks> 
   31:     public class Default
   32:     {
   33:         private static int updateProductUrlListCounter = 0;
   34:  
   35:         private static XDocument xd;
   36:  
   37:         private static List<Ia.Statistics.Cl.Models.Category> categoryList;
   38:  
   39:         private static Dictionary<Ia.Statistics.Cl.Models.Category, string> categoryToNextUrlDictionary = new Dictionary<Ia.Statistics.Cl.Models.Category, string>();
   40:  
   41:         private static List<string> productUrlList = new List<string>();
   42:  
   43:         ////////////////////////////////////////////////////////////////////////////
   44:  
   45:         /// <summary>
   46:         /// 
   47:         /// </summary>
   48:         public Default() { }
   49:  
   50:         ////////////////////////////////////////////////////////////////////////////
   51:  
   52:         /// <summary>
   53:         ///
   54:         /// </summary>
   55:         public static void UpdateProductUrlList(Ia.Statistics.Cl.Models.Site site)
   56:         {
   57:             var list = ProductUrlListOfCategorySequentially();
   58:  
   59:             var storedList = Ia.Statistics.Cl.Models.Product.UrlListBySiteId(site.Id);
   60:  
   61:             if (productUrlList.Count > 0)
   62:             {
   63:                 foreach (var l in list)
   64:                 {
   65:                     if (!productUrlList.Contains(l)) productUrlList.Add(l);
   66:                 }
   67:             }
   68:             else productUrlList = list;
   69:  
   70:             if (productUrlList.Count > 0)
   71:             {
   72:                 foreach (var l in storedList)
   73:                 {
   74:                     if (!productUrlList.Contains(l)) productUrlList.Add(l);
   75:                 }
   76:             }
   77:             else productUrlList = storedList;
   78:         }
   79:  
   80:         ////////////////////////////////////////////////////////////////////////////
   81:  
   82:         /// <summary>
   83:         ///
   84:         /// </summary>
   85:         private static List<string> ProductUrlListOfCategorySequentially()
   86:         {
   87:             Ia.Statistics.Cl.Models.Category category;
   88:  
   89:             if (categoryToNextUrlDictionary.Count > 0)
   90:             {
   91:                 var categoryToNextUrl = categoryToNextUrlDictionary.First();
   92:  
   93:                 category = categoryToNextUrl.Key;
   94:                 category.Url = categoryToNextUrl.Value;
   95:  
   96:                 categoryToNextUrlDictionary.Remove(category);
   97:             }
   98:             else
   99:             {
  100:                 category = Ia.Statistics.Cl.Models.LuluHypermarket.Default.CategoryList.RandomThenNext();
  101:             }
  102:  
  103:             var list = ProductUrlListOfCategory(category);
  104:  
  105:             return list;
  106:         }
  107:  
  108:         ////////////////////////////////////////////////////////////////////////////
  109:  
  110:         /// <summary>
  111:         ///
  112:         /// </summary>
  113:         public static List<string> ProductUrlListOfCategory(Ia.Statistics.Cl.Models.Category category)
  114:         {
  115:             var list = new List<string>();
  116:  
  117:             var options = new ChromeOptions();
  118:  
  119:             var chromeDriverService = ChromeDriverService.CreateDefaultService();
  120:             chromeDriverService.HideCommandPromptWindow = true;
  121:             chromeDriverService.SuppressInitialDiagnosticInformation = true;
  122:  
  123:             options.AddArgument("--headless");
  124:             options.AddArgument("--log-level=3");
  125:             options.AddArgument("--disable-extensions");
  126:             options.AddArgument("--ignore-certificate-errors");
  127:  
  128:             using (var chromeDriver = new OpenQA.Selenium.Chrome.ChromeDriver(chromeDriverService, options))
  129:             {
  130:                 chromeDriver.Manage().Timeouts().ImplicitWait = Ia.Statistics.Cl.Models.Default.TimeoutTimeSpan;
  131:  
  132:                 chromeDriver.Navigate().GoToUrl(category.Url);
  133:  
  134:                 var javaScriptExecutor = ((IJavaScriptExecutor)chromeDriver);
  135:                 javaScriptExecutor.ExecuteScript("window.scrollTo(0, document.body.scrollHeight)");
  136:  
  137:                 var content = chromeDriver.PageSource;
  138:  
  139:                 list = ProductUrlListFromCategoryContent(category, content);
  140:             }
  141:  
  142:             return list;
  143:         }
  144:  
  145:         ////////////////////////////////////////////////////////////////////////////
  146:  
  147:         /// <summary>
  148:         ///
  149:         /// </summary>
  150:         public static List<string> ProductUrlListFromCategoryContent(Ia.Statistics.Cl.Models.Category category, string content)
  151:         {
  152:             string url;
  153:  
  154:             var list = new List<string>();
  155:  
  156:             /*
  157:             // below: check if content has a Next link
  158:             var nextMatch = Regex.Match(content, @"<li class=""item pages-item-next"">.+?<a class=""action  next"".+?href=""(.+?)"".+?title=""Next"">", RegexOptions.Singleline, Ia.Statistics.Cl.Model.Default.TimeoutTimeSpan);
  159: 
  160:             if (nextMatch.Success)
  161:             {
  162:                 var nextUrl = nextMatch.Groups[1].Value;
  163: 
  164:                 categoryToNextUrlDictionary[category] = nextUrl;
  165:             }
  166:             */
  167:  
  168:             var matchCollection = Regex.Matches(content, @"<div class=""product-box .+? data-url=""(.+?)"" data-productcode=""\d+?"">.+?<input type=""hidden"" id="".+?"" class="".+?"" data-id=""\d+?"" data-name="".+?"" data-price="".+?"" .+?", RegexOptions.Singleline, Ia.Statistics.Cl.Models.Default.TimeoutTimeSpan);
  169:  
  170:             foreach (Match match in matchCollection)
  171:             {
  172:                 url = Ia.Statistics.Cl.Models.Site.LuluHypermarketKuwait.BaseUrl + match.Groups[1].Value;
  173:  
  174:                 list.Add(url);
  175:             }
  176:  
  177:             return list;
  178:         }
  179:  
  180:         ////////////////////////////////////////////////////////////////////////////
  181:         ////////////////////////////////////////////////////////////////////////////
  182:  
  183:         /// <summary>
  184:         ///
  185:         /// </summary>
  186:         public static string ReadUpdateProductPriceStockByProductUrlSequentially(Ia.Statistics.Cl.Models.Site site)
  187:         {
  188:             var s = string.Empty;
  189:             var productUrl = string.Empty;
  190:  
  191:             if (productUrlList.Count == 0 || updateProductUrlListCounter++ % Ia.Statistics.Cl.Models.Default.AverageNumberOfProductsPerCategory == 0) Ia.Statistics.Cl.Models.LuluHypermarket.Default.UpdateProductUrlList(site);
  192:  
  193:             if (productUrlList.Count > 0)
  194:             {
  195:                 productUrl = productUrlList.RandomThenNext();
  196:  
  197:                 ReadProductPriceStockByProductUrl(site, productUrl, out Ia.Statistics.Cl.Models.Product product, out decimal price, out int stock);
  198:  
  199:                 if (!string.IsNullOrEmpty(product.Sku))
  200:                 {
  201:                     Ia.Statistics.Cl.Models.Product.Create(product);
  202:                     Ia.Statistics.Cl.Models.ProductPriceSpot.Create(product, price);
  203:                     Ia.Statistics.Cl.Models.ProductStockSpot.Create(product, stock);
  204:  
  205:                     s = "Product: " + product.Name + "; price: " + price + "; stock: " + stock + ". ";
  206:                 }
  207:                 else s = "Product: " + product.Name + ": SKU is null. ";
  208:             }
  209:             else s = "Product list is empty. ";
  210:  
  211:             s = site.Name + ": " + productUrl + ": " + s;
  212:  
  213:             return s;
  214:         }
  215:  
  216:         ////////////////////////////////////////////////////////////////////////////
  217:  
  218:         /// <summary>
  219:         ///
  220:         /// </summary>
  221:         public static void ReadProductPriceStockByProductUrl(Ia.Statistics.Cl.Models.Site site, string productUrl, out Ia.Statistics.Cl.Models.Product product, out decimal price, out int stock)
  222:         {
  223:             var options = new ChromeOptions();
  224:  
  225:             var chromeDriverService = ChromeDriverService.CreateDefaultService();
  226:             chromeDriverService.HideCommandPromptWindow = true;
  227:             chromeDriverService.SuppressInitialDiagnosticInformation = true;
  228:  
  229:             options.AddArgument("--headless");
  230:             options.AddArgument("--log-level=3");
  231:             options.AddArgument("--disable-extensions");
  232:             options.AddArgument("--ignore-certificate-errors");
  233:  
  234:             using (var chromeDriver = new OpenQA.Selenium.Chrome.ChromeDriver(chromeDriverService, options))
  235:             {
  236:                 chromeDriver.Manage().Timeouts().ImplicitWait = Ia.Statistics.Cl.Models.Default.TimeoutTimeSpan;
  237:  
  238:                 chromeDriver.Navigate().GoToUrl(productUrl);
  239:  
  240:                 //var javaScriptExecutor = ((IJavaScriptExecutor)chromeDriver); do not scroll or you will loose button position
  241:                 //javaScriptExecutor.ExecuteScript("window.scrollTo(0, document.body.scrollHeight)");
  242:  
  243:                 var content = chromeDriver.PageSource;
  244:  
  245:                 ProductSkuNamePriceStockFromContent(content, out string sku, out string name, out price, out stock);
  246:  
  247:                 product = new Ia.Statistics.Cl.Models.Product();
  248:  
  249:                 product.Id = Ia.Statistics.Cl.Models.Product.ProductId(site, sku);
  250:                 product.SiteId = site.Id;
  251:                 //product.Category = product.Category;
  252:                 product.Sku = sku;
  253:                 product.Name = name;
  254:                 product.Url = productUrl;
  255:  
  256:                 if (content.Contains("product:availability") && content.Contains("in stock"))
  257:                 {
  258:                     var exceptionCounter = 0;
  259:                     stock = 0;
  260:                     var stockList = new List<int>();
  261:                     //var list = new List<int>();
  262:  
  263:                     do
  264:                     {
  265:                         try
  266:                         {
  267:                             // <button id="addToCartButton"
  268:                             var addToCartButton = chromeDriver.FindElement(By.Id("addToCartButton"), 10);
  269:  
  270:                             // <span class="badge badge-warning minicart-count js-mini-cart-count">100</span>
  271:                             var counterNumberTag = chromeDriver.FindElement(By.ClassName("badge"), 10);
  272:  
  273:                             if (addToCartButton.Text == "ADD TO CART")
  274:                             {
  275:                                 addToCartButton.Click();
  276:                                 //list.Add(0);
  277:  
  278:                                 var text = counterNumberTag.Text;
  279:  
  280:                                 if (int.TryParse(text, out stock)) stockList.Add(stock);
  281:                             }
  282:                             else //if(addToCartButton.Text == "Add to Cart" || addToCartButton.Text == "Adding...")
  283:                             {
  284:                                 // nothing
  285:                             }
  286:                         }
  287:                         catch (Exception e)
  288:                         {
  289:                             if (exceptionCounter++ == 10) throw new Exception("Exception counter at 10: " + e.Message);
  290:                         }
  291:                     }
  292:                     while (!LastThreeNumbersAreIdentical(stockList));
  293:                 }
  294:                 else stock = 0;
  295:             }
  296:         }
  297:  
  298:         private static bool LastThreeNumbersAreIdentical(List<int> list)
  299:         {
  300:             var identical = false;
  301:  
  302:             if (list.Count >= 3)
  303:             {
  304:                 var length = list.Count;
  305:  
  306:                 if (list[length - 1] == list[length - 2] && list[length - 1] == list[length - 3]) identical = true;
  307:                 else identical = false;
  308:             }
  309:  
  310:             return identical;
  311:         }
  312:  
  313:         ////////////////////////////////////////////////////////////////////////////
  314:  
  315:         ///// <summary>
  316:         ///
  317:         /// </summary>
  318:         public static void ProductSkuNamePriceStockFromContent(string content, out string sku, out string name, out decimal price, out int stock)
  319:         {
  320:             var match = Regex.Match(content, @"<div class=""product-box .+? data-productcode=""(\d+?)"" data-url="".+?"">.+?<input type=""hidden"" id="".+?"" class="".+?"" data-id=""\d+?"" data-name=""(.+?)"" data-price=""(.+?)"" data-brand=.+?", RegexOptions.Singleline, Ia.Statistics.Cl.Models.Default.TimeoutTimeSpan);
  321:  
  322:             if (match.Success)
  323:             {
  324:                 sku = match.Groups[1].Value;
  325:                 name = match.Groups[2].Value;
  326:                 name = Ia.Statistics.Cl.Models.Default.NormalizeName(name);
  327:  
  328:                 price = decimal.TryParse(match.Groups[3].Value, out decimal d) ? d : 0;
  329:  
  330:                 //stock = int.Parse(match.Groups[6].Value);
  331:                 stock = Ia.Statistics.Cl.Models.Default.StockValueUnAvailable; //stock <= Ia.Statistics.Cl.Model.Default.MaximumReasonableStockValue ? stock : Ia.Statistics.Cl.Model.Default.MaximumReasonableStockValue;
  332:             }
  333:             else
  334:             {
  335:                 name = string.Empty;
  336:                 sku = string.Empty;
  337:  
  338:                 price = Ia.Statistics.Cl.Models.Default.UndefinedOrInvalidOrUnknown;
  339:                 stock = Ia.Statistics.Cl.Models.Default.UndefinedOrInvalidOrUnknown;
  340:             }
  341:         }
  342:  
  343:         /*
  344:         ////////////////////////////////////////////////////////////////////////////
  345: 
  346:         /// <summary>
  347:         ///
  348:         /// </summary>
  349:         public static string ReadUpdateProductListOfCategorySequentially()
  350:         {
  351:             string s;
  352:             List<string> productIdList;
  353: 
  354:             var category = Ia.Statistics.Cl.Model.LuluHypermarket.Default.CategoryList.RandomThenNext();
  355: 
  356:             var site = Ia.Statistics.Cl.Model.Site.SiteFromId(category.SiteId);
  357: 
  358:             var productPriceStockQuantitySoldList = ProductPriceStockListOfCategory(site, category, out string exception);
  359: 
  360:             if (string.IsNullOrEmpty(exception))
  361:             {
  362:                 if (productPriceStockQuantitySoldList.Count > 0)
  363:                 {
  364:                     s = string.Empty;
  365:                     productIdList = new List<string>(); // this is needed because sometimes the parser read a product twice
  366: 
  367:                     foreach (var productPriceStockQuantitySold in productPriceStockQuantitySoldList)
  368:                     {
  369:                         if (!productIdList.Contains(productPriceStockQuantitySold.Product.Id))
  370:                         {
  371:                             if (!string.IsNullOrEmpty(productPriceStockQuantitySold.Product.Sku))
  372:                             {
  373:                                 Ia.Statistics.Cl.Model.Product.Create(productPriceStockQuantitySold.Product);
  374:                                 Ia.Statistics.Cl.Model.ProductPriceSpot.Create(productPriceStockQuantitySold.Product, productPriceStockQuantitySold.Price);
  375:                                 Ia.Statistics.Cl.Model.ProductStockSpot.Create(productPriceStockQuantitySold.Product, productPriceStockQuantitySold.Stock);
  376: 
  377:                                 s += "Product: " + productPriceStockQuantitySold.Product.Name + "; price: " + productPriceStockQuantitySold.Price + "; stock: " + productPriceStockQuantitySold.Stock + ". ";
  378:                             }
  379:                             else
  380:                             {
  381:                                 s += "Product: " + productPriceStockQuantitySold.Product.Name + ": SKU is null. ";
  382:                             }
  383:                         }
  384:                         else
  385:                         {
  386:                             s += "Product: Product with Id " + productPriceStockQuantitySold.Product.Id + " has already been created. ";
  387:                         }
  388: 
  389:                         productIdList.Add(productPriceStockQuantitySold.Product.Id);
  390:                     }
  391:                 }
  392:                 else s = "Product list is 0. ";
  393: 
  394:                 s = site.Name + ": " + category.Url + ": " + s;
  395:             }
  396:             else s = exception;
  397: 
  398:             return s;
  399:         }
  400: 
  401:         ////////////////////////////////////////////////////////////////////////////
  402: 
  403:         /// <summary>
  404:         ///
  405:         /// </summary>
  406:         public static List<Ia.Statistics.Cl.Model.ProductPriceStockQuantitySold> ProductPriceStockListOfCategory(Ia.Statistics.Cl.Model.Site site, Ia.Statistics.Cl.Model.Category category, out string exception)
  407:         {
  408:             int areaId;
  409: 
  410:             var productPriceStockQuantitySoldList = new List<Ia.Statistics.Cl.Model.ProductPriceStockQuantitySold>();
  411: 
  412:             var options = new ChromeOptions();
  413: 
  414:             var chromeDriverService = ChromeDriverService.CreateDefaultService();
  415:             chromeDriverService.HideCommandPromptWindow = true;
  416:             chromeDriverService.SuppressInitialDiagnosticInformation = true;
  417: 
  418:             options.AddArgument("--headless");
  419:             options.AddArgument("--log-level=3");
  420:             options.AddArgument("--disable-extensions");
  421:             options.AddArgument("--ignore-certificate-errors");
  422: 
  423:             /*
  424:             switch (site.Iso)
  425:             {
  426:                 case "KW": areaId = 10; break;
  427:                 case "SA": areaId = 2648; break;
  428:                 case "AE": areaId = 12; break;
  429:                 case "QA": areaId = 6; break;
  430:                 case "BH": areaId = 11; break;
  431:                 default: areaId = 10; break;
  432:             }
  433:             * /
  434: 
  435:             using (var chromeDriver = new OpenQA.Selenium.Chrome.ChromeDriver(chromeDriverService, options))
  436:             {
  437:                 chromeDriver.Manage().Timeouts().ImplicitWait = Ia.Statistics.Cl.Model.Default.TimeoutTimeSpan;
  438: 
  439:                 chromeDriver.Navigate().GoToUrl(category.Url);
  440: 
  441:                 //chromeDriver.Manage().Cookies.AddCookie(new OpenQA.Selenium.Cookie("DAB_AREA", areaId.ToString(), "", DateTime.UtcNow.AddHours(3).AddYears(1)));
  442:                 //chromeDriver.Manage().Cookies.AddCookie(new OpenQA.Selenium.Cookie("DAB_COUNTRY", site.Iso, "", DateTime.UtcNow.AddHours(3).AddYears(1)));
  443:                 //chromeDriver.Manage().Cookies.AddCookie(new OpenQA.Selenium.Cookie("accept_cookies", "accepted", "", DateTime.UtcNow.AddHours(3).AddYears(1)));
  444:                 //chromeDriver.Manage().Cookies.AddCookie(new OpenQA.Selenium.Cookie("ajs_anonymous_id", "e7a170bb-807b-4546-8caf-b7cec22f20c5", "", DateTime.UtcNow.AddHours(3).AddYears(1)));
  445: 
  446:                 //chromeDriver.Navigate().GoToUrl(category.Url); // I will access site again with location cookies
  447: 
  448:                 // maximize the browser
  449:                 // chromeDriver.Manage().Window.Maximize();
  450: 
  451:                 // scroll down the webpage
  452:                 var javaScriptExecutor = ((IJavaScriptExecutor)chromeDriver);
  453:                 javaScriptExecutor.ExecuteScript("window.scrollTo(0, document.body.scrollHeight)");
  454: 
  455:                 var content = chromeDriver.PageSource;
  456: 
  457:                 ProductPriceStockListFromCategoryContent(site, category, content, out productPriceStockQuantitySoldList, out exception);
  458:             }
  459: 
  460:             return productPriceStockQuantitySoldList;
  461:         }
  462: 
  463:         ////////////////////////////////////////////////////////////////////////////
  464: 
  465:         /// <summary>
  466:         ///
  467:         /// </summary>
  468:         public static void ProductPriceStockListFromCategoryContent(Ia.Statistics.Cl.Model.Site site, Ia.Statistics.Cl.Model.Category category, string content, out List<Ia.Statistics.Cl.Model.ProductPriceStockQuantitySold> productPriceStockQuantitySoldList, out string exception)
  469:         {
  470:             productPriceStockQuantitySoldList = new List<Ia.Statistics.Cl.Model.ProductPriceStockQuantitySold>();
  471: 
  472:             var matchCollection = Regex.Matches(content, @"<div class=""product-box .+? data-url=""(.+?)"" data-productcode=""(\d+?)"">.+?<input type=""hidden"" id="".+?"" class="".+?"" data-id=""\d+?"" data-name=""(.+?)"" data-price=""(.+?)"" .+?", RegexOptions.Singleline, Ia.Statistics.Cl.Model.Default.TimeoutTimeSpan);
  473: 
  474:             foreach (Match match in matchCollection)
  475:             {
  476:                 var product = new Ia.Statistics.Cl.Model.Product();
  477:                 var productPriceStockQuantitySold = new Ia.Statistics.Cl.Model.ProductPriceStockQuantitySold();
  478: 
  479:                 var sku = match.Groups[2].Value; // data-productcode
  480: 
  481:                 var name = match.Groups[3].Value; // name
  482:                 name = Ia.Statistics.Cl.Model.Default.NormalizeName(name);
  483: 
  484:                 var url = match.Groups[1].Value; // data-url
  485: 
  486:                 product.Id = Ia.Statistics.Cl.Model.Product.ProductId(site, sku);
  487:                 product.SiteId = site.Id;
  488:                 //product.Category = category;
  489:                 product.Sku = sku;
  490:                 product.Name = name;
  491:                 product.Url = site.BaseUrl + url;
  492: 
  493:                 var price = decimal.TryParse(match.Groups[4].Value, out decimal d) ? d : 0;
  494: 
  495:                 //var stock = int.Parse(match.Groups[6].Value); // buy_limit;
  496:                 var stock = Ia.Statistics.Cl.Model.Default.StockValueUnAvailable; // stock <= Ia.Statistics.Cl.Model.Default.MaximumReasonableStockValue ? stock : Ia.Statistics.Cl.Model.Default.MaximumReasonableStockValue;
  497: 
  498:                 productPriceStockQuantitySold.Product = product;
  499:                 productPriceStockQuantitySold.Price = price;
  500:                 productPriceStockQuantitySold.Stock = stock;
  501: 
  502:                 productPriceStockQuantitySoldList.Add(productPriceStockQuantitySold);
  503:             }
  504: 
  505:             exception = string.Empty;
  506:         }
  507: 
  508:         ////////////////////////////////////////////////////////////////////////////
  509:         ////////////////////////////////////////////////////////////////////////////
  510: 
  511:         /// <summary>
  512:         ///
  513:         /// </summary>
  514:         public static string ProductUrlListOfCategorySequentially()
  515:         {
  516:             Ia.Statistics.Cl.Model.Category category;
  517: 
  518:             /*
  519:             if (categoryToNextUrlDictionary.Count > 0)
  520:             {
  521:                 var categoryToNextUrl = categoryToNextUrlDictionary.First();
  522: 
  523:                 category = categoryToNextUrl.Key;
  524:                 category.Url = categoryToNextUrl.Value;
  525: 
  526:                 categoryToNextUrlDictionary.Remove(category);
  527:             }
  528:             else
  529:             {
  530:             * /
  531:             category = Ia.Statistics.Cl.Model.LuluHypermarket.Default.CategoryList.RandomThenNext();
  532:             //category = (from c in Ia.Statistics.Cl.Model.LuluHypermarket.Default.CategoryList where c.Url.Contains("chocolate-candy.html") select c).SingleOrDefault();
  533:             //}
  534: 
  535:             var list = ProductUrlListOfCategory(category);
  536: 
  537:             if (productUrlList.Count > 0)
  538:             {
  539:                 foreach (var l in list)
  540:                 {
  541:                     if (!productUrlList.Contains(l)) productUrlList.Add(l);
  542:                 }
  543:             }
  544:             else productUrlList = list;
  545: 
  546:             return "Category: " + category.Name + "; product count: " + productUrlList.Count + ". ";
  547:         }
  548:         */
  549:  
  550:         ////////////////////////////////////////////////////////////////////////////
  551:         ////////////////////////////////////////////////////////////////////////////
  552:  
  553:         /// <summary>
  554:         ///
  555:         /// </summary>
  556:         public static List<Ia.Statistics.Cl.Models.Category> CategoryList
  557:         {
  558:             get
  559:             {
  560:                 if (categoryList == null || categoryList.Count == 0)
  561:                 {
  562:                     categoryList = (from c in XDocument.Element("luluhypermarket").Descendants("category")
  563:                                     where !c.HasElements
  564:                                     select new Ia.Statistics.Cl.Models.Category
  565:                                     {
  566:                                         Id = 0, //Ia.Statistics.Cl.Model.Category.CategoryId(Ia.Statistics.Cl.Model.Site.LuluHypermarketKuwait, int.Parse(c.Attribute("id").Value)),
  567:                                         SiteId = Ia.Statistics.Cl.Models.Site.LuluHypermarketKuwait.Id,
  568:                                         Url = Ia.Statistics.Cl.Models.Site.LuluHypermarketKuwait.BaseUrl + c.Attribute("url").Value,
  569:                                         Name = c.Attribute("name").Value
  570:                                     }
  571:                                     ).ToList<Ia.Statistics.Cl.Models.Category>();
  572:  
  573:                     categoryList = categoryList.Shuffle().ToList();
  574:                 }
  575:  
  576:                 return categoryList;
  577:             }
  578:         }
  579:  
  580:         ////////////////////////////////////////////////////////////////////////////
  581:  
  582:         /// <summary>
  583:         /// 
  584:         /// How to embed and access resources by using Visual C# http://support.microsoft.com/kb/319292/en-us
  585:         /// 
  586:         /// 1. Change the "Build Action" property of your XML file from "Content" to "Embedded Resource".
  587:         /// 2. Add "using System.Reflection".
  588:         /// 3. Manifest resource stream will start with the project namespace, the location of XML file.
  589:         /// 
  590:         /// </summary>
  591:  
  592:         private static XDocument XDocument
  593:         {
  594:             get
  595:             {
  596:                 Assembly assembly;
  597:                 StreamReader streamReader;
  598:  
  599:                 xd = null;
  600:                 assembly = Assembly.GetExecutingAssembly();
  601:                 streamReader = new StreamReader(assembly.GetManifestResourceStream("Ia.Statistics.Cl.Models.luluhypermarket.com.default.xml"));
  602:  
  603:                 try
  604:                 {
  605:                     if (streamReader.Peek() != -1)
  606:                     {
  607:                         xd = System.Xml.Linq.XDocument.Load(streamReader);
  608:                     }
  609:                 }
  610:                 catch (Exception)
  611:                 {
  612:                 }
  613:                 finally
  614:                 {
  615:                 }
  616:  
  617:                 return xd;
  618:             }
  619:         }
  620:  
  621:         ////////////////////////////////////////////////////////////////////////////
  622:         ////////////////////////////////////////////////////////////////////////////
  623:     }
  624: }