public void SaveSiteRules(string alias, XElement settings, SiteRules rules = null, WebContextProxy wc = null)
        {
            try
            {
            #if DEBUG
                if (BoostLog.Instance != null && wc != null)
                    BoostLog.Instance.WriteEntry(EventLogEntryType.Information,
                        string.Format("Saving Rules for {0}", alias), "Context:\n" + wc.ToString(), alias);
            #endif
                var path = DataPath.Instance.ClientDataPath(alias, true);
                if (!Directory.Exists(path)) Directory.CreateDirectory(path);
                settings.Save(path + SiteRulesFileName);

                //check to see if we should update BoostConfigOverride (used when customers upload data directly to us)
                if (rules == null || rules.CartExtractorExists || TableAccess.Instance == null) return;

                var data = rules.FormatGeneratorConfig();
                TableAccess.Instance.WriteTable(alias, "ConfigBoostOverride.txt", data);
            }
            catch { }
        }
        public void SaveSettings(WebContextProxy wc = null, bool ruleChange = true)
        {
            try
            {
                var settings = new XElement("siteRules");

                //basic site definition
                settings.Add(new XElement("alias", Alias));
                settings.Add(new XElement("tier", Tier.ToString()));
                settings.Add(new XElement("storeUrl", StoreShortUrl));
                if (!SiteTimeZone.Id.Equals(DefaultTimeZoneId))
                    settings.Add(new XElement("siteTimeZone", SiteTimeZone.Id));
                settings.Add(new XElement("cartType", CartName)); //set and get using CartName and assign matching enum to CartType
                if (PluginVersion > 0)
                    settings.Add(new XElement("pluginVersion", PluginVersion));
                //TODO: save and retrieve cartlevel as a string (with legacy support for ints)
                settings.Add(new XElement("cartLevel", CartLevel));
                if (EnableServiceCallDetailLog) settings.Add(new XElement("enableServiceCallDetailLog", "true"));

                //Access Rules
                if (RequireSecureBoost)
                    settings.Add(new XElement("requireSecureBoost", RequireSecureBoost));
                if (RequireSecureUpload)
                    settings.Add(new XElement("requireSecureUpload", RequireSecureUpload));
                if (AccessCredentials != null)
                    settings.Add(AccessCredentials.ToXml("accessCredentials"));
                if (ExtractorCredentials != null)
                    settings.Add(ExtractorCredentials.ToXml("extractorCredentials"));
                if (ExtractorLoginCredentials != null)
                    settings.Add(ExtractorLoginCredentials.ToXml("extractorLoginCredentials"));
                if (!string.IsNullOrEmpty(ExtractorLoginUrl))
                    settings.Add(new XElement("extractorLoginUrl", ExtractorLoginUrl));
                if (UploadAddresses != null && UploadAddresses.Any())
                    settings.Add(new XElement("uploadAddresses", UploadAddresses.Aggregate((w, j) => string.Format("{0},{1}", w, j))));
                settings.Add(new XElement("lastExtractionType", LastExtractionType));
                if (LastDynamicUpdateType != CartExtractor.ExtractType.None)
                    settings.Add(new XElement("lastDynamicUpdateType", LastDynamicUpdateType));
                if (LastExtractionTime != DateTime.MinValue)
                    settings.Add(new XElement("lastExtractionTime", LastExtractionTime));
                if (LastDynamicUpdateTime != DateTime.MinValue)
                    settings.Add(new XElement("lastDynamicUpdateTime", LastDynamicUpdateTime));
                if (LastGeneratorTime != DateTime.MinValue)
                    settings.Add(new XElement("lastGeneratorTime", LastGeneratorTime));
                if (ruleChange) LastRuleChangeTime = DateTime.Now;
                if (LastRuleChangeTime != DateTime.MinValue)
                    settings.Add(new XElement("lastRuleChange", LastRuleChangeTime));
                if (LastExtractorDuration > 0)
                    settings.Add(new XElement("lastExtractorDuration", LastExtractorDuration));
                if (LastGeneratorDuration > 0)
                    settings.Add(new XElement("lastGeneratorDuration", LastGeneratorDuration));
                if (ExtractorLockoutMinutes != DefaultExtractorLockoutMinutes)
                    settings.Add(new XElement("extractorLockoutMinutes", ExtractorLockoutMinutes));
                if (!AllowManualUpload)
                    settings.Add(new XElement("allowManualUpload", "false")); //default is true
                if (!AllowUserExtraction)
                    settings.Add(new XElement("allowUserExtraction", "false")); //default is true

                //Data Extraction -parsing rules
                //general

                //hidden admin rules
                if (Resell)
                    settings.Add(new XElement("resell", "true"));
                if (!MinLikelihood.Equals(DefaultMinLikelihood))
                    settings.Add(new XElement("minLikelihood", MinLikelihood));
                if (!MinCommon.Equals(DefaultMinCommon))
                    settings.Add(new XElement("minCommon", MinCommon));
                if (!CurrencySymbol.Equals("$"))
                    settings.Add(new XElement("currencySymbol", CurrencySymbol));
                if (!DecimalSeparator.Equals("."))
                    settings.Add(new XElement("decimalSeparator", DecimalSeparator));
                if (!SimilarTopSellerRule.Equals(DefaultSimilarTopSellerRule))
                    settings.Add(new XElement("similarTopSellerRule", SimilarTopSellerRule));
                if (!SimilarClickStreamRule.Equals(DefaultSimilarClickStreamRule))
                    settings.Add(new XElement("similarClickStreamRule", SimilarClickStreamRule));
                if (!UpsellFactor.Equals(DefaultUpsellFactor))
                    settings.Add(new XElement("upsellFactor", UpsellFactor));
                if (!string.IsNullOrEmpty(FilterFilename))
                    settings.Add(new XElement("filterFilename", FilterFilename));
                if (CreateWhyItems)
                    settings.Add(new XElement("createWhyItems", "true"));
                if (CreateCampaignOptimization)
                    settings.Add(new XElement("createCampaignOptimization", "true"));
                if (RecTypesDisabled != null && RecTypesDisabled.Any())
                    settings.Add(new XElement("recTypesDisabled", RecTypesDisabled.Aggregate("", (w, j) => string.Format("{0},{1}", w, j.ToString()))));
                if (SalesFilenames != null && SalesFilenames.Any(x => !string.IsNullOrEmpty(x)))
                    settings.Add(new XElement("salesFilenames", SalesFilenames.Aggregate((w, j) => string.Format("{0},{1}", w, j))));
                if (OrdersFilenames != null && OrdersFilenames.Any(x => !string.IsNullOrEmpty(x)))
                    settings.Add(new XElement("ordersFilenames", OrdersFilenames.Aggregate((w, j) => string.Format("{0},{1}", w, j))));
                if (OrderDetailsFilenames != null && OrderDetailsFilenames.Any(x => !string.IsNullOrEmpty(x)))
                    settings.Add(new XElement("orderDetailsFilenames", OrderDetailsFilenames.Aggregate((w, j) => string.Format("{0},{1}", w, j))));
                if (ClickStreamFilenames != null && ClickStreamFilenames.Any(x => !string.IsNullOrEmpty(x)))
                    settings.Add(new XElement("clickStreamFilenames", ClickStreamFilenames.Aggregate((w, j) => string.Format("{0},{1}", w, j))));

                //Onboarding Credentials (not used by service but sometimes needed for onboarding)
                if (!string.IsNullOrEmpty(AdminUser))
                    settings.Add(new XElement("adminUser", AdminUser));
                if (!string.IsNullOrEmpty(AdminPassword))
                    settings.Add(new XElement("adminPassword", AdminPassword));
                if (!string.IsNullOrEmpty(FtpType))
                    settings.Add(new XElement("ftpType", FtpType));
                if (!string.IsNullOrEmpty(FtpUrl))
                    settings.Add(new XElement("ftpUrl", FtpUrl));
                if (!string.IsNullOrEmpty(FtpUser))
                    settings.Add(new XElement("ftpUser", FtpUser));
                if (!string.IsNullOrEmpty(FtpPassword))
                    settings.Add(new XElement("ftpPassword", FtpPassword));

                //Api settings
                if (!string.IsNullOrEmpty(ApiUrl))
                    settings.Add(new XElement("apiUrl", ApiUrl));
                if (!string.IsNullOrEmpty(ApiUserName))
                    settings.Add(new XElement("apiUserName", ApiUserName));
                if (ApiVersion > 0)
                    settings.Add(new XElement("apiVersion", ApiVersion));
                if (!ApiCountEnabled)
                    settings.Add(new XElement("apiCountEnabled", "false"));
                if (!ApiCustomerDateRangeEnabled)
                    settings.Add(new XElement("apiCustomerDateRangeEnabled", "false"));
                if (!ApiSalesDateRangeEnabled)
                    settings.Add(new XElement("apiSalesDateRangeEnabled", "false"));
                if (ApiHeaderIsOnlyOnFirstRow)
                    settings.Add(new XElement("apiHeaderIsOnlyOnFirstRow", "true"));
                var rowEnd = Input.SetCsvStringList(ApiRowEnd);
                if (!string.IsNullOrEmpty(rowEnd))
                    settings.Add(new XElement("apiRowEnd", rowEnd));
                var trimChars = Input.SetCsvCharList(ApiTrimChars);
                if (!string.IsNullOrEmpty(trimChars))
                    settings.Add(new XElement("apiTrimChars", trimChars));
                if (ApiMinimumCatalogSize > 0)
                    settings.Add(new XElement("apiMinimumCatalogSize", ApiMinimumCatalogSize));
                if (ApiForceAllRowRanges > 0)
                    settings.Add(new XElement("apiForceAllRowRanges", ApiForceAllRowRanges));
                if (ApiForceCatalogRowRange > 0)
                    settings.Add(new XElement("apiForceCatalogRowRange", ApiForceCatalogRowRange));
                if (ApiForceCategoryRowRange > 0)
                    settings.Add(new XElement("apiForceCategoryRowRange", ApiForceCategoryRowRange));
                if (ApiForceSalesRowRange > 0)
                    settings.Add(new XElement("apiForceSalesRowRange", ApiForceSalesRowRange));
                if (ApiForceCustomerRowRange > 0)
                    settings.Add(new XElement("apiForceCustomerRowRange", ApiForceCustomerRowRange));
                if (ApiForceInventoryRowRange > 0)
                    settings.Add(new XElement("apiForceInventoryRowRange", ApiForceInventoryRowRange));
                if (ApiAllowExtraRows)
                    settings.Add(new XElement("apiAllowExtraRows", "true"));
                if (ApiMaxDaysPerRequest > 0)
                    settings.Add(new XElement("apiMaxDaysPerRequest", ApiMaxDaysPerRequest));
                if (!string.IsNullOrEmpty(ApiKey))
                    settings.Add(new XElement("apiKey", ApiKey));
                if (!string.IsNullOrEmpty(ApiSecret))
                    settings.Add(new XElement("apiSecret", ApiSecret));
                if (!string.IsNullOrEmpty(ApiAliasParam))
                    settings.Add(new XElement("apiAliasParam", ApiAliasParam));
                if (!string.IsNullOrEmpty(ApiUserParam))
                    settings.Add(new XElement("apiUserParam", ApiUserParam));
                if (!string.IsNullOrEmpty(ApiKeyParam))
                    settings.Add(new XElement("apiKeyParam", ApiKeyParam));
                if (!string.IsNullOrEmpty(ApiFieldParam))
                    settings.Add(new XElement("apiFieldParam", ApiFieldParam));
                if (!string.IsNullOrEmpty(ApiRowRangeParam))
                    settings.Add(new XElement("apiRowRangeParam", ApiRowRangeParam));
                if (!string.IsNullOrEmpty(ApiIdRangeParam))
                    settings.Add(new XElement("apiIdRangeParam", ApiIdRangeParam));
                if (!string.IsNullOrEmpty(ApiDateRangeParam))
                    settings.Add(new XElement("apiDateRangeParam", ApiDateRangeParam));
                if (!string.IsNullOrEmpty(ApiYearParam))
                    settings.Add(new XElement("apiYearParam", ApiYearParam));
                if (!string.IsNullOrEmpty(ApiMonthParam))
                    settings.Add(new XElement("apiMonthParam", ApiMonthParam));
                if (!string.IsNullOrEmpty(ApiModeParam))
                    settings.Add(new XElement("apiModeParam", ApiModeParam));
                if (!string.IsNullOrEmpty(ApiResponseFormat))
                    settings.Add(new XElement("apiResponseFormat", ApiResponseFormat));
                if (!string.IsNullOrEmpty(ApiAcceptHeader))
                    settings.Add(new XElement("apiAcceptHeader", ApiAcceptHeader));
                if (ApiExtraHeaders > 0)
                    settings.Add(new XElement("apiExtraHeaders", ApiExtraHeaders));
                if (ApiAddQueries != null && ApiAddQueries.Any())
                {
                    var queries = new XElement("apiAddQueries");
                    foreach (var group in ApiAddQueries)
                    {
                        var groupName = group.Key;
                        foreach (var name in group.Value.AllKeys)
                        {
                            var add1 = new XElement("addQuery",
                                                                 new XAttribute("group", groupName),
                                                                 new XAttribute("name", name),
                                                                 new XAttribute("value", group.Value[name]));
                            queries.Add(add1);
                        }
                    }
                    settings.Add(queries);
                }
                if (TitleCharMap != null && TitleCharMap.Any())
                {
                    var pairs = new XElement("titleCharMap");
                    foreach (var pair in TitleCharMap)
                    {
                        char test;
                        string from, to;
                        if (!Input.TryConvert(pair.Key, out test)
                            || !Input.TryConvert(test, out from))
                            from = pair.Key;
                        if (!Input.TryConvert(pair.Value, out test)
                            || !Input.TryConvert(test, out to))
                            to = pair.Value;
                        pairs.Add(new XElement("mapPair",
                                                        new XAttribute("from", from),
                                                        new XAttribute("to", to)));
                    }
                    settings.Add(pairs);
                }
                if (WebClientConfig != null)
                    settings.Add(WebClientConfig.Xml);

                if (!string.IsNullOrEmpty(CombinedFeedUrl))
                    settings.Add(new XElement("combinedFeedUrl", CombinedFeedUrl));
                if (!string.IsNullOrEmpty(CatalogFeedUrl))
                    settings.Add(new XElement("catalogFeedUrl", CatalogFeedUrl));
                if (!string.IsNullOrEmpty(SalesFeedUrl))
                    settings.Add(new XElement("salesFeedUrl", SalesFeedUrl));
                if (!string.IsNullOrEmpty(CustomerFeedUrl))
                    settings.Add(new XElement("customerFeedUrl", CustomerFeedUrl));
                if (!string.IsNullOrEmpty(Att1NameFeedUrl))
                    settings.Add(new XElement("att1NameFeedUrl", Att1NameFeedUrl));
                if (!string.IsNullOrEmpty(Att2NameFeedUrl))
                    settings.Add(new XElement("att2NameFeedUrl", Att2NameFeedUrl));
                if (!string.IsNullOrEmpty(DepartmentNameFeedUrl))
                    settings.Add(new XElement("departmentNameFeedUrl", DepartmentNameFeedUrl));
                if (!string.IsNullOrEmpty(InventoryFeedUrl))
                    settings.Add(new XElement("inventoryFeedUrl", InventoryFeedUrl));

                //Data Extraction -parsing rules
                //general
                if (!SalesMonthsToExport.Equals(DefaultSalesMonths))
                    settings.Add(new XElement("salesMonthsToExport", SalesMonthsToExport));
                if (!CustomerMonthsToExport.Equals(DefaultSalesMonths))
                    settings.Add(new XElement("customerMonthsToExport", CustomerMonthsToExport));
                if (!ClickStreamWeeksToExport.Equals(DefaultClickWeeks))
                    settings.Add(new XElement("clickStreamWeeksToExport", ClickStreamWeeksToExport));
                if (!TopSellRangeInDays.Equals(DefaultTopSellDays))
                    settings.Add(new XElement("topSellRangeInDays", TopSellRangeInDays));
                if (UnescapeFeedData)
                    settings.Add(new XElement("unescapeFeedData", "true"));
                if (ReduceXmlFeed)
                    settings.Add(new XElement("reduceXmlFeed", "true"));
                if (OmitExtraFields)
                    settings.Add(new XElement("omitExtraFields", "true"));
                if (UseLargeCatalogHandling)
                    settings.Add(new XElement("useLargeCatalogHandling", "true"));
                //sales
                if (ExtractSalesUpdate)
                    settings.Add(new XElement("extractSalesUpdate", "true"));
                if (!ExtractSalesFull)
                    settings.Add(new XElement("extractSalesFull", "false")); //default true
                if (ExtractSalesFromXmlFile)
                    settings.Add(new XElement("extractSalesFromXmlFile", "true"));
                if (OrderDateReversed)
                    settings.Add(new XElement("orderDateReversed", "true"));
                //customers
                if (ExtractCustomerData)
                    settings.Add(new XElement("extractCustomerData", "true"));
                if (RequireEmailOptIn)
                    settings.Add(new XElement("requireEmailOptIn", "true"));
                if (TrackShopperActivity)
                    settings.Add(new XElement("trackShopperActivity", "true"));
                if (!string.IsNullOrEmpty(PersonaMappingFields))
                    settings.Add(new XElement("personaMappingFields", PersonaMappingFields));
                //catalog
                if (InvalidatePricesOnExtract)
                    settings.Add(new XElement("invalidatePricesOnExtract", "true"));
                if (InvalidatePricesOnExtractComplete)
                    settings.Add(new XElement("invalidatePricesOnExtractComplete", "true"));
                if (ExtractCatalogFromXmlFile)
                    settings.Add(new XElement("extractCatalogFromXmlFile", "true"));
                if (ExtractAtt2Names)
                    settings.Add(new XElement("extractAtt2Names", "true"));
                if (AllowLowerCatalogCount)
                    settings.Add(new XElement("allowLowerCatalogCount", "true"));
                if (AllowLowerSalesCount)
                    settings.Add(new XElement("allowLowerSalesCount", "true"));
                if (AllowLowerCustomerCount)
                    settings.Add(new XElement("allowLowerCustomerCount", "true"));
                if (MapStockToVisibility)
                    settings.Add(new XElement("mapStockToVisibility", "true"));
                if (ReverseVisibleFlag)
                    settings.Add(new XElement("reverseVisibleFlag", "true"));
                if (IgnoreStockUseFlag)
                    settings.Add(new XElement("ignoreStockUseFlag", "true"));
                if (IgnoreStockInPriceRange)
                    settings.Add(new XElement("ignoreStockInPriceRange", "true"));
                if (IncludeChildrenInCatalog)
                    settings.Add(new XElement("includeChildrenInCatalog", "true"));
                if (UseAverageChildRating)
                    settings.Add(new XElement("useAverageChildRating", "true"));
                if (!string.IsNullOrEmpty(HiddenSalePriceText))
                    settings.Add(new XElement("hiddenSalePriceText", HiddenSalePriceText));
                //categories
                if (MapCategoriesToFilters)
                    settings.Add(new XElement("mapCategoriesToFilters", "true"));
                if (IncludeCategoryParents)
                    settings.Add(new XElement("includeCategoryParents", "true"));
                if (ExportDepartmentNames)
                    settings.Add(new XElement("exportDepartmentNames", "true"));
                if (UseDepartmentsAsCategories)
                    settings.Add(new XElement("useDepartmentsAsCategories", "true"));
                if (!string.IsNullOrEmpty(CategorySeparator))
                    settings.Add(new XElement("categorySeparator", CategorySeparator));
                //inages
                if (AllowMissingPhotos)
                    settings.Add(new XElement("allowMissingPhotos", "true"));
                if (!MissingImageThreshold.Equals(DefaultMissingImageThreshold))
                    settings.Add(new XElement("missingImageThreshold", MissingImageThreshold));
                if (ExtrapolateThumbnailPath)
                    settings.Add(new XElement("extrapolateThumbnailPath", "true"));
                if (!ScrapeCategoryThumbnails)
                    settings.Add(new XElement("scrapeCategoryThumbnails", "false"));
                if (ForceCategoryTreeScrape)
                    settings.Add(new XElement("forceCategoryTreeScrape", "true"));
                if (!string.IsNullOrEmpty(ImageLinkBaseUrl))
                    settings.Add(new XElement("imageLinkBaseUrl", ImageLinkBaseUrl));
                if (!string.IsNullOrEmpty(ImageLinkFormat))
                    settings.Add(new XElement("imageLinkFormat", ImageLinkFormat));
                if (!string.IsNullOrEmpty(PageLinkFormat))
                    settings.Add(new XElement("pageLinkFormat", PageLinkFormat));
                if (!string.IsNullOrEmpty(ProductNodeSelector))
                    settings.Add(new XElement("productNodeSelector", ProductNodeSelector));
                if (!string.IsNullOrEmpty(ImageUrlSelector))
                    settings.Add(new XElement("imageUrlSelector", ImageUrlSelector));
                if (!string.IsNullOrEmpty(ImageUrlPrefix))
                    settings.Add(new XElement("imageUrlPrefix", ImageUrlPrefix));
                if (!string.IsNullOrEmpty(ImageUrlSuffix))
                    settings.Add(new XElement("imageUrlSuffix", ImageUrlSuffix));
                if (!string.IsNullOrEmpty(PidSelector))
                    settings.Add(new XElement("pidSelector", PidSelector));
                if (!string.IsNullOrEmpty(PidPrefix))
                    settings.Add(new XElement("pidPrefix", PidPrefix));
                if (!string.IsNullOrEmpty(PidSuffix))
                    settings.Add(new XElement("pidSuffix", PidSuffix));
                if (!string.IsNullOrEmpty(CommentParseKey))
                    settings.Add(new XElement("commentParseKey", CommentParseKey));

                //user details
                if (Users.Any())
                {
                    var users = new XElement("users");
                    foreach (var u in Users)
                    {
                        users.Add(u.ToXml("user"));
                    }
                    settings.Add(users);
                }

                //catalog migration
                if (MigrationRules != null)
                {
                    //test validity date each time rules are saved
                    MigrationRules.CheckDate(SalesMonthsToExport);
                    var migration = new XElement("catalogMigration",
                                                                new XAttribute("enabled", MigrationRules.Enabled),
                                            new XAttribute("startDate", MigrationRules.StartDate.ToShortDateString()),
                                                                new XAttribute("mapFromField", MigrationRules.MapFromField),
                                                                new XAttribute("mapToField", MigrationRules.MapToField),
                                                                new XAttribute("use4TellCatalog", MigrationRules.Use4TellCatalog),
                                                                new XAttribute("use4TellSales", MigrationRules.Use4TellSales)
                        );
                    settings.Add(migration);
                }

                // moved to DataField.cs
                ////Need to only save fieldnames if current value does not equal the default
                //foreach (var f in _fieldNames.Where(f => !f.Value.IsDefault))
                //{
                //  settings.Add(new XElement(GetRuleNameFromField(f.Key), f.Value.Name));
                //}

                ////Additions to the standard field list
                //if (AddStandardFields != null && AddStandardFields.Any())
                //  settings.Add(new XElement("addStandardFields", AddStandardFields.Aggregate((c, j) => string.Format("{0},{1}", c, j))));

                ////Alternate Price/Page/Image Fields
                //if (AlternatePriceFields != null && AlternatePriceFields.Any())
                //  settings.Add(new XElement("alternatePriceFields", AlternatePriceFields.Aggregate((c, j) => string.Format("{0},{1}", c, j))));
                //if (AlternatePageFields != null && AlternatePageFields.Any())
                //  settings.Add(new XElement("alternatePageFields", AlternatePageFields.Aggregate((c, j) => string.Format("{0},{1}", c, j))));
                //if (AlternateImageFields != null && AlternateImageFields.Any())
                //  settings.Add(new XElement("alternateImageFields", AlternateImageFields.Aggregate((c, j) => string.Format("{0},{1}", c, j))));

                //conditional rules
                settings.Add(new XElement("rulesEnabled", RulesEnabled));
                if (ExclusionRules != null && ExclusionRules.Any())
                {
                    var rules = new XElement("exclusionConditions");
                    foreach (var rule in ExclusionRules)
                    {
                        var c = new XElement("condition",
                                             new XAttribute("name", rule.Name),
                                             new XAttribute("comparison", rule.Comparison),
                                             new XAttribute("value", rule.Value),
                                             new XAttribute("fieldName", rule.QueryField)
                            );
                        rules.Add(c);
                    }
                    settings.Add(rules);
                }
                if (ExclusionSet != null)
                {
                    settings.Add(ExclusionSet.GetXml("exclusionSet"));
                }

                if (FilterRules != null && FilterRules.Any())
                {
                    var rules = new XElement("filterConditions");
                    foreach (var rule in FilterRules)
                    {
                        var c = new XElement("condition",
                                             new XAttribute("name", rule.Name),
                                             new XAttribute("comparison", rule.Comparison),
                                             new XAttribute("value", rule.Value),
                                             new XAttribute("fieldName", rule.QueryField)
                            );
                        rules.Add(c);
                    }
                    settings.Add(rules);
                }
                if (!string.IsNullOrEmpty(UniversalFilterName) && !UniversalFilterName.Equals("universal", StringComparison.OrdinalIgnoreCase))
                    settings.Add(new XElement("universalFilterName", UniversalFilterName));
                if (FilterTopSellers)
                    settings.Add(new XElement("filterTopSellers", "true"));

                if (FilterParsingRules != null && FilterParsingRules.Any())
                {
                    var rules = new XElement("filterParsingRules");
                    foreach (var group in FilterParsingRules)
                    {
                        var g = new XElement("parseGroup",
                                                                 new XAttribute("delimiter", group.Delimiter)
                            );
                        foreach (var rule in group.ParseRules)
                        {
                            XElement r;
                            if (rule.Expand)
                                r = new XElement("parseRule",
                                                                         new XAttribute("fromField", rule.FromField),
                                                                         new XAttribute("toField", rule.ToField),
                                                                         new XAttribute("regexMatch", rule.RegexMatch),
                                                                         new XAttribute("regexGroup", rule.RegexGroup),
                                                                         new XAttribute("expand", "true"),
                                                                         new XAttribute("modulo", rule.Modulo),
                                                                         new XAttribute("delimiter", rule.Delimiter),
                                                                         new XAttribute("format", rule.Format)
                                    );
                            else
                                r = new XElement("parseRule",
                                                                         new XAttribute("fromField", rule.FromField),
                                                                         new XAttribute("toField", rule.ToField),
                                                                         new XAttribute("regexMatch", rule.RegexMatch),
                                                                         new XAttribute("regexGroup", rule.RegexGroup)
                                    );
                            g.Add(r);
                        }
                        rules.Add(g);
                    }
                    settings.Add(rules);
                }

                if (FeaturedCrossSellRules != null && FeaturedCrossSellRules.Any())
                {
                    var rules = new XElement("featuredCrossSellConditions");
                    foreach (var rule in FeaturedCrossSellRules)
                    {
                        var c = new XElement("condition",
                                             new XAttribute("type", rule.Include ? "include" : "exclude"),
                                                                 new XAttribute("fieldName", rule.QueryField),
                                                                 new XAttribute("enabled", rule.Enabled)
                            );
                        rules.Add(c);
                    }
                    settings.Add(rules);
                }
                if (FeaturedUpSellRules != null && FeaturedUpSellRules.Any())
                {
                    var rules = new XElement("featuredUpSellConditions");
                    foreach (var rule in FeaturedUpSellRules)
                    {
                        var c = new XElement("condition",
                                             new XAttribute("type", rule.Include ? "include" : "exclude"),
                                                                 new XAttribute("fieldName", rule.QueryField),
                                                                 new XAttribute("enabled", rule.Enabled)
                            );
                        rules.Add(c);
                    }
                    settings.Add(rules);
                }
                if (FeaturedRules != null && FeaturedRules.Any())
                {
                    var rules = new XElement("featuredTopSellConditions");
                    foreach (var rule in FeaturedRules)
                    {
                        var c = new XElement("condition",
                                             new XAttribute("type", rule.Include ? "include" : "exclude"),
                                             new XAttribute("fieldName", rule.QueryField),
                                             new XAttribute("enabled", rule.Enabled)
                            );
                        rules.Add(c);
                    }
                    settings.Add(rules);
                }
                if (ReplacementRules != null && ReplacementRules.Any())
                {
                    var rules = new XElement("replacementConditions");
                    foreach (var rule in ReplacementRules)
                    {
                        var c = new XElement("condition",
                                             new XAttribute("name", rule.Name),
                                             new XAttribute("type", rule.Type.ToString()),
                                                                 new XAttribute("oldFieldName", rule.OldName),
                                                                 new XAttribute("newFieldName", rule.NewName)
                            );
                        rules.Add(c);
                    }
                    settings.Add(rules);
                }
                if (CategoryRules != null)
                {
                    var rules = new XElement("categoryConditions");
                    if (CategoryRules.OptimizationsExist)
                    {
                        foreach (var cat in CategoryRules.Optimizations)
                        {
                            var c = new XElement("condition",
                                                 new XAttribute("type", "ignore"),
                                                 new XAttribute("value", cat)
                                );
                            rules.Add(c);
                        }
                    }
                    if (CategoryRules.CrossCategoryExist)
                    {
                        foreach (var cat in CategoryRules.CrossSellCats)
                        {
                            var c = new XElement("condition",
                                                 new XAttribute("type", "crossSell"),
                                                 new XAttribute("value", cat)
                                );
                            rules.Add(c);
                        }
                    }
                    if (CategoryRules.ExclusionsExist)
                    {
                        foreach (var cat in CategoryRules.Exclusions)
                        {
                            var c = new XElement("condition",
                                                 new XAttribute("type", "exclude"),
                                                 new XAttribute("value", cat)
                                );
                            rules.Add(c);
                        }
                    }
                    if (CategoryRules.FiltersExist)
                    {
                        foreach (var filter in CategoryRules.Filters)
                        {
                            var c = new XElement("condition",
                                                 new XAttribute("type", "filter"),
                                                 new XAttribute("value", filter.CatId),
                                                 new XAttribute("groupId", filter.GroupId)
                                );
                            rules.Add(c);
                        }
                    }
                    if (CategoryRules.UniversalExist)
                    {
                        foreach (var cat in CategoryRules.Universals)
                        {
                            var c = new XElement("condition",
                                                 new XAttribute("type", "universal"),
                                                 new XAttribute("value", cat)
                                );
                            rules.Add(c);
                        }
                    }
                    if (rules.Descendants().Any())
                        settings.Add(rules);
                }
                //upload timers
                if (ExtractorSchedules != null && ExtractorSchedules.Any())
                {
                    foreach (var timer in ExtractorSchedules)
                    {
                        var t = new XElement("updateTimer",
                                                                 new XAttribute("enabled", timer.Enabled),
                                                                 new XAttribute("extractType", timer.ExtractType),
                                                                 new XAttribute("rate", timer.Rate)
                            );
                        if (timer.Rate != ExtractorSchedule.ExtractRate.Hourly)
                        {
                            t.Add(new XAttribute("hourOfDay", timer.HourOfDay));
                            if (timer.Rate == ExtractorSchedule.ExtractRate.Weekly)
                                t.Add(new XAttribute("dayOfWeek", timer.DayOfWeek));
                            else if (timer.Rate == ExtractorSchedule.ExtractRate.Monthly)
                            {
                                t.Add(new XAttribute("dayOfWeek", timer.DayOfWeek));
                                t.Add(new XAttribute("dayOfMonth", timer.DayOfMonth));
                            }
                        }
                        settings.Add(t);
                    }
                }

                //Exclusion Stats
                if (ExclusionStats != null && ExclusionStats.Any())
                {
                    var stats = new XElement("exclusionStats");
                    foreach (var es in ExclusionStats)
                    {
                        var s = new XElement("stat",
                                                                    new XAttribute("name", es.Key),
                                                                    new XAttribute("value", es.Value)
                            );
                        stats.Add(s);
                    }
                    settings.Add(stats);
                }
                if (Fields != null) Fields.SaveSettings(ref settings);

                ClientData.Instance.SaveSiteRules(Alias, settings, this, wc);
            }
            catch (Exception ex)
            {
                if (BoostLog.Instance != null)
                    BoostLog.Instance.WriteEntry(EventLogEntryType.Error, "Error in SaveSettings", ex, Alias);
            }
        }
        public WebContextProxy GetContextOfRequest()
		{
			var wc = new WebContextProxy();
			var context = OperationContext.Current;
			if (context == null) return wc;
			//Message msg = OperationContext.Current.RequestContext.RequestMess  age.CreateBufferedCopy(Int32.MaxValue).CreateMessage();
			var messageProperties = context.IncomingMessageProperties;
			if (messageProperties == null) return wc;

			try
			{
				var via = messageProperties.Via;
				if (via != null)
				{
					wc.Parameters = via.Query;
					wc.Operation = via.LocalPath;
				}
			}
			catch { }

			try
			{
				object request;
				if (messageProperties.TryGetValue("httpRequest", out request))
				{
					var msgProperty = (HttpRequestMessageProperty)request;
					wc.Parameters = msgProperty.QueryString;
					wc.Verb = msgProperty.Method;
					wc.ContentType = msgProperty.Headers["Content-Type"]; //need to store this separately from other headers so it can be set
					wc.Headers = new Dictionary<string,string>();
					for (var i = 0; i < msgProperty.Headers.Count; i++)
						wc.Headers.Add(msgProperty.Headers.GetKey(i), msgProperty.Headers.Get(i));

#if GOGRID
				var ip = msgProperty.Headers["X-Forwarded-For"];
				if (!string.IsNullOrEmpty(ip))
					wc.IP = "request." + ip;
			}
			if (string.IsNullOrEmpty(wc.IP))
			//not sure if this is ever needed
			{
				var webContext = WebOperationContext.Current;
				if (webContext != null)
				{
					var webRequest = webContext.IncomingRequest;
					if (webRequest != null)
					{
						wc.Verb = webRequest.Method;
						var ip = webRequest.Headers["X-Forwarded-For"];
						if (!string.IsNullOrEmpty(ip))
							wc.IP = "webRequest." + ip;
					}
				}
			}

			//if not forwarded through a loadbalancer, then treat as an internal call (from a replicated server)
			if (string.IsNullOrEmpty(wc.IP))
#else
				}
#endif

				{
					object endpointProperty;
					if (messageProperties.TryGetValue(RemoteEndpointMessageProperty.Name, out endpointProperty))
					{
						wc.IP = ((RemoteEndpointMessageProperty)endpointProperty).Address;
						wc.IsInternal = Replicator.Instance != null && Replicator.Instance.IsInternal(wc.IP);
						if (wc.IsInternal) wc.IP = "internal." + wc.IP;
					}
					if (string.IsNullOrEmpty(wc.ContentType) && WebOperationContext.Current != null)
					//NOTE: WebOperationContext not OperationContext
					{
						wc.ContentType = WebOperationContext.Current.OutgoingResponse.Format == WebMessageFormat.Xml
															 ? "text/xml"
															 : "application/json";
					}
				}
			}
 public void QueueSettings(bool ruleChange = true)
 {
     var wc = new WebContextProxy();
     #if WEB
     var wh = new WebHelper();
     wc = wh.GetContextOfRequest();
     #endif
     Task.Factory.StartNew(() => SaveSettings(wc, ruleChange));
 }