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.Threading;

namespace CommonFroms.G2D
{
    public partial class G2DProgressDialog : Form
    {
        private IProgress Progress;
        private Thread mThread;
        private bool mIsClose = false;
        private bool mIsFinish = false;
        private Exception mRunError;

        public G2DProgressDialog(IProgress progress)
        {
            InitializeComponent();
            this.Progress = progress;
            this.Text = Progress.Title;
            this.textBox1.Text = Progress.Text;
            this.progressBar1.Maximum = Progress.Maximum;
            this.progressBar1.Minimum = Progress.Minimum;
            this.progressBar1.Value = Progress.Value;

            progress.Begin();
            timer1.Start();
            mThread = new Thread(new ThreadStart(run));
            mThread.Start();
        }
        private void run()
        {
            try
            {
                Progress.Run();
            }
            catch (Exception err)
            {
                mRunError = err;
            }
            finally 
            { 
                mIsFinish = true;
            }
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            if (this.mIsClose)
            {
                timer1.Stop();
                this.Progress.Done();
                this.Close();
            }
            if (mRunError != null)
            {
                string msg = mRunError.Message + "\r\n" + mRunError.StackTrace;
                string cap = mRunError.Message;
                mRunError = null;
                MessageBox.Show(msg, cap);
                this.mIsClose = true;
            }
            if (Progress.IsDone || mIsFinish)
            {
                this.Refresh();
                this.mIsClose = true;
                this.progressBar1.Invalidate();
            }
            {
                int value = Progress.Value;
                value = Math.Min(value, Progress.Maximum);
                value = Math.Max(value, Progress.Minimum);
                this.progressBar1.Maximum = Progress.Maximum;
                this.progressBar1.Minimum = Progress.Minimum;
                this.progressBar1.Value = value;
                this.textBox1.Text = Progress.Text;
            }
        }

        private void G2DProgressDialog_FormClosing(object sender, FormClosingEventArgs e)
        {
            mThread.Join();
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }

    public abstract class IProgress
    {
        public virtual string Title { get; protected set; }
        public virtual string Text { get; protected set; }
        public virtual bool IsDone { get; protected set; }
        public virtual int Maximum { get; protected set; }
        public virtual int Minimum { get; protected set; }
        public virtual int Value { get; protected set; }

        public IProgress()
        {
            this.Title = "";
            this.Text = "";
            this.IsDone = false;
            this.Maximum = 1;
            this.Minimum = 0;
            this.Value = 0;
        }

        public abstract void Run();

        public virtual void Done() { }
        public virtual void Begin() { }
    }
}