//-------------------------------------------------------------------------------------
// SID Monitor - Utility for Sudden Ionospheric Disturbances Monitoring Stations
// Copyright (C) 2006 - Lionel Loudet
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//-------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Diagnostics;
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading;


namespace SID_monitor
{

    #region RRDTool as an executable
    public static class RRDToolProcess
    {
        public enum ShowOptions { ErrorsOnly, ErrorsAndStdIn, ErrorsAndStdOut, All };

        private static int ThreadTimeout = SID_monitor.Properties.Settings.Default.RRDToolExecutableTimeout;      // timeout for completion of RRDTool process

        private static Process currentRRDToolProcess;
        private static string ProcessOutput;         // the string that contains the rrdtool executable standard output
        private static string ProcessWarning;        // the string that contains warning on rrdtool execution time
        private static string ProcessError;          // the string that contains the rrdtool executable standard error
        private static string ProcessArgs;           // the rrdtool executable arguments


        public static string SendData(string DataToSend, ShowOptions showOptions, IntPtr outputTextBoxFormHandle)
        {
            // the outputTextBox that will display the messages
            OutputTextBox outputTextBox = null;

            try
            {
                // we set its value according to the type of the control associated to the handle provided (dockable or not).
                if (System.Type.Equals(Control.FromHandle(outputTextBoxFormHandle).GetType(), typeof(SID_monitor.OutputTextBoxDockablePanel)))
                {
                    outputTextBox = ((SID_monitor.OutputTextBoxDockablePanel)Control.FromHandle(outputTextBoxFormHandle)).OutputTextBox;
                }
                else
                {
                    outputTextBox = ((SID_monitor.OutputTextBox)Control.FromHandle(outputTextBoxFormHandle));
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Cannot display RRDTool messages.\n" + ex.ToString().Split('\n')[0], "Internal Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            try
            {
                ProcessOutput = String.Empty;
                ProcessWarning = String.Empty;
                ProcessError = String.Empty;
                ProcessArgs = DataToSend;
                Thread currentThreadRRDToolProcess = new Thread(new ThreadStart(ThreadRRDToolProcess));

                currentThreadRRDToolProcess.Start();

                if ((outputTextBox != null) && (currentThreadRRDToolProcess.Join(ThreadTimeout) == false))
                {
                    outputTextBox.AddOutputTextWarningMessage("Timeout exceeded for RRDTool process execution.\n");
                }

            }
            catch (Exception ex)
            {
                ProcessError = ex.ToString().Split('\n')[0] + "\n";
            }

            try
            {
                if ((outputTextBox != null) && ((showOptions == ShowOptions.ErrorsAndStdIn) || (showOptions == ShowOptions.All)))
                {
                    outputTextBox.AddOutputTextRRDToolMessage("rrdtool " + DataToSend);
                }
                if ((outputTextBox != null) && ((ProcessOutput.Length > 0) && ((showOptions == ShowOptions.ErrorsAndStdOut) || (showOptions == ShowOptions.All))))
                {
                    outputTextBox.AddOutputTextRRDToolMessage(ProcessOutput);
                }
                if ((outputTextBox != null) && (ProcessWarning.Length > 0))
                {
                    outputTextBox.AddOutputTextWarningMessage(ProcessWarning);
                }
                if ((outputTextBox != null) && (ProcessError.Length > 0))
                {
                    outputTextBox.AddOutputTextRRDToolErrorMessage(ProcessError);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Cannot display RRDTool messages.\n" + ex.ToString().Split('\n')[0], "Internal Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return ProcessOutput;

        }

        /// <summary>
        /// The thread that runs the rrdtool executable
        /// </summary>
        private static void ThreadRRDToolProcess()
        {
            try
            {
                currentRRDToolProcess = new Process();

                currentRRDToolProcess.StartInfo.FileName = SID_monitor.Properties.Settings.Default.RRDToolPath;
                currentRRDToolProcess.StartInfo.Arguments = ProcessArgs;
                currentRRDToolProcess.StartInfo.EnvironmentVariables.Add("TZ", "UTC");
                currentRRDToolProcess.StartInfo.CreateNoWindow = true;
                currentRRDToolProcess.StartInfo.UseShellExecute = false;
                currentRRDToolProcess.StartInfo.RedirectStandardError = true;
                currentRRDToolProcess.StartInfo.RedirectStandardOutput = true;

                currentRRDToolProcess.Start();

                Thread ThreadProcessError = new Thread(new ThreadStart(ReadRRDToolProcessErrorOutput));
                Thread ThreadProcessOutput = new Thread(new ThreadStart(ReadRRDToolProcessOutput));

                ThreadProcessError.Start();
                ThreadProcessOutput.Start();

                if (ThreadProcessError.Join(ThreadTimeout) == false)
                {
                    ProcessWarning = "Timeout exceeded for RRDTool process execution.\n";
                }

                if (ThreadProcessOutput.Join(ThreadTimeout) == false)
                {
                    ProcessWarning = "Timeout exceeded for RRDTool process execution.\n";
                }

            }
            catch (Exception ex)
            {
                ProcessError = ex.ToString().Split('\n')[0] + "\n";
            }
        }

        /// <summary>
        /// The thread that catches the rrdtool process standard error
        /// </summary>
        private static void ReadRRDToolProcessErrorOutput()
        {
            ProcessError = currentRRDToolProcess.StandardError.ReadToEnd();
        }

        /// <summary>
        /// The thread that catches the rrdtool process standard output
        /// </summary>
        private static void ReadRRDToolProcessOutput()
        {
            ProcessOutput = currentRRDToolProcess.StandardOutput.ReadToEnd();
        }
    }
    #endregion







    static class RRDToolConnection
    {

        public static string ExecuteRRDTool(string DataToSend, RRDToolProcess.ShowOptions showOptions, IntPtr outputTextBoxFormHandle)
        {
            if (outputTextBoxFormHandle != IntPtr.Zero)
            {
                return RRDToolProcess.SendData(DataToSend, showOptions, outputTextBoxFormHandle);
            }
            else
            {
                return RRDToolProcess.SendData(DataToSend, showOptions, Program.MainForm.outputTextBoxDockablePanel.Handle);
            }
        }

        public static string ExecuteRRDTool(string DataToSend, RRDToolProcess.ShowOptions showOptions)
        {
            return RRDToolProcess.SendData(DataToSend, showOptions, Program.MainForm.outputTextBoxDockablePanel.Handle);
        }

    }

}