using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.ServiceModel;
using System.IO;
using System.Threading;
using CeramillMotionRemoteControl.S1274;

namespace CeramillMotionRemoteControl
{
  public partial class App : Form
  {
    // ######################################################################
    // Member Variables
    // ######################################################################

    // Instance of S1274Client
    private S1274Client m_S1274 = null;

    // connected with CeramillMotion?
    private bool m_bConnected = false;

    // filenames used by File-I/O communication
    private string m_strFileNameExecute = "";
    private string m_strFileNameResult  = "";


    // ######################################################################
    // Methods
    // ######################################################################

    // //////////////////////////////////////////////////////////////////////
    // App (Construktor)

    public App()    
    {
      try
      {
        m_S1274 = new S1274Client();
      }
      catch (Exception ex)
      {
        MessageBox.Show (ex.ToString()); 
      }

      InitializeComponent();
    }


    // //////////////////////////////////////////////////////////////////////
    // Connect

    private void Connect()
    {
      // ---- File I/O ------------------------------------------------------
      if (m_rbComFileIo.Checked)
      {
        try
        {
          // Filenames for execute and result

          // Note:
          // You can optionally add an extension for the execute and result files - e. g. execute-123 and result-123
          // This is useful if two or more remote controllers are involved to control the CeramillMotion Application.
          // The first remote controller can write/read the files execute1 and result1, the second one uses execute2 and result2...
          // This feature is supported for CeramillMotion EST1274-49.12 or newer.
          
          m_strFileNameExecute = m_txtComFileIoPath.Text + @"\execute" + m_txtComFileIoExtension.Text;
          m_strFileNameResult  = m_txtComFileIoPath.Text + @"\result"  + m_txtComFileIoExtension.Text;

          // Delete result file
          File.Delete (m_strFileNameResult);

          // Check connection
          m_bConnected = false;
          StreamWriter srExecute = new StreamWriter (m_strFileNameExecute);
          srExecute.Write ("App.Echo;CheckConnection");
          srExecute.Close();
          Thread.Sleep(100);

          if (File.Exists (m_strFileNameResult))
          {
            m_bConnected = true;
            File.Delete (m_strFileNameResult);
          }
        }
        catch
        {
        }
      }

      // ---- Service Interface ---------------------------------------------
      else
      {
        if (m_S1274 == null)
          return;

        // call CheckConnection
        try
        {
          m_S1274.CheckConnection();
        }

        // if fails, try to connect
        catch
        {
          try
          {
            m_S1274.Abort();      
            m_S1274 = new S1274Client();
            m_S1274.Open();           
          }
          catch (Exception ex)
          {
            MessageBox.Show (ex.Message + "\n\n" + ex.InnerException.Message, "Exception");
          }
        }

        m_bConnected = (m_S1274.State == CommunicationState.Opened);
      }
    }


    // //////////////////////////////////////////////////////////////////////
    // Execute

    private void Execute()
    {
      // ---- build argument list -------------------------------------------
      List<string> listArguments = new List<string>();
      
      foreach (String strArgument in m_txtArguments.Lines)
      {
        if (strArgument.Length == 0)
          continue;
        listArguments.Add (strArgument);
      }

      // ---- execute command (File I/O) ------------------------------------
      if (m_rbComFileIo.Checked)
      {
        // write command and argument(s) into execution file
        try
        {
          StreamWriter swExecute = new StreamWriter (m_strFileNameExecute);
          swExecute.Write (m_cbCommand.Text);
          
          foreach (String strArgument in listArguments)
          {
            swExecute.Write (";" + strArgument);
          } 
          swExecute.Write ("\n");
          swExecute.Close();
        }
        catch
        {
          m_bConnected = false;
          return;
        }
                

        // wait for result file
        for (int i = 0; i < 100; i++)
        {
          Thread.Sleep(10);

          try
          {
            if (File.Exists(m_strFileNameResult))
            {
              StreamReader srResult = new StreamReader (m_strFileNameResult);
              string[] astrResult = srResult.ReadLine().Split (new Char[] {';', '\t' } );
              srResult.Close();

              // delete result file
              File.Delete (m_strFileNameResult);

              // list result(s)
              foreach (String strResult in astrResult)
              {
                m_txtResult.Text += strResult + "\r\n";
              }

              // scroll to end of textbox
              m_txtResult.SelectionStart = m_txtResult.TextLength - 1;
              m_txtResult.ScrollToCaret();

              return;
            }
          }
          catch {};
        }

        m_bConnected = false;
      }


      // ---- execute command (Service Interface) ---------------------------
      else
      {
        if (m_S1274 == null)
          return;

        try
        {
          List<string> listResult = m_S1274.Execute (m_cbCommand.Text, listArguments);

          // list result(s)
          foreach (String strResult in listResult)
          { 
            m_txtResult.Text += strResult + "\r\n";
          }

          // scroll to end of textbox
          m_txtResult.SelectionStart = m_txtResult.TextLength - 1;
          m_txtResult.ScrollToCaret();
        }
        catch
        {
          m_bConnected = false;
        }
      }
    }


