using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using nft.framework;
using System.IO;
using System.Diagnostics;
using System.Reflection;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading.Tasks;
using System.Threading;
using System.Reactive.Linq;
using System.Reactive.Concurrency;
using System.Windows.Forms;
using System.Reactive.Subjects;
using System.Reactive.Disposables;

namespace nft.test.test.RxPractice
{
    static class RxSamples
    {

        [TestEntry("RxSample#イベント間引き",new object[]{100}, true)]
        static private void TestMouseMove1(int span) {
            RxPracticeForm form = new RxPracticeForm();
            form.SetMessage(String.Format("{0}ミリ秒以内の更新はまとめて、マウス座標をステータスバーに表示します", span));
            var disposer = form.ObserveMouseMove()
                .Throttle(TimeSpan.FromMilliseconds(span))
                .ObserveOn(SynchronizationContext.Current)
                .Subscribe(
                    x => form.SetStatusText(String.Format("X={0},Y={1}",x.X, x.Y))
                );
            form.ShowDialog(Application.OpenForms[0]);
            disposer.Dispose();
        }

        [TestEntry("RxSample#イベント間引き2", new object[] { 500 }, true)]
        static private void TestMouseMove2(int span) {
            RxPracticeForm form = new RxPracticeForm();
            form.SetMessage(String.Format("{0}ミリ秒に一回、マウス座標をステータスバーに表示します", span));
            var disposer = form.ObserveMouseMove()
                .Sample(TimeSpan.FromMilliseconds(span))
                .ObserveOn(SynchronizationContext.Current)
                .Subscribe(
                    x => form.SetStatusText(String.Format("X={0},Y={1}", x.X, x.Y))
                );
            form.ShowDialog(Application.OpenForms[0]);
            disposer.Dispose();
        }

        [TestEntry("RxSample#ドラッグ描画パターン", true)]
        static private void TestMouseMove3() {
            RxPracticeForm form = new RxPracticeForm();
            form.SetMessage("Aボタンで開始、Bボタンで停止、マウス移動差分をステータスバーに表示します");
            var s = form.ObserveClickA() // MouseButtonDownの代わり
                .SelectMany(_ => form.ObserveMouseMove())
                .TakeUntil(form.ObserveClickB()// MouseButtonUpの代わり
                    .Do(x => form.SetStatusText("--"))
                );
            var disposer = s.Zip(
                s.Skip(1),
                (x, y) => new { Prev = x.Location, Next = y.Location }
            )
            .Repeat() // 開始～停止を何度でも繰り返す
            //.ObserveOn(SynchronizationContext.Current)
            .Subscribe(
                arg => {
                    int dx = arg.Next.X - arg.Prev.X;
                    int dy = arg.Next.Y - arg.Prev.Y;
                    form.SetStatusText(String.Format("diffX={0},diffY={1}", dx, dy));
                },
                () => Debug.WriteLine("OnComplete")
            );            
            form.ShowDialog(Application.OpenForms[0]);
            disposer.Dispose();
        }

        [TestEntry("RxSample#タイマーと後始末テスト", true)]
        static private void TestTimerAndDispose() {
            RxPracticeForm form = new RxPracticeForm();
            form.SetMessage("A・Bボタンでタイマー登録をステータスバーに表示します");

            var disposerA = form.ObserveClickA().Subscribe( _ => Debug.WriteLine("A button Clicked"));
            var disposerB = form.ObserveClickA().Subscribe( _ => Debug.WriteLine("B button Clicked"));
            int numA = 0, numB = 0;

            using (var collection = new CompositeDisposable(disposerA,disposerB)) //? 登録
            {
                disposerA = form.ObserveClickA().Subscribe(_ => {
                    int counter = 0;
                    String id = String.Format("A{0}", ++numA);
                    var disposer2 = Observable.Timer(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1))
                        .Select(v => counter++)
                        .Subscribe(v => Debug.WriteLine(String.Format("{0}={1}", id, v)));
                    collection.Add(disposer2);
                });
                collection.Add(disposerA);
                disposerB = form.ObserveClickB().Subscribe(_ =>
                {
                    int counter = 0;
                    String id = String.Format("B{0}", ++numB);
                    var disposer2 = Observable.Timer(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))
                        .Select(v => counter++)
                        .Subscribe(v => Debug.WriteLine(String.Format("{0}={1}", id, v)));
                    collection.Add(disposer2);
                });
                collection.Add(disposerB);
                form.ShowDialog(Application.OpenForms[0]);
            }
        }    
    }

}
