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 SendNumericDataToWks
{
	/// <summary>
	/// Summary description for Form1.
	/// </summary>
    public partial class Form1 : Form
	{
		public Form1()
		{		
			InitializeComponent();	
		}

        private static Random m_rndGen = new Random();	// Random number generator
        private static int m_Row1 = 1;
		private	Origin.IOApplication m_originApp;		// Origin object reference		
        

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

		private void Disconnect()
		{
			if( IsConnected() )
			{
				// If user wants to save the project...
				if( checkSaveProjOnDisconn.Checked )
				{
					// If user provided a file name then tell Origin to save the project.
					if( 0 < textSaveProjName.Text.Length )
					{
						if( !m_originApp.Save(textSaveProjName.Text) )
							ShowErrorMessage("Failed to save Origin project.");
					}
				}

				// Exit Origin if needed:
				if( checkExitOnDisconn.Checked )
					m_originApp.Exit();

                System.Runtime.InteropServices.Marshal.FinalReleaseComObject(m_originApp);
				m_originApp = null;

				// Enable or disable various controls after disconnect:
				EnableControls(false);
			}	
		}

		private bool Connect()
		{
			Disconnect(); // If already connected then disconnect.

			try
			{
				if( radioExisting.Checked )
					m_originApp = new Origin.ApplicationSI(); // SI to connect to existing Origin.
				else
					m_originApp = new Origin.Application(); // non-SI to connect to new Origin.
			}
			catch (Exception e)
			{
				ShowErrorMessage(e.Message);
			}

			bool bConnected = IsConnected();

			if ( bConnected )
			{
                if (checkShowAppWnd.Checked)
                    m_originApp.Visible = Origin.MAINWND_VISIBLE.MAINWND_SHOW; // Show the Origin application window
                else
                    m_originApp.Visible = Origin.MAINWND_VISIBLE.MAINWND_HIDE; //hide main window
				textSaveProjName.Text = GetSaveAsFileName(); // Init file name for saving
			}
			else
			{
				m_originApp = null;
				ShowErrorMessage("Failed to connect to Origin.");
			}

			EnableControls(bConnected); // Update dialog controls based on connection status.

			return bConnected; // Return connection status.
		}

		private void SendData()
		{
            // Check for connection to Origin.
            if( !IsConnected() )
	            return;

            int nColumns = CheckAndGetNumberOfColumns();
            if (nColumns <= 0)
	            return;

            int nRows = CheckAndGetNumberOfRows();
            if( nRows <= 0 )
	            return;

            Origin.Worksheet wks = CheckAndGetWorksheet(true); // true = make if does not exist
            if( null == wks )
	            return;
            // Create some random data.
            double [, ] dData = new double[nRows, nColumns];
            for (int nCol = 0; nCol < nColumns; nCol++)
            {
	            for (int nRow = 0; nRow < nRows; nRow++)
	            {
		            if (0 == nCol)
                        dData[nRow, nCol] = nRow + m_Row1;
		            else
			            dData[nRow, nCol] = ((nRow + 1) * 10 + nCol) * m_rndGen.NextDouble();
	            }
            }
            m_Row1 += nRows;
            //If user wants to append data, -1 should be used and it will trigger the proper realtime charting in Origin
            //support for Worksheet -1 to append requires SR5, but -1 to append in Column.SetData was supported in SR4
            int r1 = checkAppendAsNewRows.Checked? -1:0;
            wks.SetData(dData, r1, 0);
            ///Sophy 7/14/2009 SHOULD_RELEASE_COM_OBJ_AFTER_USE_IT
            ///reason for why make this change is given at the end of this class
            System.Runtime.InteropServices.Marshal.ReleaseComObject(wks);
            ///end SHOULD_RELEASE_COM_OBJ_AFTER_USE_IT
		}

		private void EnableControls(bool bEnable)
		{
			buttonDisconnect.Enabled = bEnable;
			buttonClearWks.Enabled = bEnable;
			buttonSendData.Enabled = bEnable;
			buttonConnect.Enabled = !bEnable;
		}

		private string GetSaveAsFileName()
		{
			string str = "";
			if (IsConnected())
                //%Y is the labtalk string register to hold the current user file folder path
                //%G is the current project file name
				str = m_originApp.get_LTStr("%Y") + m_originApp.get_LTStr("%G");
			return str;
		}

		private string CheckAndGetWorkbookName()
		{
			string strWkbkName = textWorkbook.Text;
			strWkbkName.Trim();
			if (0 == strWkbkName.Length)
				ShowErrorMessage("Please provide a workbook name.");
			return strWkbkName;
		}

		private string CheckAndGetWorksheetName()
		{
			string strWksName = textWorksheet.Text;
			strWksName.Trim();
			if (0 == strWksName.Length)
				ShowErrorMessage("Please provide a worksheet name.");
			return strWksName;
		}

		private int CheckAndGetNumberOfColumns()
		{
			string strColumns = textColumns.Text;
			strColumns.Trim();
			int nColumns = int.Parse(strColumns);
			if (nColumns <= 0)
				ShowErrorMessage("Please provide a number of columns greater than zero.");
			return nColumns;
		}

		private int CheckAndGetNumberOfRows()
		{
			string strRows = textRows.Text;
			strRows.Trim();
			int nRows = int.Parse(strRows);
			if (nRows <= 0)
				ShowErrorMessage("Please provide a number of rows greater than zero.");
			return nRows;
		}

		private Origin.Worksheet CheckAndGetWorksheet(bool bCreateIfNotFound)
		{
			string strBookName = CheckAndGetWorkbookName();
			if (strBookName.Length <= 0)
				return null;

			string strSheetName = CheckAndGetWorksheetName();
			if (strSheetName.Length <= 0)
				return null;
            ///Sophy 12/10/2009 NUMERIC_SHEETNAME_SUPPORT_CAUSE_INCONSISTENCY_IN_FINDWORKSHEET_AND_ADDLAYER
            /*
			// Use the book name and sheet name to make a range string.
			string strWksName = "[" + strBookName + "]" + strSheetName;

			// Ask Origin to find the worksheet.
			Origin.Worksheet wks = m_originApp.FindWorksheet(strWksName);
            */
            Origin.WorksheetPage wksPage = GetWorksheetPage(strBookName, bCreateIfNotFound);
            Origin.Worksheet wks = GetWorksheet(strBookName, strSheetName, bCreateIfNotFound);
            ///end NUMERIC_SHEETNAME_SUPPORT_CAUSE_INCONSISTENCY_IN_FINDWORKSHEET_AND_ADDLAYER
			if( null == wks )
			{
				if( bCreateIfNotFound )
				{
					wks = GetWorksheet(strBookName, strSheetName, bCreateIfNotFound);
					if (null == wks)
						ShowErrorMessage("Failed to create a new worksheet.");
				}
				else
					ShowErrorMessage("The named worksheet does not exist.");
			}
			return wks;
		}

		private Origin.WorksheetPage GetWorksheetPage(string strPageName, bool bCreateIfNotFound)
		{
			// Ask Origin to find the workbook.
			Origin.WorksheetPage wksPg = m_originApp.WorksheetPages[strPageName];

			// If the workbook and caller wants it created...
			if( null == wksPg && bCreateIfNotFound )
			{
				// Create a new workbook.
				strPageName = m_originApp.CreatePage((int)Origin.PAGETYPES.OPT_WORKSHEET, strPageName, "W", 2);
				wksPg = m_originApp.WorksheetPages[strPageName];
			}

			return wksPg;
		}

		private Origin.Worksheet GetWorksheet(string strPageName, string strSheetName, bool bCreateIfNotFound)
		{
			// Get the worksheet page.
			Origin.WorksheetPage wksPg = GetWorksheetPage(strPageName, bCreateIfNotFound);
			if( null == wksPg )
				return null;

			// Ask Origin to find the worksheet.
			Origin.Worksheet wks = (Origin.Worksheet)wksPg.Layers[strSheetName];
			if( null == wks && bCreateIfNotFound )
				wks = (Origin.Worksheet)wksPg.Layers.Add(strSheetName, 0, null, 0, null);
			
			return wks;
		}

		private void ShowErrorMessage(string strMsg)
		{
			MessageBox.Show(strMsg, this.Text);
		}

		private void buttonConnect_Click(object sender, System.EventArgs e)
		{
			Connect();
		}

		private void checkShowAppWnd_Click(object sender, System.EventArgs e)
		{
			if( IsConnected() )
			{
				if (checkShowAppWnd.Checked)
					m_originApp.Visible = Origin.MAINWND_VISIBLE.MAINWND_SHOW;
				else
					m_originApp.Visible = Origin.MAINWND_VISIBLE.MAINWND_HIDE;
			}
		}

		private void buttonDisconnect_Click(object sender, System.EventArgs e)
		{
			Disconnect();
		}

		private void checkSaveProjOnDisconn_Click(object sender, System.EventArgs e)
		{
			textSaveProjName.Enabled = checkSaveProjOnDisconn.Checked;
		}

		private void buttonSendData_Click(object sender, System.EventArgs e)
		{
			SendData();
		}

        private void buttonClearWks_Click(object sender, System.EventArgs e)
        {
            Origin.Worksheet wks = CheckAndGetWorksheet(false);
            ///Sophy 7/14/2009 SHOULD_RELEASE_COM_OBJ_AFTER_USE_IT
            ///reason for why make this change is given at the end of this class
            //if (null != wks)
            //    wks.ClearData(0, -1);
            if (null != wks)
            {
                wks.ClearData(0, -1);
                System.Runtime.InteropServices.Marshal.ReleaseComObject(wks);
            }
            ///end SHOULD_RELEASE_COM_OBJ_AFTER_USE_IT
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (IsConnected())
            {
                System.Runtime.InteropServices.Marshal.FinalReleaseComObject(m_originApp);
                m_originApp = null;
            }
        }

        ///Sophy 7/14/2009 SHOULD_RELEASE_COM_OBJ_AFTER_USE_IT
        ///When I try this example I get the follow result:
        /// 1. Run \Samples\Automation Server\CSharp\SendNumericDataToWks\SendNumericDataToWks.exe
        //2. Launch Origin first and Connect to existing Origin instance
        //3. Click Send Data. or Click Clear Worksheet.
        //4. Click Disconnect.
        //5. Try to Close Origin manully. //==> Say "Origin cannot be closed because it is being controlled by another application"


        //1. Run \Samples\Automation Server\CSharp\SendNumericDataToWks\SendNumericDataToWks.exe
        //2. Connect to existing Origin instance
        //3. Click Disconnect.
        //4. Try to Close Origin manully. //-->Closed directly or Ask whether to save project, and this correct.


        //I debug in v8.1063, and found that if I connect to Origin and never click "Send Data" or "Clear Worksheet", then I click Disconnect button, it will go into "COKCOMAppSingleInstance::OnFinalRelease()"
        //and this is correct. But if I click "Send Data" or "Clear Worksheet" after connect to Origin, then click "Disconnect", it will not go into "COKCOMAppSingleInstance::OnFinalRelease()
        //" until I close the COM client dialog. Indeed, OnFinalRelease() is called only when InterlockedDecrement(&m_dwRef) return 0.
        ///end SHOULD_RELEASE_COM_OBJ_AFTER_USE_IT
	}
}
