public static BindingList <T> ForEachNewOrExistingItem <T>(this BindingList <T> source, Action <T> handler)
        {
            source.ForEachNewItem(handler).ForEach(handler);

            return(source);
        }
        public SolitaireGame()
        {
            Width = DefaultWidth;
            Height = DefaultHeight;

            System.Console.WriteLine("--- solitare ---");

            this.MyStatus = new StatusControl().AttachContainerTo(this).MoveContainerTo(
                (DefaultWidth - StatusControl.Width) / 2,
                (DefaultHeight - StatusControl.Height)
            );


            var GameOverBox = new TextBox
            {
                Width = DefaultWidth,
                TextAlignment = System.Windows.TextAlignment.Center,
                Foreground = Brushes.White,
                Background = Brushes.Transparent,
                BorderThickness = new Thickness(0),
                IsReadOnly = true,
                FontSize = 24,
            }.MoveTo(0, DefaultHeight / 2).AttachTo(this);


            // add autoscroll ?
            this.MyDeck.SizeTo(DefaultWidth, DefaultHeight);
            this.MyDeck.AttachContainerTo(this);
            this.MyDeck.GetRank = e => (int)RankMapping[e];


            System.Console.WriteLine("adding card infos... ");

            MyDeck.UnusedCards.AddRange(CardInfo.FullDeck());

            this.MyStatus.Score = -1;
            this.MyStatus.CardsLeft = this.MyDeck.UnusedCards.Count;
            this.MyStatus.Update();


            MyDeck.Stacks.ListChanged +=
                (sender, args) =>
                {
                    if (args.ListChangedType == ListChangedType.ItemAdded)
                    {
                        // fixme: dynamically set backside for this card

                        //var s = MyDeck.Stacks[args.NewIndex];
                        //s.SetBackground(MyDeck.GfxPath + "/spider.empty.png");
                    }
                };


            System.Console.WriteLine("creating stacklists... ");

            PlayStacks = MyDeck.CreateStackList();
            TempStacks = MyDeck.CreateStackList();
            GoalStacks = MyDeck.CreateStackList();

            PlayStacks.ForEachNewItem(
                delegate(CardStack s)
                {
                    s.CardMargin = new Vector { Y = 20 };
                    s.Update();

                    s.Cards.ListChanged +=
                        (sender, args) =>
                        {
                            if (args.ListChangedType == ListChangedType.ItemDeleted)
                                s.RevealLastCard();
                        };

                }
            );



            GameOver += delegate
            {
                GameOverBox.Text = "Congratulations! You Won!";
            };


            System.Console.WriteLine("creating goalstack... ");

            var Margin = (DefaultWidth - CardInfo.Width * 7) / 8;

            var ReserveStack = new CardStack().MoveTo(Margin, Margin);
            var UsedChoiceStack = new CardStack().MoveTo(Margin + CardInfo.Width + Margin, Margin);
            var ChoiceStack = new CardStack().MoveTo(Margin + CardInfo.Width + Margin, Margin);


            TempStacks.AddRange(
                ReserveStack,
                UsedChoiceStack,
                ChoiceStack
            );


            ReserveStack.CardMargin.X = 0;
            ReserveStack.CardMargin.Y = 0;

            UsedChoiceStack.CardMargin.X = 0;
            UsedChoiceStack.CardMargin.Y = 0;

            ChoiceStack.CardMargin.X = 20;
            ChoiceStack.CardMargin.Y = 0;



            #region rules
            Func<bool> Rule_WinConditionMet =
                delegate
                {
                    if (PlayStacks.All(s => s.Cards.Count > 0))
                        return false;

                    if (TempStacks.All(s => s.Cards.Count == 0))
                        return false;

                    return true;
                };

            Func<Card, Card, bool> RuleForStackingCardsInGoalStack =
                (Previous, Current) =>
                {
                    if (Cheat)
                        return true;

                    if (Previous == null)
                        return Current.Info.Rank == CardInfo.RankEnum.RankAce;

                    if (Previous.Info.Suit != Current.Info.Suit)
                        return false;

                    if (Previous.Rank != Current.Rank + 1)
                        return false;

                    return true;
                };

            Func<Card, Card, bool> RuleForStackingCardsInPlayStack =
                (Previous, Current) =>
                {
                    if (Cheat)
                        return true;

                    if (Previous.Info.SuitColor == Current.Info.SuitColor)
                        return false;

                    if (Previous.Rank + 1 != Current.Rank)
                        return false;

                    return true;
                };

            #endregion

            MyDeck.ApplyCardRules += delegate(Card card)
            {
                card.MovedByLocalPlayer +=
                    delegate
                    {
                        MyStatus.Moves++;
                        MyStatus.Update();

                    };

                card.ValidateDragStart =
                    delegate
                    {
                        if (Cheat)
                            return true;

                        // cannot remove cards from goal stack
                        if (GoalStacks.Contains(card))
                            return false;

                        if (TempStacks.Contains(card))
                        {
                            return (card == ChoiceStack.LastOrDefault());
                        }

                        // cannot drag a pile of cards unless alternate colors and descending numbers
                        return card.SelectedCards.AllWithPrevious(RuleForStackingCardsInPlayStack);
                    };


                card.ValidateDragStop =
                    CandidateStack =>
                    {
                        if (Cheat)
                            return true;

                        if (TempStacks.Contains(CandidateStack))
                        {
                            return false;
                        }

                        if (PlayStacks.Contains(CandidateStack))
                        {
                            if (CandidateStack.Cards.Count == 0)
                                return card.Info.Rank == CardInfo.RankEnum.RankKing;


                            return (RuleForStackingCardsInPlayStack(CandidateStack.Cards.Last(), card));
                        }

                        if (GoalStacks.Contains(CandidateStack))
                        {
                            if (card.StackedCards.Length > 0)
                                return false;

                            return (RuleForStackingCardsInGoalStack(CandidateStack.Cards.LastOrDefault(), card));

                        }

                        return false;
                    };
            };



            GoalStacks.ForEachNewItem(
                s =>
                {
                    s.CardMargin.X = 0;
                    s.CardMargin.Y = 0;

                    s.Cards.ForEachNewItem(
                        card =>
                        {
                            this.MyStatus.CardsLeft--;
                            this.MyStatus.Update();

                            if (card.Info.Rank == CardInfo.RankEnum.RankKing)
                            {

                                card.VisibleSide = Card.SideEnum.BackSide;


                                if (Rule_WinConditionMet())
                                {
                                    // winner!
                                    MyDeck.Sounds.win();

                                    if (this.GameOver != null)
                                        this.GameOver();
                                }
                            }
                        }
                    );
                }
            );
            GoalStacks.AddRange(
                Enumerable.Range(0, 4).ToArray(
                    i => new CardStack().MoveTo(DefaultWidth - ((CardInfo.Width + Margin) * 4) + i * (CardInfo.Width + Margin), Margin)
                )
            );

            System.Console.WriteLine("creating playstack... ");

            PlayStacks.AddRange(
                Enumerable.Range(0, 7).ToArray(
                    i => new CardStack().MoveTo(Margin + i * (CardInfo.Width + Margin), Margin * 3 + CardInfo.Height).Apply(s => s.Cards.AddRange(MyDeck.FetchCards(i + 1)))
                )
            );

            ReserveStack.Cards.AddRange(MyDeck.FetchCards(MyDeck.UnusedCards.Count));
            ReserveStack.Update();

            PlayStacks.ForEach(k => k.Last().VisibleSide = Card.SideEnum.TopSide);


            UsedChoiceStack.Cards.ForEachNewItem(
                card => card.VisibleSide = Card.SideEnum.BackSide
            );

            ChoiceStack.Cards.ForEachNewItem(
                card => card.VisibleSide = Card.SideEnum.TopSide
            );

            ChoiceStack.Click +=
                delegate
                {
                    ChoiceStack.Update();
                }
            ;

            ReserveStack.Overlay.Cursor = Cursors.Hand;
            ReserveStack.Cards.ForEachNewItem(
                card => card.VisibleSide = Card.SideEnum.BackSide
            );





            var ReserveStackEnabled = true;

            ReserveStack.Click +=
                delegate
                {
                    if (!ReserveStackEnabled)
                        return;

                    if (ReserveStack.Cards.Count == 0)
                    {
                        MyDeck.Sounds.deal();

                        ChoiceStack.FirstOrDefault().Apply(
                            card =>
                            {

                                card.AnimatedMoveToStack(ReserveStack, null, null);
                            }
                        );

                        UsedChoiceStack.FirstOrDefault().Apply(
                            card =>
                            {

                                card.AnimatedMoveToStack(ReserveStack, null, null);
                            }
                        );
                    }
                    else
                    {
                        ReserveStackEnabled = false;


                        ChoiceStack.Cards.ToArray().ForEach(
                            card =>
                            {
                                card.AttachToStack(UsedChoiceStack);
                            }
                        );
                        UsedChoiceStack.Update();

                        3.Times(
                            SignalNext =>
                                ReserveStack.LastOrDefault().Apply(
                                    card =>
                                    {
                                        card.BringToFront();

                                        Console.WriteLine(card.ToString());

                                        card.AnimatedMoveToStack(ChoiceStack, null, null);

                                        MyDeck.Sounds.deal();

                                        200.AtDelay(SignalNext);
                                    }
                                )
                        );

                    }


                    // a timepoint when movements are done.. this should ba an event actually
                    2000.AtDelay(() => ReserveStackEnabled = true);

                };
        }
        public FreeCellGame()
        {
            Width = DefaultWidth;
            Height = DefaultHeight;


            var Margin = (DefaultWidth - CardInfo.Width * 8) / 9;

            var GameOverBox = new TextBox
            {
                Width = DefaultWidth,
                TextAlignment = System.Windows.TextAlignment.Center,
                Foreground = Brushes.White,
                Background = Brushes.Transparent,
                BorderThickness = new Thickness(0),
                IsReadOnly = true,
                FontSize = 24,
            }.MoveTo(0, DefaultHeight / 2).AttachTo(this);

            GameOver += delegate
            {
                GameOverBox.Text = "Congratulations! You Won!";
            };

            #region king
            var KingCanvas = new Canvas
            {
                Width = 96,
                Height = 96
            }.AttachTo(this).MoveTo(
                (DefaultWidth - 32) / 2,
                Margin * 2 + (CardInfo.Height - 32) / 2
            );

            var KingRight = new kingbitm().AttachTo(KingCanvas);

            var KingLeft = new kingleft().AttachTo(KingCanvas);

            var KingSmile = new kingsmil().AttachTo(KingCanvas);

            KingSmile.Hide();

            #endregion

            this.MyDeck.Overlay.MouseMove +=
                (sender, args) =>
                {
                    var p = args.GetPosition(this.MyDeck.Overlay);

                    if (p.X < DefaultWidth / 2)
                    {
                        KingLeft.Show();
                        KingRight.Hide();
                    }
                    else
                    {
                        KingLeft.Hide();
                        KingRight.Show();
                    }
                };

            this.MyStatus = new StatusControl().AttachContainerTo(this).MoveContainerTo(
                (DefaultWidth - StatusControl.Width) / 2,
                (DefaultHeight - StatusControl.Height)
            );



            //this.MyStatus.Container.Hide();

            // add autoscroll ?
            this.MyDeck.SizeTo(DefaultWidth, DefaultHeight);
            this.MyDeck.AttachContainerTo(this);
            this.MyDeck.GetRank = e => (int)RankMapping[e];

            System.Console.WriteLine("--- freecell ---");

            System.Console.WriteLine("adding card infos... ");

            MyDeck.UnusedCards.AddRange(CardInfo.FullDeck());

            this.MyStatus.CardsLeft = MyDeck.UnusedCards.Count;
            this.MyStatus.Score = -1;
            this.MyStatus.Update();

            System.Console.WriteLine("creating stacklists... ");

            PlayStacks = MyDeck.CreateStackList();
            PlayStacks.ForEachNewItem(
                k =>
                {
                    k.CardMargin = new Vector { Y = 20 };
                    k.Update();
                }
            );

            TempStacks = MyDeck.CreateStackList();

            Func<bool> Rule_WinConditionMet =
                delegate
                {
                    if (PlayStacks.All(s => s.Cards.Count > 0))
                        return false;

                    if (TempStacks.All(s => s.Cards.Count == 0))
                        return false;

                    return true;
                };

            Action MyStatus_UpdateCardsLeft =
                delegate
                {

                    MyStatus.CardsLeft = 0;

                    PlayStacks.ForEach(q => MyStatus.CardsLeft += q.Cards.Count);
                    TempStacks.ForEach(q => MyStatus.CardsLeft += q.Cards.Count);
                };

            GoalStacks = MyDeck.CreateStackList();
            GoalStacks.ForEachNewItem(
                k =>
                {

                    k.CardMargin.Y = 0;

                    k.Cards.ForEachNewItem(
                        card =>
                        {
                            Console.WriteLine("GoalStacks ForEachNewItem " + new { k.CardMargin.Y });

                            if (card.Info.Rank == CardInfo.RankEnum.RankKing)
                            {
                                KingSmile.Show();

                                card.VisibleSide = Card.SideEnum.BackSide;


                                if (Rule_WinConditionMet())
                                {
                                    // winner!
                                    MyDeck.Sounds.win();

                                    if (this.GameOver != null)
                                        this.GameOver();
                                }
                                else
                                {
                                    600.AtDelay(KingSmile.Hide);
                                }
                            }


                            MyStatus_UpdateCardsLeft();
                            MyStatus.Update();
                        }
                    );
                }
            );

            Func<Card, Card, bool> RuleForStackingCardsInGoalStack =
                (Previous, Current) =>
                {
                    if (Cheat)
                        return true;

                    if (Previous == null)
                        return Current.Info.Rank == CardInfo.RankEnum.RankAce;

                    if (Previous.Info.Suit != Current.Info.Suit)
                        return false;

                    if (Previous.Rank != Current.Rank + 1)
                        return false;

                    return true;
                };

            Func<Card, Card, bool> RuleForStackingCardsInPlayStack =
                (Previous, Current) =>
                {
                    if (Cheat)
                        return true;

                    if (Previous.Info.SuitColor == Current.Info.SuitColor)
                        return false;

                    if (Previous.Rank + 1 != Current.Rank)
                        return false;

                    return true;
                };


            #region rules
            MyDeck.ApplyCardRules += delegate(Card card)
            {

                #region MovedByLocalPlayer
                card.MovedByLocalPlayer +=
                    delegate
                    {
                        var FrozenTokens = new
                        {
                            card.CurrentStack,
                            card.PreviousStack
                        };

                        Console.WriteLine(new { HistoryMove = card, StackedCards = card.StackedCards.Length, Previous = card.PreviousStack, Current = card.CurrentStack }.ToString());

                        History.History.Add(
                            delegate
                            {


                                // we already are at the state we want to be
                                if (card.CurrentStack == FrozenTokens.PreviousStack)
                                    return;

                                card.VisibleSide = Card.SideEnum.TopSide;
                                card.AnimatedMoveToStack(FrozenTokens.PreviousStack, null);


                                this.MyDeck.Sounds.deal();

                                MyStatus.Moves--;
                                MyStatus_UpdateCardsLeft();
                                MyStatus.Update();
                            },
                            delegate
                            {
                                MyStatus.Moves++;
                                MyStatus.Update();

                                // we already are at the state we want to be
                                if (card.CurrentStack == FrozenTokens.CurrentStack)
                                    return;



                                card.AnimatedMoveToStack(FrozenTokens.CurrentStack, null);
                                this.MyDeck.Sounds.deal();



                            }
                        );
                    };
                #endregion


                card.VisibleSide = Card.SideEnum.TopSide;

                card.ValidateDragStart =
                    delegate
                    {
                        if (Cheat)
                            return true;

                        // cannot remove cards from goal stack
                        if (GoalStacks.Contains(card))
                            return false;

                        // cannot drag a pile of cards unless alternate colors and descending numbers
                        return card.SelectedCards.AllWithPrevious(RuleForStackingCardsInPlayStack);
                    };

                card.ValidateDragStop =
                    CandidateStack =>
                    {
                        if (Cheat)
                            return true;

                        if (TempStacks.Contains(CandidateStack))
                        {
                            // temp only holds one card
                            if (CandidateStack.Cards.Count > 0)
                                return false;

                            // and only one card can be inserted
                            if (card.StackedCards.Length > 0)
                                return false;

                            return true;
                        }

                        if (PlayStacks.Contains(CandidateStack))
                        {
                            if (CandidateStack.Cards.Count == 0)
                                return true;


                            return (RuleForStackingCardsInPlayStack(CandidateStack.Cards.Last(), card));
                        }

                        if (GoalStacks.Contains(CandidateStack))
                        {
                            if (CandidateStack.Cards.Count == 0)
                            {

                                return (RuleForStackingCardsInGoalStack(null, card));
                            }

                            return (RuleForStackingCardsInGoalStack(CandidateStack.Cards.Last(), card));

                        }

                        return false;
                    };
            };
            #endregion


            System.Console.WriteLine("creating goalstack... ");


            GoalStacks.AddRange(
                Enumerable.Range(0, 4).ToArray(
                    i =>
                        new CardStack
                        {
                            Name = "GoalStack " + i
                        }.MoveTo(
                            DefaultWidth - Margin / 2 - ((CardInfo.Width + Margin / 2) * 4) + i * (CardInfo.Width + Margin / 2),
                            Margin * 2
                        )
                )
            );

            System.Console.WriteLine("creating tempstack... ");


            TempStacks.AddRange(
                Enumerable.Range(0, 4).ToArray(
                    i => new CardStack
                    {
                        Name = "TempStack " + i
                    }.MoveTo(
                        Margin + i * (CardInfo.Width + Margin / 2),
                        Margin * 2
                    )
                )
            );

            System.Console.WriteLine("creating playstack... ");

            PlayStacks.AddRange(
                Enumerable.Range(0, 8).ToArray(
                    i => new CardStack
                    {
                        Name = "PlayStack " + i
                    }.MoveTo(
                        Margin + (i) * (CardInfo.Width + Margin),
                        Margin * 4 + CardInfo.Height
                    ).Apply(
                        s =>
                        {
                            var Count = 6;

                            if (i < 4)
                                Count = 7;

                            s.Cards.AddRange(MyDeck.FetchCards(Count));
                        }
                    )
                )
            );

        }
        public GameSocialLinks(Canvas Container)
        {
            this.Container = Container;

            Buttons.ForEachNewItem(
                e =>
            {
                var i = true;
                //var x = Buttons.Where(k => i).Aggregate(Margin,
                //    (s, k) =>
                //    {
                //        if (k == e)
                //        {
                //            i = false;
                //            return s;
                //        }

                //        return s + k.Width + Margin;
                //    }
                //);

                //var y = this.Container.Height - Margin - e.Height;

                e.Y = Buttons.Where(k => i).Aggregate(Margin,
                                                      (s, k) =>
                {
                    if (k == e)
                    {
                        i = false;
                        return(s);
                    }

                    return(s + k.Height + Margin);
                }
                                                      );


                e.X = Margin;

                e.Image = new Image
                {
                    Source  = e.Source,
                    Width   = e.Width,
                    Height  = e.Height,
                    Name    = "GameSocialLinks_Button_Image",
                    Opacity = 0.6
                }.AttachTo(this).MoveTo(e.X, e.Y);

                e.Overlay = new Rectangle
                {
                    Fill    = Brushes.White,
                    Width   = e.Width,
                    Height  = e.Height,
                    Opacity = 0,
                    Cursor  = Cursors.Hand,
                    Name    = "GameSocialLinks_Button_Overlay",
                }.AttachTo(this).MoveTo(e.X, e.Y);

                var ImageOpacity     = e.Image.ToAnimatedOpacity();
                ImageOpacity.Opacity = 0.4;

                e.Overlay.MouseEnter +=
                    delegate
                {
                    ImageOpacity.Opacity = 1;
                };

                e.Overlay.MouseLeave +=
                    delegate
                {
                    ImageOpacity.Opacity = 0.4;
                };

                e.Overlay.MouseLeftButtonUp +=
                    delegate
                {
                    if (e.Click != null)
                    {
                        e.Click();
                    }

                    if (e.Hyperlink != null)
                    {
                        e.Hyperlink.NavigateTo();
                    }
                };
            }

                );
        }