public Advertiser Build(DbAdvertiser repoAdv, DateTime dateTime)
        {
            var adv = new Advertiser();

            //Discard disabled
            if (!repoAdv.Enabled)
            {
                return(null);
            }
            //discard hitted HourlyBudget
            if ((repoAdv.CurrentHourlyPrints / (decimal)1000) * repoAdv.CPM >= repoAdv.MaxHourlyBudget)
            {
                return(null);
            }
            //Skip not available
            if (repoAdv.WorkingCalendar != null)
            {
                if (!repoAdv.WorkingCalendar.ContainsKey((byte)dateTime.DayOfWeek))
                {
                    return(null);
                }
                if (!repoAdv.WorkingCalendar[(byte)dateTime.DayOfWeek].Contains(dateTime.Hour))
                {
                    return(null);
                }
            }

            //optional Tags are not needed

            adv.RequiredTagsHashSetsFull = new HashSet <Tag>();
            for (int i = 0; i < repoAdv.RequiredTags.Count; i++)
            {
                adv.RequiredTagsHashSetsFull.Add(repoAdv.RequiredTags[i]);
            }
            adv.RequiredTagsCount = repoAdv.RequiredTags.Count;

            adv.RejectedTagsHashSetsFull = new HashSet <Tag>();
            for (int i = 0; i < repoAdv.RejectedTags.Count; i++)
            {
                adv.RejectedTagsHashSetsFull.Add(repoAdv.RejectedTags[i]);
            }

            adv.RequiredTagsHashSetsFull.TrimExcess();
            adv.RejectedTagsHashSetsFull.TrimExcess();

            adv.CPM = repoAdv.CPM;
            adv.Id  = repoAdv.Id;
            return(adv);
        }
 public Task Push(Bid bid, Advertiser advertiser, DateTime dateTime)
 {
     return(Task.CompletedTask);
 }
        public Advertiser GetWinner(Bid bid, DateTime dateTime)
        {
            //used a linked list, to easily remove advertisers with rejected tags
            var list = LinkedListAdvertizers.BuildFrom(this.advertisersCache.GetCurrentAdvertisers());
            var prev = list;
            var curr = list;

            //iterate bid tags, remove from the list rejected advertisers and count every passing adv required tag
            for (int i = 0; i < bid.Tags.Count; i++)
            {
                Tag tag = bid.Tags[i];
                //var tagHash = tag.GetHashCode();
                while (curr != null)
                {
                    if (curr.Advertiser.RejectedTagsHashSetsFull.Contains(tag))
                    {
                        //found
                        if (list == curr)
                        {
                            list = curr.Next;
                            prev = curr.Next;
                            curr = curr.Next;
                            continue;
                        }
                        else
                        {
                            prev.Next = curr.Next;
                            curr      = curr.Next;
                            continue;
                        }
                    }

                    if (curr.Advertiser.RequiredTagsHashSetsFull.Contains(tag))
                    {
                        //found
                        curr.MissingRequeriments--;
                    }
                    prev = curr;
                    curr = curr.Next;
                    continue;
                }
                prev = list;
                curr = list;
            }

            //iterate results of full passing advertizers picking the best bet win, if any
            curr = list;
            Advertiser winner = null;

            while (curr != null)
            {
                if (curr.MissingRequeriments == 0)
                {
                    //list was previously sorted by CPM so this is the max bet for this requeriments.
                    winner = curr.Advertiser;
                    break;
                }
                curr = curr.Next;
            }
            return(winner);
        }