/// <summary>
        /// Creates an AdWords Campaign grouped by category
        /// </summary>
        /// <param name="UseSandbox">Call the webservices in the test env</param>
        /// <param name="AffiliateSiteRefId"></param>
        /// <param name="Name">Campaign Name</param>
        /// <param name="Countries">Targeted countires</param>
        /// <param name="Languages">Targeted Languages</param>
        /// <param name="BudgetPeriod">The duration over which to spend the budgetAmount. For most developers, Daily is the only allowable option.</param>
        /// <param name="BudgetAmount">The amount of the budget in micros. Use budgetPeriod to set the duration over which to spend this amount.</param>
        /// <param name="KeywordMaxCpc">The default maximum cost-per-click bid for Keyword criteria in this ad group. See the note on bid amounts for more information on using this field.</param>
        /// <param name="MaxAdsPerGroup">Max Ads to create for each AdGroup</param>
        /// <param name="MaxAdvertiserCompetitionScale">The Max level of competition allowed from advertisers for keyword variations, on a scale from 0 to 5. Set to -1 if data is not available</param>
        /// <param name="MinSearchVolumeScale">The Min amount of searches to allowed related to keyword variations, on a scale from 0 to 5. Set to -1 if data is not available</param>
        /// <param name="DisplayUrl">Display Url to use for each Ad</param>
        /// <param name="destinationUrlPrefix">Destination Url Prefix for the destination Url of the Ads created.</param>
        /// <param name="UseKeywordVariations">Check for Keyword variations</param>
        /// <param name="MaxVariations">Max number of Keyword variations to use.</param>
        /// <param name="AdKeywordType">The type of keyword, indicating how it is targeted. This is not mutable after being set the first time. Values are: Broad=0,Phrase=1,Exact=2</param>
        //public void CreateCampaignGroupByProduct(bool UseSandbox, Guid AffiliateSiteRefId, string Name, String[] Countries, String[] Languages, int BudgetPeriod,
        //                                        Moneyv200906 BudgetAmount, long KeywordMaxCpc, int MaxAdGroups, int MaxAdvertiserCompetitionScale, int MinSearchVolumeScale,
        //                                        string DisplayUrl, string destinationUrlPrefix, bool GetKeywordsFromLandingPage, int MaxVariations, int AdKeywordType)
        //{
        //    // Create a user (reads headers from App.config file).
        //    AdWordsUser user = new AdWordsUser();
        //    if (UseSandbox)
        //        user.UseSandbox();	// use sandbox
        //    AccountService accountService = (AccountService)user.GetService(ApiServices.v13.AccountService);
        //    string[] accounts = accountService.getClientAccounts();
        //    try
        //    {
        //        #region Create Campaign
        //        // Create a new campaign with an ad group.  First create a
        //        // campaign, so we can get its id.
        //        Campaignv200906 newCampaign = new Campaignv200906();
        //        newCampaign.budget.amount = BudgetAmount;
        //        //newCampaign.budget.amountSpecified = true;
        //        newCampaign.budget.period = (BudgetPeriodv200906)Enum.ToObject(typeof(BudgetPeriodv200906), BudgetPeriod);
        //        newCampaign.budget.periodSpecified = true;
        //        // The campaign name is optional.  An error results if a campaign
        //        // of the same name already exists.
        //        newCampaign.name = Name;
        //        //TODO:newCampaign.networkTargeting = new NetworkType[] { NetworkType.SearchNetwork };
        //        // Target the campaign at
        //        CampaignServicev200906 campaignService = (CampaignServicev200906)user.GetService(ApiServices.v200906.CampaignService);
        //        // Set the campaign status to paused, we don't want to start
        //        // paying for this test.
        //        newCampaign.status = CampaignStatusv200906.PAUSED;
        //        // Add this campaign.  The campaign object is returned with ids
        //        // filled in.
        //        // Define an Add operation to add the campaign.
        //        CampaignOperation campaignOperation = new CampaignOperation();
        //        campaignOperation.operatorSpecified = true;
        //        campaignOperation.@operator = CampaignOperatorv200906.ADD;
        //        campaignOperation.operand = newCampaign;
        //        try
        //        {
        //            CampaignReturnValue results =
        //              campaignService.mutate(new CampaignOperation[] { campaignOperation });
        //            if (results != null && results.value != null && results.value.Length > 0)
        //            {
        //                Trace.TraceInformation("New campaign with name = \"{0}\" and id = " + "\"{1}\" was created.", results.value[0].name, results.value[0].id);
        //            }
        //        }
        //        catch (Exception ex)
        //        {
        //            throw new Exception("Failed to create campaign. " + ex.Message);
        //        }
        //        long campaignId = newCampaign.id;
        //        #endregion
        //        #region Targeting
        //        CampaignTargetServicev200906 service = (CampaignTargetServicev200906)user.GetService(ApiServices.v200906.CampaignTargetService);
        //        // Create a language target - for English language.
        //        LanguageTargetv200906 languageTarget = new LanguageTargetv200906();
        //        languageTarget.languageCode = "en";
        //        LanguageTargetList languageTargetList = new LanguageTargetList();
        //        languageTargetList.targets = new LanguageTargetv200906[] { languageTarget };
        //        languageTargetList.campaignId = campaignId;
        //        languageTargetList.campaignIdSpecified = true;
        //        // Create a country target - include US, exclude metrocode 743.
        //        CountryTargetv200906 countryTarget = new CountryTargetv200906();
        //        countryTarget.countryCode = "US";
        //        countryTarget.excludedSpecified = true;
        //        countryTarget.excluded = false;
        //        MetroTargetv200906 metroTarget = new MetroTargetv200906();
        //        metroTarget.excludedSpecified = true;
        //        metroTarget.excluded = true;
        //        metroTarget.metroCode = "743";
        //        GeoTargetList geoTargetList = new GeoTargetList();
        //        geoTargetList.targets = new GeoTargetv200906[] { countryTarget, metroTarget };
        //        geoTargetList.campaignId = campaignId;
        //        geoTargetList.campaignIdSpecified = true;
        //        // Create a network target - Google Search.
        //        NetworkTargetv200906 networkTarget1 = new NetworkTargetv200906();
        //        networkTarget1.networkCoverageTypeSpecified = true;
        //        networkTarget1.networkCoverageType = NetworkCoverageTypev200906.GOOGLE_SEARCH;
        //        NetworkTargetv200906 networkTarget2 = new NetworkTargetv200906();
        //        networkTarget2.networkCoverageTypeSpecified = true;
        //        networkTarget2.networkCoverageType = NetworkCoverageTypev200906.SEARCH_NETWORK;
        //        NetworkTargetList networkTargetList = new NetworkTargetList();
        //        networkTargetList.targets = new NetworkTargetv200906[] { networkTarget1, networkTarget2 };
        //        networkTargetList.campaignId = campaignId;
        //        networkTargetList.campaignIdSpecified = true;
        //        TargetList[] targets =
        //            new TargetList[] { languageTargetList, geoTargetList, networkTargetList };
        //        ArrayList campaignTargetOperations = new ArrayList();
        //        foreach (TargetList target in targets)
        //        {
        //            CampaignTargetOperation ops = new CampaignTargetOperation();
        //            ops.operatorSpecified = true;
        //            ops.@operator = CampaignTargetOperatorv200906.SET;
        //            ops.operand = target;
        //            campaignTargetOperations.Add(ops);
        //        }
        //        try
        //        {
        //            service.mutate((CampaignTargetOperation[])
        //              campaignTargetOperations.ToArray(typeof(CampaignTargetOperation)));
        //            Console.WriteLine("Geo, language, and network targeting were " +
        //                "successfully added to campaign id = \"{0}\".", campaignId);
        //        }
        //        catch (Exception ex)
        //        {
        //            Console.WriteLine("Failed to create campaign targeting. " +
        //                "Exception says \"{0}\"", ex.Message);
        //        }
        //        #endregion
        //        #region Create your Services
        //        //create your services
        //        List<SeedKeyword> keywords = new List<SeedKeyword>();
        //        AdService adService = (AdService)user.GetService(ApiServices.v200906.AdGroupAdService);
        //        KeywordToolService keywordToolService = (KeywordToolService)user.GetService(ApiServices.v13.KeywordToolService);
        //        AdGroupService adgroupService = (AdGroupService)user.GetService(ApiServices.v200906.AdGroupService);
        //        TrafficEstimatorService trafficEstimatorService = (TrafficEstimatorService)user.GetService(ApiServices.v13.TrafficEstimatorService);
        //        #endregion
        //        #region Enumerate thru all the categories
        //        //enumerate thru all the categories
        //        foreach (SiteCategory siteCategory in DataRepository.SiteCategoryProvider.GetByAffiliateSiteRefId(AffiliateSiteRefId))
        //        {
        //            int GroupAdCount = 0;
        //            DataRepository.SiteCategoryProvider.DeepLoad(siteCategory, true, DeepLoadType.IncludeChildren, typeof(TList<SiteCategoryCategoryMapping>));
        //            //////Create an ad group by site category
        //            ////AdGroup newAdGroup = new AdGroup();
        //            ////newAdGroup.name = siteCategory.SiteCategory;
        //            ////newAdGroup.keywordMaxCpc = KeywordMaxCpc;
        //            ////newAdGroup.keywordMaxCpcSpecified = true;
        //            ////// Associate this ad group with the newly created campaign.  Send
        //            ////// the request to add the new ad group.
        //            ////AdGroup myAdGroup = adgroupService.addAdGroup(campaignId, newAdGroup);
        //            ////long adGroupId = myAdGroup.id;
        //            #region Enumerate thru the category mappings to get the merchants
        //            //enumerate thru the categoru mappings to get the merchants
        //            foreach (SiteCategoryCategoryMapping catMap in siteCategory.SiteCategoryCategoryMappingCollection)
        //            {
        //                if (GroupAdCount >= MaxAdGroups)
        //                    break;
        //                DataRepository.SiteCategoryCategoryMappingProvider.DeepLoad(catMap, true, DeepLoadType.IncludeChildren, typeof(Category));
        //                DataRepository.CategoryProvider.DeepLoad(catMap.CategoryRefIdSource, true, DeepLoadType.IncludeChildren, typeof(TList<Merchant>));
        //                catMap.CategoryRefIdSource.MerchantCollection.Shuffle();
        //                foreach (Merchant merch in catMap.CategoryRefIdSource.MerchantCollection)
        //                {
        //                    if (GroupAdCount >= MaxAdGroups)
        //                        break;
        //                    DataRepository.MerchantProvider.DeepLoad(merch, true, DeepLoadType.IncludeChildren, typeof(TList<Product>));
        //                    //shuffle the products
        //                    merch.ProductCollection.Shuffle();
        //                    // enumerate thru all the merchant's products
        //                    foreach (Product prod in merch.ProductCollection)
        //                    {
        //                        //Create an ad group by site category
        //                        AdGroup newAdGroup = new AdGroup();
        //                        newAdGroup.name = siteCategory.Name + "-" + prod.Name;
        //                        newAdGroup.keywordMaxCpc = KeywordMaxCpc;
        //                        newAdGroup.keywordMaxCpcSpecified = true;
        //                        Trace.TraceInformation(prod.Name);
        //                        string cleanProdName = StringUtils.ScrubProdName(StringUtils.RemoveDuplicateWords(prod.Name));
        //                        string urlProdName = StringUtils.ScrubProdNameUrl(cleanProdName) + ".aspx";
        //                        int c = 0;
        //                        keywords.Clear();
        //                        string[] rawKeywords = new string[] { "" };
        //                        //check to see if the product record has keywords
        //                        //if (prod.Keywords != null)
        //                        //    rawKeywords = prod.Keywords.Split(',');
        //                        //if (rawKeywords.Length < 2)
        //                        rawKeywords = cleanProdName.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
        //                        foreach (string str in rawKeywords)
        //                        {
        //                            int tryInt = 0; //not empty, not a number, and not lower case
        //                            if (str.Trim() != "" && !int.TryParse(str.Trim(), out tryInt)) //&& !isLowerCase(str.Trim().Substring(0, 1).ToCharArray()[0])
        //                            {
        //                                SeedKeyword sw = new SeedKeyword();
        //                                sw.text = StringUtils.ScrubKeywords(str);
        //                                if (sw.text.Trim() != "")
        //                                {
        //                                    sw.type = (KeywordType)Enum.ToObject(typeof(KeywordType), AdKeywordType);
        //                                    sw.negative = false;
        //                                    keywords.Add(sw);
        //                                    c++;
        //                                    if (c == 10) //TODO: fix this to get all words
        //                                        break;
        //                                }
        //                            }
        //                        }
        //                        //Create an add for each product
        //                        //
        //                        // IMPORTANT: create an ad before adding keywords!  Else the
        //                        // minCpc will have a higher value.
        //                        TextAd newTextAd = new TextAd();
        //                        newTextAd.headline = prod.Name;
        //                        while (newTextAd.headline.Length > 25)
        //                        {
        //                            newTextAd.headline = newTextAd.headline.Substring(0, newTextAd.headline.LastIndexOf(" ")).Substring(0, newTextAd.headline.Substring(0, newTextAd.headline.LastIndexOf(" ")).LastIndexOf(" "));
        //                        }
        //                        if (prod.Description.Length > 35)
        //                        {
        //                            string[] words = prod.Description.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
        //                            //descriptions are limited to 35 chars
        //                            foreach (string wrd in words)
        //                            {
        //                                string word = StringUtils.ScrubKeywords(wrd);
        //                                if (word.Trim() != "")
        //                                {
        //                                    if (newTextAd.description1 == null || (newTextAd.description1.Length + word.Length) < 35)
        //                                        newTextAd.description1 += word + " ";
        //                                    else if (newTextAd.description2 == null || (newTextAd.description2.Length + word.Length) < 35)
        //                                    {
        //                                        newTextAd.description1 = newTextAd.description1.PadRight(35);
        //                                        newTextAd.description2 += word + " ";
        //                                    }
        //                                    else
        //                                    {
        //                                        newTextAd.description2 = newTextAd.description2.PadRight(35);
        //                                        break;
        //                                    }
        //                                }
        //                            }
        //                            if (newTextAd.description2 == null || (newTextAd.description2.Length + string.Format("{0:c}", prod.Price).Length) < 35)
        //                                newTextAd.description2 += string.Format("{0:c}", prod.Price);
        //                        }
        //                        else
        //                        {
        //                            newTextAd.description1 = prod.Description;
        //                            newTextAd.description2 = string.Format("{0:c}", prod.Price);
        //                        }
        //                        newTextAd.displayUrl = DisplayUrl;
        //                        newTextAd.destinationUrl = destinationUrlPrefix + siteCategory.PageUrl.Substring(2, siteCategory.PageUrl.IndexOf(".") - 2) + "__" + urlProdName;
        //                        //newTextAd.adGroupId = adGroupId;
        //                        //don't add it yet, there is a check below to see if it meets criteria
        //                        SeedKeyword[] keywordsArray = new SeedKeyword[] { new SeedKeyword() };
        //                        keywordsArray = keywords.ToArray();
        //                        //add variations if requested
        //                        if (GetKeywordsFromLandingPage)
        //                        {
        //                            SiteKeywordGroups siteKeywordGroups = keywordToolService.getKeywordsFromSite(newTextAd.destinationUrl, false, Languages, Countries);
        //                            int maxVariations = 0;
        //                            bool AdAdded = false;
        //                            // Associate this ad group with the newly created campaign.  Send
        //                            // the request to add the new ad group.
        //                            AdGroup myAdGroup; //= adgroupService.addAdGroup(campaignId, newAdGroup);
        //                            long adGroupId = 0; //= myAdGroup.id;
        //                            if (siteKeywordGroups.keywords != null)
        //                            {
        //                                foreach (SiteKeyword sitekeyword in siteKeywordGroups.keywords)
        //                                {
        //                                    //Trace.TraceInformation("Checking Site Keyword " + maxVariations + ":" + sitekeyword.text);
        //                                    // check for low compitition and high search volumes
        //                                    if (sitekeyword.advertiserCompetitionScale <= MaxAdvertiserCompetitionScale && sitekeyword.lastMonthSearchVolume >= MinSearchVolumeScale)
        //                                    {
        //                                        // Add keywords to the newly created ad group.
        //                                        //add keywords and url to dbs
        //                                        AffiliTrac.Entities.Keywords kws = new AffiliTrac.Entities.Keywords();
        //                                        kws.KeywordRefId = Guid.NewGuid();
        //                                        kws.Keywords = sitekeyword.text;
        //                                        kws.Url = newTextAd.destinationUrl;
        //                                        kws.SiteCategoryRefId = siteCategory.SiteCategoryRefId;
        //                                        DataRepository.KeywordsProvider.Insert(kws);
        //                                        CriterionService criterionService = (CriterionService)user.GetService(ApiServices.v200906.CampaignCriterionService);
        //                                        // check for low compitition and high search volumes
        //                                        #region Create Ad & Keywords from the Product Name
        //                                        if (!AdAdded)
        //                                        {
        //                                            // Associate this ad group with the newly created campaign.  Send
        //                                            // the request to add the new ad group.
        //                                            myAdGroup = adgroupService.addAdGroup(campaignId, newAdGroup);
        //                                            adGroupId = myAdGroup.id;
        //                                            newTextAd.adGroupId = adGroupId;
        //                                            // create the new add
        //                                            try
        //                                            {
        //                                                //we found a keyword that meets criteria so ad the new Ad.
        //                                                Ad[] myAds = adService.addAds(new Ad[] { newTextAd });
        //                                                GroupAdCount++;
        //                                                Trace.TraceInformation("Text ad" + GroupAdCount + ": " + newTextAd.headline + " Text Line1:" + newTextAd.description1 + " Text Line2:" + newTextAd.description2);
        //                                                //Trace.TraceInformation("Text ad: " + newTextAd.headline + " Text Line1:" + newTextAd.description1 + " Text Line2:" + newTextAd.description2);
        //                                                AdAdded = true;
        //                                            }
        //                                            catch
        //                                            {
        //                                                //do nothing
        //                                                Trace.TraceError("***Text ad Failed:" + newTextAd.headline + " Text Line1:" + newTextAd.description1 + " Text Line2:" + newTextAd.description2);
        //                                            }
        //                                            //Add the Product name as a whole phrase
        //                                            try
        //                                            {
        //                                                //add keywords and url to dbs
        //                                                kws = new AffiliTrac.Entities.Keywords();
        //                                                kws.KeywordRefId = Guid.NewGuid();
        //                                                kws.Keywords = cleanProdName;
        //                                                kws.Url = newTextAd.destinationUrl;
        //                                                kws.SiteCategoryRefId = siteCategory.SiteCategoryRefId;
        //                                                DataRepository.KeywordsProvider.Insert(kws);
        //                                                Keyword newKeyword = new Keyword();
        //                                                newKeyword.adGroupId = adGroupId;
        //                                                newKeyword.type = (KeywordType)Enum.ToObject(typeof(KeywordType), AdKeywordType);
        //                                                newKeyword.text = cleanProdName;
        //                                                //TODO: Use the Traffic Estimator to determine the
        //                                                // the maxCpc to use
        //                                                newKeyword.maxCpc = KeywordMaxCpc;
        //                                                newKeyword.maxCpcSpecified = true;
        //                                                newKeyword.criterionType = CriterionType.Keyword;
        //                                                newKeyword.destinationUrl = destinationUrlPrefix + siteCategory.PageUrl.Substring(2, siteCategory.PageUrl.IndexOf(".") - 2) + "__" + urlProdName;
        //                                                Criterion[] newCriteria = new Criterion[] { newKeyword };
        //                                                newCriteria[0].destinationUrl = newKeyword.destinationUrl;
        //                                                criterionService.addCriteria(newCriteria);
        //                                            }
        //                                            catch
        //                                            {
        //                                                //do nothing
        //                                                Trace.TraceError("***Add Criteria Failed: Keyword" + cleanProdName);
        //                                            }
        //                                            //Add the individual product name keywords
        //                                            foreach (SeedKeyword sk in keywordsArray)
        //                                            {
        //                                                try
        //                                                {
        //                                                    //add keywords and url to dbs
        //                                                    kws = new AffiliTrac.Entities.Keywords();
        //                                                    kws.KeywordRefId = Guid.NewGuid();
        //                                                    kws.Keywords = sk.text;
        //                                                    kws.Url = newTextAd.destinationUrl;
        //                                                    kws.SiteCategoryRefId = siteCategory.SiteCategoryRefId;
        //                                                    DataRepository.KeywordsProvider.Insert(kws);
        //                                                    // Add keywords to the newly created ad group.
        //                                                    Keyword newKeyword = new Keyword();
        //                                                    newKeyword.adGroupId = adGroupId;
        //                                                    newKeyword.type = (KeywordType)Enum.ToObject(typeof(KeywordType), AdKeywordType);
        //                                                    newKeyword.text = sk.text;
        //                                                    //TODO: Use the Traffic Estimator to determine the
        //                                                    // the maxCpc to use
        //                                                    newKeyword.maxCpc = KeywordMaxCpc;
        //                                                    newKeyword.maxCpcSpecified = true;
        //                                                    newKeyword.criterionType = CriterionType.Keyword;
        //                                                    newKeyword.destinationUrl = destinationUrlPrefix + siteCategory.PageUrl.Substring(2, siteCategory.PageUrl.IndexOf(".") - 2) + "__" + urlProdName;
        //                                                    Criterion[] newCriteria = new Criterion[] { newKeyword };
        //                                                    newCriteria[0].destinationUrl = newKeyword.destinationUrl;
        //                                                    criterionService.addCriteria(newCriteria);
        //                                                }
        //                                                catch
        //                                                {
        //                                                    //do nothing
        //                                                    Trace.TraceError("***Add Criteria Failed: Keyword" + sk.text);
        //                                                }
        //                                            }
        //                                        }
        //                                        #endregion
        //                                        #region Create keywords from the keyword suggestion gotten from the landing page
        //                                        try
        //                                        {
        //                                            Keyword newKeyword = new Keyword();
        //                                            newKeyword = new Keyword();
        //                                            newKeyword.adGroupId = adGroupId;
        //                                            newKeyword.type = (KeywordType)Enum.ToObject(typeof(KeywordType), AdKeywordType);
        //                                            newKeyword.text = sitekeyword.text;
        //                                            //TODO: Use the Traffic Estimator to determine the
        //                                            // the maxCpc to use
        //                                            newKeyword.maxCpc = KeywordMaxCpc;
        //                                            newKeyword.maxCpcSpecified = true;
        //                                            newKeyword.criterionType = CriterionType.Keyword;
        //                                            newKeyword.destinationUrl = destinationUrlPrefix + siteCategory.PageUrl.Substring(2, siteCategory.PageUrl.IndexOf(".") - 2) + "__" + urlProdName;
        //                                            Criterion[] newCriteria = new Criterion[] { newKeyword };
        //                                            newCriteria[0].destinationUrl = newKeyword.destinationUrl;
        //                                            criterionService.addCriteria(newCriteria);
        //                                        }
        //                                        catch
        //                                        {
        //                                            //do nothing
        //                                            Trace.TraceError("***Add Criteria Failed: Keyword" + sitekeyword.text);
        //                                        }
        //                                        #endregion
        //                                    }
        //                                    maxVariations++;
        //                                    if (maxVariations > MaxVariations)
        //                                        break;
        //                                }
        //                            }
        //                            //check add variations for product name raw keywords
        //                            try
        //                            {
        //                                KeywordVariations keywordVariations = keywordToolService.getKeywordVariations(keywordsArray, true, Languages, Countries);
        //                                foreach (KeywordVariation keywordVariation in keywordVariations.moreSpecific)
        //                                {
        //                                    if (Languages[0].ToString() == keywordVariation.language && keywordVariation.advertiserCompetitionScale <= MaxAdvertiserCompetitionScale && keywordVariation.lastMonthSearchVolume >= MinSearchVolumeScale)
        //                                    {
        //                                        // Add keywords to the newly created ad group.
        //                                        //add keywords and url to dbs
        //                                        AffiliTrac.Entities.Keywords kws = new AffiliTrac.Entities.Keywords();
        //                                        kws.KeywordRefId = Guid.NewGuid();
        //                                        kws.Keywords = keywordVariation.text;
        //                                        kws.Url = newTextAd.destinationUrl;
        //                                        kws.SiteCategoryRefId = siteCategory.SiteCategoryRefId;
        //                                        DataRepository.KeywordsProvider.Insert(kws);
        //                                        CriterionService criterionService = (CriterionService)user.GetService(ApiServices.v200906.CampaignCriterionService);
        //                                        // check for low compitition and high search volumes
        //                                        #region Create Ad & Keywords from the Product Name
        //                                        if (!AdAdded)
        //                                        {
        //                                            // Associate this ad group with the newly created campaign.  Send
        //                                            // the request to add the new ad group.
        //                                            myAdGroup = adgroupService.addAdGroup(campaignId, newAdGroup);
        //                                            adGroupId = myAdGroup.id;
        //                                            newTextAd.adGroupId = adGroupId;
        //                                            // create the new add
        //                                            try
        //                                            {
        //                                                //we found a keyword that meets criteria so ad the new Ad.
        //                                                Ad[] myAds = adService.addAds(new Ad[] { newTextAd });
        //                                                GroupAdCount++;
        //                                                Trace.TraceInformation("Text ad" + GroupAdCount + ": " + newTextAd.headline + " Text Line1:" + newTextAd.description1 + " Text Line2:" + newTextAd.description2);
        //                                                //Trace.TraceInformation("Text ad: " + newTextAd.headline + " Text Line1:" + newTextAd.description1 + " Text Line2:" + newTextAd.description2);
        //                                                AdAdded = true;
        //                                            }
        //                                            catch
        //                                            {
        //                                                //do nothing
        //                                                Trace.TraceError("***Text ad Failed:" + newTextAd.headline + " Text Line1:" + newTextAd.description1 + " Text Line2:" + newTextAd.description2);
        //                                            }
        //                                            //Add the Product name as a whole phrase
        //                                            try
        //                                            {
        //                                                //add keywords and url to dbs
        //                                                kws = new AffiliTrac.Entities.Keywords();
        //                                                kws.KeywordRefId = Guid.NewGuid();
        //                                                kws.Keywords = cleanProdName;
        //                                                kws.Url = newTextAd.destinationUrl;
        //                                                kws.SiteCategoryRefId = siteCategory.SiteCategoryRefId;
        //                                                DataRepository.KeywordsProvider.Insert(kws);
        //                                                Keyword newKeyword = new Keyword();
        //                                                newKeyword.adGroupId = adGroupId;
        //                                                newKeyword.type = (KeywordType)Enum.ToObject(typeof(KeywordType), AdKeywordType);
        //                                                newKeyword.text = cleanProdName;
        //                                                //TODO: Use the Traffic Estimator to determine the
        //                                                // the maxCpc to use
        //                                                newKeyword.maxCpc = KeywordMaxCpc;
        //                                                newKeyword.maxCpcSpecified = true;
        //                                                newKeyword.criterionType = CriterionType.Keyword;
        //                                                newKeyword.destinationUrl = destinationUrlPrefix + siteCategory.PageUrl.Substring(2, siteCategory.PageUrl.IndexOf(".") - 2) + "__" + urlProdName;
        //                                                Criterion[] newCriteria = new Criterion[] { newKeyword };
        //                                                newCriteria[0].destinationUrl = newKeyword.destinationUrl;
        //                                                criterionService.addCriteria(newCriteria);
        //                                            }
        //                                            catch (Exception ex)
        //                                            {
        //                                                //do nothing
        //                                                Trace.TraceError("***Add Criteria Failed: Keyword" + cleanProdName + ex.Message);
        //                                            }
        //                                            //Add the individual product name keywords
        //                                            foreach (SeedKeyword sk in keywordsArray)
        //                                            {
        //                                                try
        //                                                {
        //                                                    //add keywords and url to dbs
        //                                                    kws = new AffiliTrac.Entities.Keywords();
        //                                                    kws.KeywordRefId = Guid.NewGuid();
        //                                                    kws.Keywords = sk.text;
        //                                                    kws.Url = newTextAd.destinationUrl;
        //                                                    kws.SiteCategoryRefId = siteCategory.SiteCategoryRefId;
        //                                                    DataRepository.KeywordsProvider.Insert(kws);
        //                                                    // Add keywords to the newly created ad group.
        //                                                    Keyword newKeyword = new Keyword();
        //                                                    newKeyword.adGroupId = adGroupId;
        //                                                    newKeyword.type = (KeywordType)Enum.ToObject(typeof(KeywordType), AdKeywordType);
        //                                                    newKeyword.text = sk.text;
        //                                                    //TODO: Use the Traffic Estimator to determine the
        //                                                    // the maxCpc to use
        //                                                    newKeyword.maxCpc = KeywordMaxCpc;
        //                                                    newKeyword.maxCpcSpecified = true;
        //                                                    newKeyword.criterionType = CriterionType.Keyword;
        //                                                    newKeyword.destinationUrl = destinationUrlPrefix + siteCategory.PageUrl.Substring(2, siteCategory.PageUrl.IndexOf(".") - 2) + "__" + urlProdName;
        //                                                    Criterion[] newCriteria = new Criterion[] { newKeyword };
        //                                                    newCriteria[0].destinationUrl = newKeyword.destinationUrl;
        //                                                    criterionService.addCriteria(newCriteria);
        //                                                }
        //                                                catch (Exception ex)
        //                                                {
        //                                                    //do nothing
        //                                                    Trace.TraceError("***Add Criteria Failed: Keyword" + cleanProdName + ex.Message);
        //                                                }
        //                                            }
        //                                        }
        //                                        #endregion
        //                                        #region Create keywords from the keyword suggestion gotten from the landing page
        //                                        try
        //                                        {
        //                                            Keyword newKeyword = new Keyword();
        //                                            newKeyword = new Keyword();
        //                                            newKeyword.adGroupId = adGroupId;
        //                                            newKeyword.type = (KeywordType)Enum.ToObject(typeof(KeywordType), AdKeywordType);
        //                                            newKeyword.text = keywordVariation.text;
        //                                            //TODO: Use the Traffic Estimator to determine the
        //                                            // the maxCpc to use
        //                                            newKeyword.maxCpc = KeywordMaxCpc;
        //                                            newKeyword.maxCpcSpecified = true;
        //                                            newKeyword.criterionType = CriterionType.Keyword;
        //                                            newKeyword.destinationUrl = destinationUrlPrefix + siteCategory.PageUrl.Substring(2, siteCategory.PageUrl.IndexOf(".") - 2) + "__" + urlProdName;
        //                                            Criterion[] newCriteria = new Criterion[] { newKeyword };
        //                                            newCriteria[0].destinationUrl = newKeyword.destinationUrl;
        //                                            criterionService.addCriteria(newCriteria);
        //                                        }
        //                                        catch (Exception ex)
        //                                        {
        //                                            //do nothing
        //                                            Trace.TraceError("***Add Criteria Failed: Keyword" + cleanProdName + ex.Message);
        //                                        }
        //                                        #endregion
        //                                    }
        //                                }
        //                            }
        //                            catch
        //                            {//this call fails quite a bit so we need the try catch
        //                            }
        //                        }
        //                        else
        //                        {
        //                            #region Create Keywords from the Product Name Only
        //                            //  create the ad
        //                            // Associate this ad group with the newly created campaign.  Send
        //                            // the request to add the new ad group.
        //                            AdGroup myAdGroup = adgroupService.addAdGroup(campaignId, newAdGroup);
        //                            long adGroupId = myAdGroup.id;
        //                            newTextAd.adGroupId = adGroupId;
        //                            try
        //                            {
        //                                //we found a keyword that meets criteria so ad the new Ad.
        //                                Ad[] myAds = adService.addAds(new Ad[] { newTextAd });
        //                                GroupAdCount++;
        //                                Trace.TraceInformation("Text ad" + GroupAdCount + ": " + newTextAd.headline + " Text Line1:" + newTextAd.description1 + " Text Line2:" + newTextAd.description2);
        //                                //Trace.TraceInformation("Text ad: " + newTextAd.headline + " Text Line1:" + newTextAd.description1 + " Text Line2:" + newTextAd.description2);
        //                            }
        //                            catch
        //                            {
        //                                //do nothing
        //                                Trace.TraceError("***Text ad Failed:" + newTextAd.headline + " Text Line1:" + newTextAd.description1 + " Text Line2:" + newTextAd.description2);
        //                            }
        //                            //Add the Product name as a whole phrase
        //                            CriterionService criterionService = (CriterionService)user.GetService(ApiServices.v200906.CampaignCriterionService);
        //                            //add keywords and url to dbs
        //                            AffiliTrac.Entities.Keywords kws = new AffiliTrac.Entities.Keywords();
        //                            kws.KeywordRefId = Guid.NewGuid();
        //                            kws.Keywords = cleanProdName;
        //                            kws.Url = newTextAd.destinationUrl;
        //                            kws.SiteCategoryRefId = siteCategory.SiteCategoryRefId;
        //                            DataRepository.KeywordsProvider.Insert(kws);
        //                            try
        //                            {
        //                                Keyword newKeyword = new Keyword();
        //                                newKeyword.adGroupId = adGroupId;
        //                                newKeyword.type = (KeywordType)Enum.ToObject(typeof(KeywordType), AdKeywordType);
        //                                newKeyword.text = cleanProdName;
        //                                //TODO: Use the Traffic Estimator to determine the
        //                                // the maxCpc to use
        //                                newKeyword.maxCpc = KeywordMaxCpc;
        //                                newKeyword.maxCpcSpecified = true;
        //                                newKeyword.criterionType = CriterionType.Keyword;
        //                                newKeyword.destinationUrl = destinationUrlPrefix + siteCategory.PageUrl.Substring(2, siteCategory.PageUrl.IndexOf(".") - 2) + "__" + urlProdName;
        //                                Criterion[] newCriteria = new Criterion[] { newKeyword };
        //                                newCriteria[0].destinationUrl = newKeyword.destinationUrl;
        //                                criterionService.addCriteria(newCriteria);
        //                            }
        //                            catch
        //                            {
        //                                //do nothing
        //                                Trace.TraceError("***Add Criteria Failed: Keyword" + cleanProdName);
        //                            }
        //                            //Add the individual product name keywords
        //                            foreach (SeedKeyword sk in keywordsArray)
        //                            {
        //                                //add keywords and url to dbs
        //                                kws = new AffiliTrac.Entities.Keywords();
        //                                kws.KeywordRefId = Guid.NewGuid();
        //                                kws.Keywords = sk.text;
        //                                kws.Url = newTextAd.destinationUrl;
        //                                kws.SiteCategoryRefId = siteCategory.SiteCategoryRefId;
        //                                DataRepository.KeywordsProvider.Insert(kws);
        //                                try
        //                                {
        //                                    // Add keywords to the newly created ad group.
        //                                    Keyword newKeyword = new Keyword();
        //                                    newKeyword.adGroupId = adGroupId;
        //                                    newKeyword.type = (KeywordType)Enum.ToObject(typeof(KeywordType), AdKeywordType);
        //                                    newKeyword.text = sk.text;
        //                                    //TODO: Use the Traffic Estimator to determine the
        //                                    // the maxCpc to use
        //                                    newKeyword.maxCpc = KeywordMaxCpc;
        //                                    newKeyword.maxCpcSpecified = true;
        //                                    newKeyword.criterionType = CriterionType.Keyword;
        //                                    newKeyword.destinationUrl = destinationUrlPrefix + siteCategory.PageUrl.Substring(2, siteCategory.PageUrl.IndexOf(".") - 2) + "__" + urlProdName;
        //                                    Criterion[] newCriteria = new Criterion[] { newKeyword };
        //                                    newCriteria[0].destinationUrl = newKeyword.destinationUrl;
        //                                    criterionService.addCriteria(newCriteria);
        //                                }
        //                                catch
        //                                {
        //                                    //do nothing
        //                                    Trace.TraceError("***Add Criteria Failed: Keyword" + sk.text);
        //                                }
        //                            }
        //                            #endregion
        //                        }
        //                        if (GroupAdCount >= MaxAdGroups)
        //                            break;
        //                    }
        //                }
        //            }
        //            #endregion
        //        }
        //        #endregion
        //        #region Log everything created
        //        AdGroup[] adGroups = adgroupService.getAllAdGroups(campaignId);
        //        foreach (AdGroup adGroup in adGroups)
        //        {
        //            Trace.TraceInformation("Ad group: " + adGroup.name);
        //            Ad[] ads = adService.getAllAds(new long[] { adGroup.id });
        //            foreach (Ad ad in ads)
        //            {
        //                if (ad is TextAd)
        //                {
        //                    TextAd textAd = (TextAd)ad;
        //                    Trace.TraceInformation("Text ad: " + textAd.headline + " Text Line1:" + textAd.description1 + " Text Line2:" + textAd.description2);
        //                }
        //            }
        //        }
        //        #endregion
        //    }
        //    catch (Exception ex)
        //    {
        //        throw ex;
        //    }
        //}
        /// <summary>
        /// CreateKeywordsByAffiliateSiteRefId
        /// </summary>
        /// <param name="CheckAgainstAdwordsAPI"></param>
        /// <param name="UseSandbox"></param>
        /// <param name="AffiliateSiteRefId"></param>
        /// <param name="destinationUrlPrefix"></param>
        /// <param name="MaxAdvertiserCompetitionScale"></param>
        /// <param name="MinSearchVolumeScale"></param>
        /// <param name="MaxEstimateCpc"></param>
        /// <param name="MinEstimateCpc"></param>
        /// <param name="MaxEstimateClicksPerDay"></param>
        /// <param name="MinEstimateClicksPerDay"></param>
        /// <param name="getVariations"></param>
        /// <param name="getSiteKeywords"></param>
        /// <param name="Languages"></param>
        /// <param name="Countries"></param>
        public VList<SiteCategoryKeywords> CreateKeywordsByAffiliateSiteRefId(bool CheckAgainstAdwordsAPI, bool UseSandbox, Guid AffiliateSiteRefId,
            bool getVariations, bool getSiteKeywords, int maxKeywordsPerEstimate, String[] Languages,
            String[] Countries, decimal maxApiUsageDollars)
        {
            // Create a user (reads headers from App.config file).
            AdWordsUser user = new AdWordsUser();

            VList<SiteCategoryKeywords> reserachList = new VList<SiteCategoryKeywords>();

            //get seo parameters
            SeoParameters seop = DataRepository.SeoParametersProvider.GetByAffiliateSiteRefId(AffiliateSiteRefId)[0];

            if (CheckAgainstAdwordsAPI)
            {
                if (UseSandbox)
                    user.UseSandbox();	// use sandbox

                AccountService accountService = (AccountService)user.GetService(ApiServices.v13.AccountService);
                string[] accounts = accountService.getClientAccounts();
            }

            try
            {
                #region Create your Services
                //create your services
                List<KeywordRequest> keywords = new List<KeywordRequest>();
                //List<SeedKeyword> keywordsForVariation = new List<SeedKeyword>();

                TrafficEstimatorService trafficEstimatorService = (TrafficEstimatorService)user.GetService(ApiServices.v13.TrafficEstimatorService);
                AdGroupAdServicev200906 adService = (AdGroupAdServicev200906)user.GetService(ApiServices.v200906.AdGroupAdService);

                KeywordToolService keywordToolService = (KeywordToolService)user.GetService(ApiServices.v13.KeywordToolService);
                AdGroupServicev200906 adgroupService = (AdGroupServicev200906)user.GetService(ApiServices.v200906.AdGroupService);

                #endregion

                #region Enumerate thru all the categories
                bool SiteCategoryKeywordMaxCntReached = false;
                int SiteCategoryKeywordMaxCnt = 0;
                int SiteCategoryAdMaxCnt = 0;
                int SiteCategoryKeywordCnt = 0;

                // calculate max values by budget
                CalculateKeywordCountsPerSiteCategoryByApiBudget(out SiteCategoryKeywordMaxCnt, out SiteCategoryAdMaxCnt);

                //enumerate thru all the categories
                foreach (SiteCategory siteCategory in DataRepository.SiteCategoryProvider.GetByAffiliateSiteRefId(AffiliateSiteRefId))
                {
                    if (SiteCategoryKeywordMaxCntReached)
                    {
                        SiteCategoryKeywordMaxCntReached = false;
                        SiteCategoryKeywordCnt = 0;
                    }

                    DataRepository.SiteCategoryProvider.DeepLoad(siteCategory, true, DeepLoadType.IncludeChildren, typeof(TList<SiteCategoryCategoryMapping>));

                    #region Enumerate thru the category mappings to get the merchants
                    //enumerate thru the categoru mappings to get the merchants
                    foreach (SiteCategoryCategoryMapping catMap in siteCategory.SiteCategoryCategoryMappingCollection)
                    {
                        if (SiteCategoryKeywordMaxCntReached)
                            break;

                        DataRepository.SiteCategoryCategoryMappingProvider.DeepLoad(catMap, true, DeepLoadType.IncludeChildren, typeof(Category));
                        DataRepository.CategoryProvider.DeepLoad(catMap.CategoryRefIdSource, true, DeepLoadType.IncludeChildren, typeof(TList<Merchant>));
                        catMap.CategoryRefIdSource.MerchantCollection.Shuffle();
                        foreach (Merchant merch in catMap.CategoryRefIdSource.MerchantCollection)
                        {
                            if (SiteCategoryKeywordMaxCntReached)
                                break;

                            DataRepository.MerchantProvider.DeepLoad(merch, true, DeepLoadType.IncludeChildren, typeof(TList<Product>));

                            //shuffle the products
                            merch.ProductCollection.Shuffle();

                            // enumerate thru all the merchant's products
                            foreach (Product prod in merch.ProductCollection)
                            {
                                if (SiteCategoryKeywordMaxCntReached)
                                    break;

                                Trace.TraceInformation(prod.Name);
                                //scrub the product name to extract the keywords
                                string cleanProdKeywords = StringUtils.ScrubProdName(StringUtils.RemoveDuplicateWords(prod.Name));

                                string urlProdRefId = siteCategory.ProductUrlPrefix + prod.ProductRefId.ToString();

                                keywords.Clear();

                                //create an array of keywords
                                string[] rawKeywords = new string[] { "" };
                                //seperate into individual keywords
                                rawKeywords = cleanProdKeywords.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
                                List<string> cleanKeyword = new List<string>();
                                foreach (string str in rawKeywords)
                                {
                                    int tryInt = 0; //not empty, not a number, and not lower case
                                    if (str.Length > 2 && str.Trim() != "" && !int.TryParse(str.Trim(), out tryInt)) //&& !isLowerCase(str.Trim().Substring(0, 1).ToCharArray()[0])
                                    {
                                        cleanKeyword.Add(StringUtils.ScrubKeywords(str));
                                    }
                                }

                                //seperate into keywords phrases
                                //TODO: KeywordPhraseWordCount use this config
                                for (int i = 0; i < rawKeywords.Length - 1; i++)
                                {
                                    int tryInt = 0; //not empty, not a number, and not lower case
                                    if (rawKeywords[i].Length > 2 && rawKeywords[i].Trim() != "" && !int.TryParse(rawKeywords[i].Trim(), out tryInt) && rawKeywords[i + 1].Length > 2 && rawKeywords[i + 1].Trim() != "" && !int.TryParse(rawKeywords[i + 1].Trim(), out tryInt))
                                    {
                                        cleanKeyword.Add(StringUtils.ScrubKeywords(rawKeywords[i] + " " + StringUtils.ScrubKeywords(rawKeywords[i + 1])));
                                    }
                                }

                                //also add a key word for the entire product name
                                cleanKeyword.Add(prod.Name);

                                foreach (string keyword in cleanKeyword)
                                {
                                    if (DataRepository.KeywordsProvider.GetByUrlKeywords(urlProdRefId, keyword) == null)
                                    {
                                        //add keywords and url to dbs
                                        AffiliTrac.Entities.Keywords kws = new AffiliTrac.Entities.Keywords();
                                        kws.KeywordRefId = Guid.NewGuid();
                                        kws.Keywords = keyword;
                                        kws.Url = urlProdRefId;
                                        kws.ProductRefId = prod.ProductRefId;
                                        kws.SiteCategoryRefId = siteCategory.SiteCategoryRefId;

                                        DataRepository.KeywordsProvider.Insert(kws);
                                        SiteCategoryKeywordCnt += 1;

                                        if (SiteCategoryKeywordCnt >= SiteCategoryKeywordMaxCnt)
                                        {
                                            SiteCategoryKeywordMaxCntReached = true;
                                            break;
                                        }
                                    }
                                }
                            }

                        }
                    }
                    #endregion
                }
                #endregion

                #region Check Traffic Estimates for Keywords
                if (CheckAgainstAdwordsAPI)
                {
                    try
                    {
                        int apiUnitUsage = 0;
                        reserachList = DataRepository.SiteCategoryKeywordsProvider.GetDistinct(AffiliateSiteRefId);
                        foreach (SiteCategoryKeywords kw in reserachList)
                        {
                            //TODO: check usage
                            //if (apiUsage >= maxApiUsage)
                            //    break;

                            KeywordRequest sw = new KeywordRequest();
                            sw.text = kw.Keywords;

                            sw.type = kw.Keywords.IndexOf(' ') > 0 ? KeywordType.Phrase : KeywordType.Broad; //check to see if it's a phrase
                            sw.maxCpc = seop.MaxEstimateCpc;
                            sw.maxCpcSpecified = true;
                            sw.typeSpecified = true;
                            keywords.Add(sw);

                            #region Add Aditional Search types
                            //sw = new KeywordRequest();
                            //sw.text = StringUtils.ScrubKeywords(str);
                            //if (sw.text.Length > 2 && sw.text.Trim() != "")
                            //{
                            //    sw.type = KeywordType.Exact;
                            //    sw.maxCpc = 1000000;
                            //    sw.maxCpcSpecified = true;
                            //    sw.typeSpecified = true;

                            //    keywords.Add(sw);
                            //}

                            //sw = new KeywordRequest();
                            //sw.text = StringUtils.ScrubKeywords(str);
                            //if (sw.text.Length > 2 && sw.text.Trim() != "")
                            //{
                            //    sw.type = KeywordType.Phrase;
                            //    sw.maxCpc = 1000000;
                            //    sw.maxCpcSpecified = true;
                            //    sw.typeSpecified = true;

                            //    keywords.Add(sw);
                            //}
                            #endregion
                        }

                        // check traffic estimates 100 at a time
                        for (int i = 0; i < keywords.Count; i += maxKeywordsPerEstimate)
                        {
                            if (i >= keywords.Count)
                                break;

                            KeywordRequest[] keywordsRequestArray = new KeywordRequest[] { new KeywordRequest() };
                            keywordsRequestArray = keywords.GetRange(i, keywords.Count - i >= maxKeywordsPerEstimate ? maxKeywordsPerEstimate : keywords.Count - i).ToArray();
                            KeywordEstimate[] KeywordEstimates = null;

                            try
                            {
                                KeywordEstimates = trafficEstimatorService.estimateKeywordList(keywordsRequestArray);

                                foreach (KeywordRequest kr in keywordsRequestArray)
                                {
                                    Trace.TraceInformation("Accepted keyword :" + kr.text);
                                }

                                //apiUsage += DataRepository.PpcApiRequestTypesProvider.GetByName("").ApiUnitCostPerItem; //((decimal)keywordsRequestArray.Length * (decimal).20);

                                //Trace.TraceInformation("API Usage :" + apiUsage.ToString("{0:c}"));

                            }
                            catch (Exception ex)
                            {
                                //do nothing
                                Trace.TraceError("***Get Keyword Traffic Estimates Failed: " + ex.Message);
                                foreach (KeywordRequest kr in keywordsRequestArray)
                                {
                                    Trace.TraceInformation("Possible bad keyword :" + kr.text);
                                }

                                // TODO: now go thru and do them individually

                                continue;

                            }

                            if (KeywordEstimates.Length > 0)
                            {
                                int c = 0;
                                foreach (KeywordEstimate keywordEstimate in KeywordEstimates)
                                {
                                    //Trace.TraceInformation("Checking Site Keyword " + maxVariations + ":" + sitekeyword.text);
                                    // check for low compitition and high search volumes

                                    if (UseSandbox || (keywordEstimate.lowerClicksPerDay >= seop.MinEstimateClicksPerDay && keywordEstimate.lowerCpc <= seop.MaxEstimateCpc))
                                    {
                                        // mark MeetsSeoParm on all keyword records with this keyword
                                        TList<Keywords> updateList = DataRepository.KeywordsProvider.GetByKeywords(keywordsRequestArray[c].text);
                                        foreach (Keywords ukw in updateList)
                                        {
                                            ukw.MeetsSeoCriteria = true;
                                        }

                                        DataRepository.KeywordsProvider.Update(updateList);
                                    }

                                    c++;
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        //do nothing
                        Trace.TraceError("***Get Keyword Traffic Estimates Failed: " + ex.Message);
                    }
                }

                #endregion

                //go get the updated list again
                reserachList = DataRepository.SiteCategoryKeywordsProvider.GetDistinct(AffiliateSiteRefId);

                return reserachList;

            }
            catch (Exception ex)
            {
                Trace.TraceError("Error:" + ex.Message);
                throw ex;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="UseSandbox"></param>
        /// <param name="Name"></param>
        /// <param name="Countries"></param>
        /// <param name="Languages"></param>
        /// <param name="BudgetPeriod"></param>
        /// <param name="BudgetAmount"></param>
        /// <param name="MaxAdGroups"></param>
        /// <param name="DisplayUrl"></param>
        /// <param name="destinationUrlPrefix"></param>
        public void CreateCampaignByKeywordDensityContentMatch(bool UseSandbox, Guid AffiliateSiteRefId, int BudgetPeriod,
            Moneyv200906 BudgetAmount, AdGroupCriterionMoneyv200906 KeywordMaxCpc, string DisplayUrl, int MaxAdGroups, int AdKeywordType, int MinKeywordDensity,
            int MaxKeywordDensity, int MinContentMatch, decimal maxApiUsageDollars)
        {
            // Create a user (reads headers from App.config file).
            AdWordsUser user = new AdWordsUser();
            if (UseSandbox)
                user.UseSandbox();	// use sandbox

            AccountService accountService = (AccountService)user.GetService(ApiServices.v13.AccountService);
            string[] accounts = accountService.getClientAccounts();

            try
            {
                #region Create Campaign

                PpcNetwork ppcNetwork = DataRepository.PpcNetworkProvider.GetByName("AdWords");

                TList<PpcCampaign> Campaigns =
                    DataRepository.PpcCampaignProvider.GetByPpcNetworkRefId(ppcNetwork.PpcNetworkRefId);

                foreach (PpcCampaign campaign in Campaigns)
                {
                    // Target the campaign at
                    CampaignServicev200906 campaignService =
                        (com.google.api.adwords.v200906.CampaignService.CampaignService)
                        user.GetService(ApiServices.v200906.CampaignService);

                    // Create a new campaign with an ad group.  First create a
                    // campaign, so we can get its id.
                    Campaignv200906 newCampaign = new Campaignv200906();

                    // The campaign name is optional.  An error results if a campaign
                    // of the same name already exists.
                    newCampaign.name = campaign.CampaignName + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString();

                    // Set the campaign status to paused, we don't want to start
                    // paying for this test.
                    // Required: Set the campaign status.
                    newCampaign.status = CampaignStatusv200906.ACTIVE;
                    newCampaign.statusSpecified = true;

                    // Required: Specify the currency and budget amount.
                    Budget budget = new Budget();
                    BudgetAmount.microAmountSpecified = true;
                    budget.amount = BudgetAmount;

                    // Required: Specify the bidding strategy.
                    newCampaign.biddingStrategy = new ManualCPC();

                    // Optional: Specify the budget period and delivery method.
                    budget.periodSpecified = true;
                    budget.period = BudgetBudgetPeriod.DAILY;
                    budget.deliveryMethodSpecified = true;
                    budget.deliveryMethod = BudgetBudgetDeliveryMethod.STANDARD;
                    newCampaign.budget = budget;

                    // Optional: Specify an endDate for the campaign.
                    newCampaign.endDate = DateTime.Now.AddDays(campaign.DurationInDays).ToString("yyyyMMdd");

                    // Define an Add operation to add the campaign.
                    CampaignOperation campaignOperation = new CampaignOperation();

                    campaignOperation.operatorSpecified = true;
                    campaignOperation.@operator = CampaignOperatorv200906.ADD;
                    campaignOperation.operand = newCampaign;

                    try
                    {
                        CampaignReturnValue results =
                            campaignService.mutate(new CampaignOperation[] { campaignOperation });
                        if (results != null && results.value != null && results.value.Length > 0)
                        {
                            newCampaign.id = results.value[0].id;
                            newCampaign.idSpecified = true;
                            Trace.TraceInformation(
                                "New campaign with name = \"{0}\" and id = " + "\"{1}\" was created.",
                                results.value[0].name, results.value[0].id);
                        }
                    }
                    catch (Exception ex)
                    {
                        Trace.TraceError("Error:" + ex.Message);
                        throw new Exception("Failed to create campaign. " + ex.Message);
                    }

                #endregion

                    #region Targeting

                    CampaignTargetService service =
                        (CampaignTargetService)user.GetService(ApiServices.v200906.CampaignTargetService);

                    // Create a language target - for English language.
                    LanguageTargetv200906 languageTarget = new LanguageTargetv200906();
                    languageTarget.languageCode = "en"; //TODO: Add as property
                    LanguageTargetList languageTargetList = new LanguageTargetList();
                    languageTargetList.targets = new LanguageTargetv200906[] { languageTarget };
                    languageTargetList.campaignId = newCampaign.id;
                    languageTargetList.campaignIdSpecified = true;

                    // Create a country target - include US, exclude metrocode 743.
                    CountryTargetv200906 countryTarget = new CountryTargetv200906();
                    countryTarget.countryCode = campaign.TargetCountry;
                    countryTarget.excludedSpecified = true;
                    countryTarget.excluded = false;
                    MetroTargetv200906 metroTarget = new MetroTargetv200906();
                    metroTarget.excludedSpecified = true;
                    metroTarget.excluded = true;
                    metroTarget.metroCode = campaign.ExcludeMetroTarget;

                    GeoTargetList geoTargetList = new GeoTargetList();
                    geoTargetList.targets = new GeoTargetv200906[] { countryTarget, metroTarget };
                    geoTargetList.campaignId = newCampaign.id;
                    geoTargetList.campaignIdSpecified = true;

                    // Create a network target - Google Search.
                    NetworkTargetv200906 networkTarget1 = new NetworkTargetv200906();
                    networkTarget1.networkCoverageTypeSpecified = true;
                    networkTarget1.networkCoverageType = NetworkCoverageTypev200906.GOOGLE_SEARCH;
                    NetworkTargetv200906 networkTarget2 = new NetworkTargetv200906();
                    networkTarget2.networkCoverageTypeSpecified = true;
                    networkTarget2.networkCoverageType = NetworkCoverageTypev200906.SEARCH_NETWORK;

                    NetworkTargetList networkTargetList = new NetworkTargetList();
                    networkTargetList.targets = new NetworkTargetv200906[] { networkTarget1, networkTarget2 };
                    networkTargetList.campaignId = newCampaign.id;
                    networkTargetList.campaignIdSpecified = true;

                    TargetList[] targets =
                        new TargetList[] { languageTargetList, geoTargetList, networkTargetList };

                    ArrayList campaignTargetOperations = new ArrayList();

                    foreach (TargetList target in targets)
                    {
                        CampaignTargetOperation ops = new CampaignTargetOperation();
                        ops.operatorSpecified = true;
                        ops.@operator = CampaignTargetOperatorv200906.SET;
                        ops.operand = target;
                        campaignTargetOperations.Add(ops);
                    }

                    try
                    {
                        service.mutate((CampaignTargetOperation[])
                                       campaignTargetOperations.ToArray(typeof(CampaignTargetOperation)));
                        Trace.TraceInformation("Geo, language, and network targeting were " +
                                               "successfully added to campaign id = \"{0}\".", newCampaign.id);
                    }
                    catch (Exception ex)
                    {
                        Trace.TraceError("Failed to create campaign targeting. " +
                                         "Exception says \"{0}\"", ex.Message);
                    }

                    #endregion

                    #region Create your Services

                    //create your services
                    List<SeedKeyword> keywords = new List<SeedKeyword>();

                    AdGroupAdServicev200906 adService =
                        (AdGroupAdServicev200906)user.GetService(ApiServices.v200906.AdGroupAdService);
                    KeywordToolService keywordToolService =
                        (KeywordToolService)user.GetService(ApiServices.v13.KeywordToolService);
                    AdGroupServicev200906 adgroupService =
                        (AdGroupServicev200906)user.GetService(ApiServices.v200906.AdGroupService);
                    TrafficEstimatorService trafficEstimatorService =
                        (TrafficEstimatorService)user.GetService(ApiServices.v13.TrafficEstimatorService);

                    #endregion

                    #region Enumerate thru all the keywords by category

                    AdGroupv200906 newAdGroup = null;

                    foreach (
                        SiteCategory siteCategory in
                            DataRepository.SiteCategoryProvider.GetByAffiliateSiteRefId(AffiliateSiteRefId))
                    {
                        int adGroupCnt = 1;
                        //enumerate thru all the keywords
                        foreach (
                            KeywordUrLsDistinct keywordUrLsDistinct in
                                DataRepository.KeywordUrLsDistinctProvider.GetBySiteCategoryRefId(
                                    siteCategory.SiteCategoryRefId))
                        {
                            VList<KeywordDensity> keywordDensityList =
                                DataRepository.KeywordDensityProvider.GetURLKeywordDensity(keywordUrLsDistinct.Url,
                                                                                           MinKeywordDensity,
                                                                                           MaxKeywordDensity).
                                    FindAllDistinct("SiteContent");

                            int GroupAdCount = 0;

                            //check the avg keyword density
                            if (keywordDensityList.Count >= MinContentMatch)
                            {
                                if (adGroupCnt == 1)
                                {
                                    #region Ad AdGroup

                                    if (GroupAdCount >= MaxAdGroups)
                                        break;

                                    //Create an ad group by site category
                                    newAdGroup = new AdGroupv200906();
                                    newAdGroup.name = siteCategory.Name;

                                    newAdGroup.campaignId = newCampaign.id;
                                    newAdGroup.campaignIdSpecified = true;
                                    //newAdGroup.campaignName = newCampaign.name;

                                    // Optional: set the status of adgroup.
                                    newAdGroup.statusSpecified = true;
                                    newAdGroup.status = AdGroupStatus.ENABLED;

                                    // Optional: Create a Manual CPC Bid.
                                    ManualCPCAdGroupBids bids = new ManualCPCAdGroupBids();

                                    // Set the keyword content max cpc.
                                    bids.keywordContentMaxCpc = new Bid();

                                    Money kwdContentMaxCpc = new Money();
                                    kwdContentMaxCpc.microAmountSpecified = true;
                                    kwdContentMaxCpc.microAmount = KeywordMaxCpc.microAmount;
                                    bids.keywordContentMaxCpc.amount = kwdContentMaxCpc;

                                    // Set the keyword max cpc.
                                    bids.keywordMaxCpc = new Bid();
                                    Money kwdMaxCpc = new Money();
                                    kwdMaxCpc.microAmountSpecified = true;
                                    kwdMaxCpc.microAmount = KeywordMaxCpc.microAmount;
                                    bids.keywordMaxCpc.amount = kwdMaxCpc;

                                    // Set the manual bid to the adgroup.
                                    newAdGroup.bids = bids;

                                    AdGroupOperation adGroupOperation = new AdGroupOperation();
                                    adGroupOperation.operatorSpecified = true;
                                    adGroupOperation.@operator = AddGroupOperatorv200906.ADD;
                                    adGroupOperation.operand = newAdGroup;

                                    try
                                    {
                                        AdGroupReturnValue results =
                                            adgroupService.mutate(new AdGroupOperation[] { adGroupOperation });
                                        if (results != null && results.value != null && results.value.Length > 0)
                                        {
                                            newAdGroup.id = results.value[0].id;
                                            newAdGroup.idSpecified = true;
                                            Trace.TraceInformation(
                                                "New ad group with name = \"{0}\" and id = \"{1}\" was created.",
                                                results.value[0].name, results.value[0].id);
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        Trace.TraceError("Failed to create ad group. Exception says \"{0}\"", ex.Message);
                                    }

                                    adGroupCnt++;

                                    #endregion
                                }

                                Trace.TraceInformation(keywordUrLsDistinct.Url);

                                //Create an add for each product
                                //
                                // IMPORTANT: create an ad before adding keywords!  Else the
                                // minCpc will have a higher value.
                                TList<PpcAdTemplate> ppcAdTemplateList =
                                    DataRepository.PpcAdTemplateProvider.GetByPpcCampaignRefId(campaign.PpcCampaignRefId);
                                foreach (var ppcAdTemplate in ppcAdTemplateList)
                                {

                                    TextAdv200906 newTextAd = new TextAdv200906();
                                    Product prod =
                                        DataRepository.ProductProvider.GetByProductRefId(
                                            (Guid)keywordUrLsDistinct.ProductRefId);
                                    newTextAd.headline = StringUtils.ScrubProdName(prod.Name);

                                    while (newTextAd.headline.Length > 25)
                                    {
                                        // if one word longer than 25 chars
                                        if (newTextAd.headline.LastIndexOf(" ") < 0)
                                            continue;

                                        newTextAd.headline =
                                            newTextAd.headline.Substring(0, newTextAd.headline.LastIndexOf(" ")).
                                                Substring(
                                                0,
                                                newTextAd.headline.Substring(0, newTextAd.headline.LastIndexOf(" "))
                                                    .
                                                    LastIndexOf(" "));
                                    }

                                    newTextAd.description1 = ppcAdTemplate.AdLine1.Replace(KeywordToken,
                                                                                           keywordDensityList[0].Keywords).Replace(ProductNameToken, newTextAd.headline);
                                    newTextAd.description2 = ppcAdTemplate.AdLine2;

                                    //}

                                    newTextAd.displayUrl = DisplayUrl;
                                    newTextAd.url = keywordUrLsDistinct.Url;
                                    //don't add it yet, there is a check below to see if it meets criteria

                                    //SeedKeyword[] keywordsArray = new SeedKeyword[] { new SeedKeyword() };
                                    //keywordsArray = keywords.ToArray();

                                    // Associate this ad group with the newly created campaign.  Send
                                    // the request to add the new ad group.

                                    try
                                    {
                                        //we found a keyword that meets criteria so ad the new Ad.
                                        AdGroupAd adGroupAd = new AdGroupAd();
                                        adGroupAd.adGroupId = newAdGroup.id;
                                        adGroupAd.adGroupIdSpecified = true;
                                        adGroupAd.ad = newTextAd;

                                        AdGroupAdOperation adGroupAdOperation = new AdGroupAdOperation();
                                        adGroupAdOperation.operatorSpecified = true;
                                        adGroupAdOperation.@operator = AddGroupAdOperatorv200906.ADD;
                                        adGroupAdOperation.operand = adGroupAd;

                                        AdGroupAdReturnValue result = null;
                                        try
                                        {
                                            result = adService.mutate(new AdGroupAdOperation[] { adGroupAdOperation });

                                            if (result.value != null && result.value.Length > 0)
                                            {
                                                foreach (AdGroupAd tempAdGroupAd in result.value)
                                                {
                                                    Trace.TraceInformation(
                                                        String.Format(
                                                            "New text ad with headline = \"{0}\" and id = \"{1}\" was created.",
                                                            ((TextAdv200906)tempAdGroupAd.ad).headline,
                                                            tempAdGroupAd.ad.id));
                                                }
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            Trace.TraceError("Failed to create Ad(s). Exception says \"{0}\"",
                                                             ex.Message);
                                        }

                                        GroupAdCount++;
                                        Trace.TraceInformation("Text ad" + GroupAdCount + ": " + newTextAd.headline +
                                                               " Text Line1:" +
                                                               newTextAd.description1 + " Text Line2:" +
                                                               newTextAd.description2);

                                        //Trace.TraceInformation("Text ad: " + newTextAd.headline + " Text Line1:" + newTextAd.description1 + " Text Line2:" + newTextAd.description2);
                                    }
                                    catch
                                    {
                                        //do nothing
                                        Trace.TraceError("***Text ad Failed:" + newTextAd.headline + " Text Line1:" +
                                                         newTextAd.description1 + " Text Line2:" +
                                                         newTextAd.description2);
                                    }

                                }

                                //Add the Product name as a whole phrase
                                AdGroupCriterionServicev200906 criterionService =
                                    (AdGroupCriterionServicev200906)
                                    user.GetService(ApiServices.v200906.AdGroupCriterionService);

                                foreach (KeywordDensity kd in keywordDensityList)
                                {
                                    try
                                    {
                                        Keywordv200906 newKeyword = new Keywordv200906();
                                        newKeyword.matchTypeSpecified = true;
                                        newKeyword.matchType =
                                            com.google.api.adwords.v200906.AdGroupCriterionService.KeywordMatchType.
                                                BROAD;
                                        newKeyword.text = kd.Keywords;

                                        BiddableAdGroupCriterion criterion = new BiddableAdGroupCriterion();
                                        criterion.adGroupId = newAdGroup.id;
                                        criterion.adGroupIdSpecified = true;
                                        criterion.criterion = newKeyword;
                                        criterion.destinationUrl = kd.Url;

                                        //TODO: Use the Traffic Estimator to determine the
                                        // the maxCpc to use
                                        //newKeyword.maxCpc = KeywordMaxCpc;
                                        //newKeyword.maxCpcSpecified = true;

                                        var adGroupCriterionBids =
                                            new com.google.api.adwords.v200906.AdGroupCriterionService.
                                                ManualCPCAdGroupCriterionBids();

                                        adGroupCriterionBids.maxCpc =
                                            new com.google.api.adwords.v200906.AdGroupCriterionService.Bid();
                                        adGroupCriterionBids.maxCpc.amount = KeywordMaxCpc;
                                        criterion.bids = adGroupCriterionBids;

                                        AdGroupCriterionOperation adGroupCriterionOperation =
                                            new AdGroupCriterionOperation();
                                        adGroupCriterionOperation.@operator =
                                            com.google.api.adwords.v200906.AdGroupCriterionService.Operator.ADD;
                                        adGroupCriterionOperation.operatorSpecified = true;
                                        adGroupCriterionOperation.operand = criterion;

                                        try
                                        {
                                            AdGroupCriterionReturnValue results =
                                                criterionService.mutate(new AdGroupCriterionOperation[] { adGroupCriterionOperation });
                                            if (results != null && results.value != null && results.value.Length > 0)
                                            {
                                                Keywordv200906 result = results.value[0].criterion as Keywordv200906;
                                                Trace.TraceInformation(
                                                    String.Format(
                                                        "New keyword with text = \"{0}\" and id = \"{1}\" was created.",
                                                        result.text, result.id));
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            Trace.TraceError(
                                                String.Format(
                                                    "Failed to create keyword at Ad group level. Exception says \"{0}\"",
                                                    ex.Message));
                                        }

                                    }
                                    catch
                                    {
                                        //do nothing
                                        Trace.TraceError("***Add Criteria Failed: Keyword" + kd.Keywords);
                                    }
                                }

                                if (GroupAdCount >= MaxAdGroups)
                                    break;
                            }
                        }
                    }

                    #endregion
                }

                #region Check api usage
                // check api usage
                ApiUsage apiUsage = new ApiUsage();
                APIQuotaValues aPIQuotaValues = apiUsage.GetApiUsage(UseSandbox);

                Trace.TraceInformation("FreeQuotaUsed:" + aPIQuotaValues.FreeQuotaUsed.ToString() + " FreeUnitsRemaining:" + aPIQuotaValues.FreeUnitsRemaining.ToString() + " SysDefinesQuotaCap:" + aPIQuotaValues.SysDefinesQuotaCap.ToString() + " TotalUsed:" + aPIQuotaValues.TotalUsed.ToString());

                #endregion

                #region Log everything created
                //AdGroup[] adGroups = adgroupService.getAllAdGroups(campaignId);

                //foreach (AdGroup adGroup in adGroups)
                //{
                //    Trace.TraceInformation("Ad group: " + adGroup.name);

                //    Ad[] ads = adService.getAllAds(new long[] { adGroup.id });

                //    foreach (Ad ad in ads)
                //    {
                //        if (ad is TextAd)
                //        {
                //            TextAd textAd = (TextAd)ad;
                //            Trace.TraceInformation("Text ad: " + textAd.headline + " Text Line1:" + textAd.description1 + " Text Line2:" + textAd.description2);
                //        }
                //    }
                //}

                #endregion

            }
            catch (Exception ex)
            {
                Trace.TraceError("Error:" + ex.Message);
                throw ex;
            }
        }