using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Drawing;
using System.IO;
//using System.Windows.Forms;
using ChamChat.Models;

namespace ChamChat
{
    public abstract class Task
    {
        private static string _LogFilePath;

        private string _EventLogFile;
        private string _DataTransferLogFile;
        public static void SetLogPath(String path)
        {

            _LogFilePath = path + "\\TaskLogs";
            
            if (!Directory.Exists(_LogFilePath))
                Directory.CreateDirectory(_LogFilePath);
        }
        


        public Task(Client Client, Profile Profile)
        {
            _Profile = Profile;
            _Client = Client;
            ThreadPool.SetMaxThreads(1000, 1000);
       }

        



        private void InitDataTransferLog()
        {
            try
            {
                _Client.DataTransferLogs = new List<DataTransferLog>();

                DateTime dt = DateTime.Now;
                _DataTransferLogFile = _LogFilePath + "\\" + string.Format("Task_{0:00000}_{1:0000}{2:00}{3:00}.{4:00}{5:00}{6:00}.csv", _Client.MIDS, dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second);

                using (StreamWriter sw = File.CreateText(_DataTransferLogFile))
                {
                    sw.WriteLine(string.Format("Client    : {0}", _Client.ToString()));
                    sw.WriteLine(string.Format("Created   : {0:0000}-{1:00}-{2:00} @ {3:00}:{4:00} (system time)", dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute));
                    if (_Client.Interface != null)
                        sw.WriteLine(string.Format("Interface : {0}", _Client.Interface.ToString()));
                    else
                        sw.WriteLine("Interface : null");
                    sw.WriteLine(string.Format("Profile   : {0}", _Profile.Title));
                    sw.WriteLine("");
                    sw.WriteLine("Timestamp; Command; Returndata");
                }
                _Client.DataTransferLogFile = _DataTransferLogFile;
            }
            catch { _Client.DataTransferLogFile = null; }
        }
        
        
        
        private void InitEventLog()
        {
            try
            {
                _EventLogs = new List<string>();

                DateTime dt = DateTime.Now;
                _EventLogFile = _LogFilePath + "\\" + string.Format("Task_{0:00000}_{1:0000}{2:00}{3:00}.{4:00}{5:00}{6:00}_events.csv", _Client.MIDS, dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second);

                using (StreamWriter sw = File.CreateText(_EventLogFile))
                {
                    sw.WriteLine(string.Format("Client    : {0}", _Client.ToString()));
                    sw.WriteLine(string.Format("Created   : {0:0000}-{1:00}-{2:00} @ {3:00}:{4:00} (system time)", dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute));
                    if (_Client.Interface != null)
                        sw.WriteLine(string.Format("Interface : {0}", _Client.Interface.ToString()));
                    else
                        sw.WriteLine("Interface : null");
                    sw.WriteLine(string.Format("Profile   : {0}", _Profile.Title));
                    sw.WriteLine("");
                }
            }
            catch { _EventLogFile = null; }
        }



        public String Description
        {
            get
            {
                string result = string.Format("{0:00000} : Profile '{1}'", _Client.MIDS, _Profile.Title);
                return result;
            }
        }


        List<String> _EventLogs; public List<String> EventLogs { get { return _EventLogs; } }
        protected void AddEventLog(String message)
        {
            try
            {
                DateTime d = DateTime.Now;
                string sTimestamp = String.Format("{0:0000}-{1:00}-{2:00} @ {3:00}:{4:00}:{5:00}", d.Year, d.Month, d.Day, d.Hour, d.Minute, d.Second);
                string entry = String.Format("{0} : {1}", sTimestamp, message);
                //if (_EventLogs.Count > 10000) // Prevent overflowing the list
                //_EventLogs.RemoveAt(0);
                
                _EventLogs.Add(entry);

                if (_EventLogFile != null)
                {
                    using (System.IO.StreamWriter sw = System.IO.File.AppendText(_EventLogFile))
                    {
                        sw.WriteLine(entry);
                    }
                }
            }
            catch { }
        }
        




