using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Reflection;
using nft.framework;
using System.Threading.Tasks;

namespace nft.test
{
    public partial class TestLauncher : Form
    {
        public TestLauncher() {
            InitializeComponent();
            listEntryView.statusLabel = lblInfo;
            listener = new MyTracer(tbLog);
        }

        protected MyTracer listener;
        public TraceListener TraceListener {
            get { return listener; }
        }

        protected bool init = false;
        protected override void OnShown(EventArgs e) {
            base.OnShown(e);
            if (!init) {
                init = true;
                // TODO: カスタム属性をつけたメソッドを集められないか？
                Assembly[] a = new Assembly[] { Assembly.GetExecutingAssembly(), typeof(TestUtil).Assembly };
                LoadAssemblies(a);
                listEntryView.AdjustColumns();
            }
        }

        private ProgressForm progressForm = null;
        protected void LoadAssemblies(Assembly[] array) {
            if (progressForm != null) {
                if (!progressForm.Disposing && !progressForm.IsDisposed) {
                    progressForm.Close();
                }
                progressForm.Dispose();
            }
            progressForm = new ProgressForm();
            progressForm.Assemblies = array;
            progressForm.ShowDialog(this);
            progressForm.Dispose();
        }

        public void AddTestEntry(TestInfo info) {
            //info.Run();
            listEntryView.AddTestInfo(info);
        }

        #region context menu event handlers
        private void btnReverseCheck_Click(object sender, EventArgs e) {
            listEntryView.ReverseCheckAll();
        }

        private void btnRunChcked_Click(object sender, EventArgs e) {
            listEntryView.RunCheckedEntries();
        }

        private void cmenuReverseCheck_Click(object sender, EventArgs e) {
            listEntryView.ReverseCheckSelected();
        }

        private void cmenuUncheck_Click(object sender, EventArgs e) {
            listEntryView.SetCheckSelected(false);
        }

        private void cmenuCheck_Click(object sender, EventArgs e) {
            listEntryView.SetCheckSelected(true);
        }

        private void cmenuRun_Click(object sender, EventArgs e) {
            listEntryView.RunSelectedEntries();
        }
        #endregion

        private void listEntryView_DoubleClick(object sender, MouseEventArgs e) {
            if ((Control.ModifierKeys & Keys.Alt) == Keys.Alt) {
                ListViewItem item = listEntryView.HitTest(e.Location).Item;
                if (item != null) {
                    item.Checked = !item.Checked;
                    JumpToLastLog(item);
                }
            }
        }

        protected void JumpToLastLog(ListViewItem item) {
            if (item != null) {
                string log = listEntryView.StartLogText(item);
                int x = tbLog.Text.LastIndexOf(log);
                if (x >= 0) {
                    tbLog.Focus();
                    tbLog.Select(x, log.Length);
                    tbLog.ScrollToCaret();
                }
            }
        }
    }

    public class MyTracer : TraceListener
    {
        readonly TextBox tbOutput;

        public MyTracer(TextBox outbox) {
            tbOutput = outbox;
        }

        public override void Write(string message) {
            if (tbOutput.InvokeRequired)
            {
                tbOutput.BeginInvoke(new Action(() => tbOutput.AppendText(message)));
            } else
            {
                tbOutput.AppendText(message);
                tbOutput.AppendText(System.Environment.NewLine);
            }
        }

        public override void WriteLine(string message) {
            if (tbOutput.InvokeRequired)
            {
                tbOutput.BeginInvoke(new Action(() =>
                {
                    tbOutput.AppendText(message);
                    tbOutput.AppendText(System.Environment.NewLine);
                }));
            } else
            {
                tbOutput.AppendText(message);
                tbOutput.AppendText(System.Environment.NewLine);
            }
        }

        public override bool IsThreadSafe
        {
            get { return true; }
        }
    }
}
