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 static System.Diagnostics.Debug; // 'Debug.WliteLine()' の 'Debug.' を省略できるぞ

namespace nft.test.test
{
    /// C# 6.0で知っておくべき12の新機能
    /// http://www.buildinsider.net/language/csharplang/0600
    ///
    class DotNetFeatureTest
    {
        public int AutoPropertyNum { get; set; } = 999; //初期値を指定できる
        public string AutoPropertyStr { get; } = "自動プロパティ"; //初期値を指定できる

        private Dictionary<int, string> textarray = new Dictionary<int, string>();
        public string this[int id]
        {
            get { return textarray[id]; }
            set { textarray[id] = value; }
        }
        private string desc;

        [TestEntry("C#6.0各種新機能を試す#1")]
        static private bool TestCS6Features1()
        {
            DotNetFeatureTest test = new DotNetFeatureTest
            { // インデクサを持つオブジェクトの新しい初期化方法
                desc = "通常のプロパティ初期化",
                [1] = "これが新しい初期化",
                [2] = "インデクサを使って初期化できる"
            };
            WriteLine(test.AutoPropertyNum, nameof(test.AutoPropertyNum)); // nameof 演算子 ＆ using static の効果
            test.AutoPropertyNum *= 10;
            WriteLine(test.AutoPropertyNum, nameof(test.AutoPropertyNum));

            // String.Formatに代わる、新しい文字列内変数置換
            WriteLine($"{test.AutoPropertyStr} ＆ [1]={test[2]}, num={test.AutoPropertyNum:#,0.#} Time={DateTime.Now:f}");

            return true;
        }
        
        // 重い処理のエミュレート兼Null条件演算子のテスト
        static private void HeavyJob(Func<int, bool> callback, string name=null, int? tick=null, int? times=null )
        {
            int _tick = tick ?? 100; // ?? 演算子は左辺がnullの時、代わりに右辺を返す
            int totalTick = _tick * (times ?? 1); 
            string _name = name?.ToUpper() ?? "<匿名>"; // ?. の前がnullなら ?? の右辺を返す
            WriteLine($"Start Heavy Job, It will took {totalTick} sec.", _name);
            for (int i = 0; i < times; i++)
            {
                WriteLine($"Callback #{i}", _name);
                if (!callback(i)) break;
                Thread.Sleep(_tick);
            }
            WriteLine("Heavy Job End.", _name);
        }


        [TestEntry("C#6.0各種新機能を試す#2")]
        static private async Task TestCS6Features2()
        {
            try
            {
                await Task.Run(() => HeavyJob( i => {
                    if (i == 2) throw new Exception("テスト用例外発生！");
                    return true;
                }, "Job#1", 100, 3 ));
            }
            catch (Exception ex) when (ex.Message == "テスト用例外発生！") // when 例外フィルター
            {
                // 例えばリトライとか
                await Task.Run(() => HeavyJob(i => {
                    return true;
                }, "job#2", 100 /*, times = null */));
                WriteLine("catch block end.");
            }
            catch (Exception ex) {
                throw ex; // 予期せぬ例外
            } finally {
                // 例えば解放処理などの後始末
                await Task.Run(() => HeavyJob(i => {
                    return true;
                } /*, name = null, tick = null, times = null */));
                WriteLine("finally block end.");
            }
        }

    }

}