        public DateTime StartOfTask { get { return _startThread; } }
        public Boolean IsRunningStandAlone { get { return _IsRunningStandAlone; } }
        public Profile Profile { get { return _Profile; } }
        public TaskStatus Status { get { return _Status; } }
        
        
        public virtual Boolean IsStandAloneProgrammable(Profile profile)
        {
            return _Client.IsProgrammable(profile);
        }
        
        public abstract Boolean IsControlledProgrammable(Profile profile);

        public String TaskProgress { get { return _TaskProgress; } }

        public Boolean Start(Boolean isStandAlone)
        {
            if (_Status != TaskStatus.IsRunning)
            {
                InitDataTransferLog(); // Only init if also really started
                InitEventLog();

                _Status = TaskStatus.IsRunning;

                if (isStandAlone)
                {
                    _thread = new Thread(new ThreadStart(ThreadStandAlone));
                }
                else
                {
                    _thread = new Thread(new ThreadStart(ThreadControlled));
                }
                _thread.Start();
                _startThread = DateTime.Now;
                _IsRunningStandAlone = isStandAlone;

                if(isStandAlone)
                    AddEventLog("Stand alone task started");
                else
                    AddEventLog("Controlled task started");
                
                
                return true;
            }
            return false;
        }

        public Boolean Stop()
        {
            _Status = TaskStatus.AbortRequested;

            DateTime OnStop = DateTime.Now;

            while ((_isKicking) && (OnStop.AddSeconds(20) > DateTime.Now))
                Thread.Sleep(100);

            if (_isKicking)
            {
                _thread.Abort();
                Thread.Sleep(100);
                if (_thread.Join(2000))
                    _isKicking = false;
            }

            if (!_isKicking)
                _Status = TaskStatus.Finished; // Set to finished because user invoked

            return !_isKicking;
        }


        public Boolean NextStep()
        {
            _Status = TaskStatus.NextStepRequested;

            DateTime OnStop = DateTime.Now;
            while (_Status == TaskStatus.NextStepRequested && (OnStop.AddSeconds(30) > DateTime.Now))
                Thread.Sleep(200);

            return (_Status == TaskStatus.IsRunning);
        }






        
        protected String _TaskProgress; 
        protected Thread _thread;
        protected Client _Client; public Client Client { get { return _Client; } }
        protected DateTime _startThread;
        protected Profile _Profile;
        protected Boolean _isKicking;
        protected TaskStatus _Status = TaskStatus.Starting;
        protected abstract void ThreadControlled();
        protected abstract void ThreadStandAlone();
        protected Boolean _IsRunningStandAlone;



        public Color StatusColor
        {
            get
            {
                Color color = Color.Black;

                switch (_Status)
                {
                    case TaskStatus.ExceptionOccured:
                        color = Color.Red;
                        break;
                    case TaskStatus.IsRunning:
                        color = Color.Green;
                        break;
                    case TaskStatus.Stopped:
                        color = Color.Orange;
                        break;
                    case TaskStatus.Finished:
                        color = Color.DarkGray;
                        break;
                    default:
                        color = Color.Black;
                        break;
                }
                return color;
            }
        }
    }











    public enum TaskStatus
    {
        Starting,
        IsRunning,
        AbortRequested,
        Aborted,
        Stopped,
        Interrupted,
        Finished,
        ExceptionOccured,
        NextStepRequested,
    }

    
    public static class TaskStatusExtensionMethods
    {
        public static string ToText(this TaskStatus s)
        {
            string result = s.ToString();

            switch (s)
            {
                case TaskStatus.AbortRequested:
                    result = "Abort requested";
                    break;
                case TaskStatus.ExceptionOccured:
                    result = "Exception occured";
                    break;
                case TaskStatus.IsRunning:
                    result = "Running";
                    break;
                case TaskStatus.NextStepRequested:
                    result = "Proceeding with next step";
                    break;
                default:
                    result = s.ToString();
                    break;
            }
            return result;
        }




     


    }


}
