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;

namespace Realtime_Send_Data_To_Wks
{
	public partial class Form1 : Form
	{
		public Form1()
		{
			InitializeComponent();
			m_startTickCount = Environment.TickCount;
		}
        
		private void ShowMessage(string strMsg)
		{
			msgTextBox.Text = strMsg;
		}

		private static Random m_rnd = new Random();
		private Origin.IOApplication m_originApp;
		private Origin.Worksheet m_targetWks;
		private ulong m_sendCount = 0;
		private long m_startTickCount;

		private bool IsConnectedToOrigin()
		{
			return m_originApp != null;
		}

		private bool ConnectToOrigin()
		{
			DisconnectFromOrigin();

			try
			{
				if (existingInstanceCheckBox.Checked)
					m_originApp = new Origin.ApplicationSI(); // SI for existing instance
				else
					m_originApp = new Origin.Application(); // non-SI for new instance
			}
			catch (Exception e)
			{
				string strMsg = "Failed to connect to Origin.\n" + e.Message;
				ShowMessage(strMsg);
			}

			return IsConnectedToOrigin();
		}

		private void DisconnectFromOrigin()
		{
			if (IsConnectedToOrigin())
			{
				System.Runtime.InteropServices.Marshal.FinalReleaseComObject(m_originApp);
				m_originApp = null;
			}
		}

		private void GetOriginProjectFileName(ref string strFileName)
		{
			strFileName = projectEditBox.Text;
			if (strFileName.StartsWith("Samples\\", StringComparison.OrdinalIgnoreCase))
				strFileName = m_originApp.get_LTStr("system.path.program$") + projectEditBox.Text;
		}

		private bool PrepareOrigin()
		{
			string str1 = "", str2 = "";

			m_originApp.Visible = Origin.MAINWND_VISIBLE.MAINWND_SHOW;

			// ---------- Open user specified project
			GetOriginProjectFileName(ref str1);
			if (!m_originApp.Load(str1, false))
			{
				ShowMessage("Failed to load Origin project\r\n" + str1);
				return false;
			}

			// ---------- Get user specified target worksheet
			GetPageAndSheetName(ref str1, ref str2);

			// ---------- Attach to target worksheet
			m_targetWks = GetOriginWorksheet(str1, str2, true); // true = create if not found
			if (null == m_targetWks)
			{
				ShowMessage("Failed to get or create worksheet.");
				return false;
			}

			// ---------- Clear target worksheet
			m_targetWks.ClearData(0, -1);

			// ---------- Make sure target worksheet has 3 columns
			if (m_targetWks.Cols < 3)
				m_targetWks.Columns.Add("C");

			// ---------- Set column long names and units
			m_targetWks.Columns[0].LongName = "Time";
			m_targetWks.Columns[0].Units = "(sec)";
			m_targetWks.Columns[1].LongName = "Sine";
			m_targetWks.Columns[1].Units = "a.u.";
			m_targetWks.Columns[2].LongName = "Square";
			m_targetWks.Columns[2].Units = "a.u.";

			// ---------- Add data columns to Graph1
			Origin.GraphPage gp = m_originApp.GraphPages["Graph1"];
			if (null != gp)
			{
				Origin.GraphLayer gl = (Origin.GraphLayer)gp.Layers[0];
				if (null != gl)
				{
					Origin.DataRange dr = m_targetWks.NewDataRange(0, 0, -1, 2);
					gl.DataPlots.Add(dr, Origin.PLOTTYPES.IDM_PLOT_LINE);

					gl.Execute("layer.x.to = 25;");
					gl.Execute("layer.y.from = -1.25; layer.y.to = 1.25;");

					// Setup the Y axis to auto adjust the scale to fit any data
					// points that are less than or greater than the scale's range.
					gl.Execute("layer.disp = layer.disp | hex(1000);");
				}
				else
					ShowMessage("Failed to get graph layer.");
			}
			else
				ShowMessage("Failed to get graph page named \"Graph1\".");

			return true;
		}

		private void GetPageAndSheetName(ref string strPageName, ref string strSheetName)
		{
			int i1 = targetTextBox.Text.IndexOf('[');
			int i2 = targetTextBox.Text.IndexOf(']');
			if (0 <= i1 && i1 < i2)
			{
				i1++;
				strPageName = targetTextBox.Text.Substring(i1, i2 - i1);
				strSheetName = targetTextBox.Text.Substring(i2 + 1);
			}
			if (0 == strPageName.Length)
				strPageName = "Book1";
			if (0 == strSheetName.Length)
				strSheetName = "Sheet1";
		}

		private Origin.WorksheetPage GetOriginWorksheetPage(string strPageName, bool bCreateIfNotFound)
		{
			Origin.WorksheetPage wksPg = m_originApp.WorksheetPages[strPageName];
			if (null == wksPg && bCreateIfNotFound)
			{
				strPageName = m_originApp.CreatePage((int)Origin.PAGETYPES.OPT_WORKSHEET, strPageName, "W", 2);
				wksPg = m_originApp.WorksheetPages[strPageName];
			}
			return wksPg;
		}

		private Origin.Worksheet GetOriginWorksheet(string strPageName, string strSheetName, bool bCreateIfNotFound)
		{
			Origin.WorksheetPage wksPg = GetOriginWorksheetPage(strPageName, bCreateIfNotFound);
			if (null == wksPg)
				return null;

			Origin.Worksheet wks = (Origin.Worksheet)wksPg.Layers[strSheetName];
            if (null == wks && bCreateIfNotFound)
            {
                wks = (Origin.Worksheet)wksPg.Layers.Add(strSheetName, 0, null, 0, null);
                wks.Activate();
            }

			return wks;
		}

		private void startStopButton_Click(object sender, EventArgs e)
		{
			ShowMessage(""); // clear message box         

            if (!IsConnectedToOrigin())
            {
                if (ConnectToOrigin())
                {
                    if (!PrepareOrigin())
                    {
                        DisconnectFromOrigin();
                    }
                }
            }

            if (!sendDataTimer.Enabled)
			{
				targetTextBox.Enabled = false;
				rateTextBox.Enabled = false;
				startStopButton.Text = "Stop Sending Data";

				m_startTickCount = Environment.TickCount;

				sendDataTimer.Interval = 1000 / Int32.Parse(rateTextBox.Text);
				sendDataTimer.Start();
			}
			else
			{
				targetTextBox.Enabled = true;
				rateTextBox.Enabled = true;
				startStopButton.Text = "Restart Sending Data";

                sendDataTimer.Stop();                
			}
		}

		private void sendDataTimer_Tick(object sender, EventArgs e)
		{
			double[,] data = new double[1, 3]; // 1 row, 3 columns
            data[0, 0] = m_sendCount / 10.0;
			data[0, 1] = (Math.Sin(data[0, 0]) + (m_rnd.NextDouble() * 0.05)) * data[0, 0];
			data[0, 2] = (Math.Sign(Math.Sin(data[0, 0]) * data[0, 0]));

			m_targetWks.SetData(data, -1, 0); // -1 for append row, 0 for first column

			m_sendCount++;
			numSentTextBox.Text = Convert.ToString(m_sendCount);
		}       

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            DisconnectFromOrigin();
        }   
        
	}
}