    // ######################################################################
    // Event-Handlers
    // ######################################################################

    // //////////////////////////////////////////////////////////////////////
    // App_Load

    private void App_Load(object sender, EventArgs e)
    {
      // restore settings
      m_rbComFileIo     .Checked = Properties.Settings.Default.bComFileIo;
      m_txtComFileIoPath.Text    = Properties.Settings.Default.strComFileIoPath;

      // fill command ComboBox items with content from textfile
      string[] astrCommands = File.ReadAllLines("CeramillMotionRemoteControl.Commands.txt");
      foreach (string strCommand in astrCommands)
      {
        m_cbCommand.Items.Add (strCommand);
      }
    }


    // //////////////////////////////////////////////////////////////////////
    // App_FormClosing

    private void App_FormClosing(object sender, FormClosingEventArgs e)
    {
      // save settings
      Properties.Settings.Default.bComFileIo       = m_rbComFileIo     .Checked;
      Properties.Settings.Default.strComFileIoPath = m_txtComFileIoPath.Text;
      Properties.Settings.Default.Save();
    }


    // //////////////////////////////////////////////////////////////////////
    // m_btnBrowseComFileIoPath_Click

    private void m_btnBrowseComFileIoPath_Click(object sender, EventArgs e)
    {
      // select File I/O path
      m_FolderBrowserDialogComFileIoPath.SelectedPath = m_txtComFileIoPath.Text;
      if (m_FolderBrowserDialogComFileIoPath.ShowDialog() == DialogResult.OK)
        m_txtComFileIoPath.Text = m_FolderBrowserDialogComFileIoPath.SelectedPath;
    }


    // //////////////////////////////////////////////////////////////////////
    // m_btnConnect_Click

    private void m_btnConnect_Click(object sender, EventArgs e)
    {
      // try to connect to CeramillMotion
      Connect();

      // focus to command if connection ok
      if (m_bConnected)
      {
        m_gbExectue.Enabled = true;
        m_cbCommand.Focus();
      }
    }


    // //////////////////////////////////////////////////////////////////////
    // m_cbCommand_KeyDown

    private void m_cbCommand_KeyDown(object sender, KeyEventArgs e)
    {
      // check for enter key
      if (e.KeyData == Keys.Enter)
      {
        e.SuppressKeyPress = true;
        Execute();
      }
    }


    // //////////////////////////////////////////////////////////////////////
    // m_btnExecute_Click

    private void m_btnExecute_Click(object sender, EventArgs e)
    {
      Execute();
    }


    // //////////////////////////////////////////////////////////////////////
    // m_btnClearArguments_Click

    private void m_btnClearArguments_Click(object sender, EventArgs e)
    {
      m_txtArguments.Clear();
    }


    // //////////////////////////////////////////////////////////////////////
    // m_btnClearResult_Click

    private void m_btnClearResult_Click(object sender, EventArgs e)
    {
      m_txtResult.Clear();
    }


    // //////////////////////////////////////////////////////////////////////
    // m_timerRun_Tick

    private void m_timerRun_Tick(object sender, EventArgs e)
    {
      // enable if connection is ok
      m_gbExectue.Enabled = m_bConnected;
      m_gbResult .Enabled = m_bConnected;

      // empty command makes no sense
      m_btnExecute.Enabled = m_cbCommand.Text.Length > 0;
      
      // connection status
      if (m_bConnected)
        m_lblStatus.Text = "Connected";
      else
        m_lblStatus.Text = "Not Connected";
    }
  }
}
