using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Origin;//to allow using MatrixObject etc with Origin.

namespace Realtime_Send_Matrix_View_Image
{
    public partial class Form1 : Form
    {
        const int NUM_ROWS = 500;
        const int NUM_COLS = 600;
        const int NUM_COLORS = 256; // for view image, this is the only supported number of colors, but image plot can be more flexible

        object Default = System.Type.Missing;
        private Origin.ApplicationSI m_app;
        private MatrixPage m_mpg;
        private MatrixSheet m_msht;
        private MatrixObject m_mObj;
        private DataPlot m_plot;
        private int m_nSendCount = 0;

        public Form1()
        {
            InitializeComponent();
            //StartStop.Enabled = true;
            //timer1.Enabled = false;
            //StartStop.Enabled = false;// enable after init
            EnableControls(false);
        }
        // we are filling the matrix with r + c from 0
        // so the range of values in the matrix is from 0 to this value
        private ushort getMaxValue()
        {
            return (NUM_ROWS - 1) + (NUM_COLS - 1);
        }
        private int RGB(int red, int green, int blue)
        {
            int nn = red & 0x000000FF;
            nn += (green & 0x000000FF) << 8;
            nn += (blue & 0x000000FF) << 16;
            return nn;
        }
        private Boolean setZColormap(ColorMap map)
        {
            // initiliaze the colormap to view the image
            double[] zLevels = new double[NUM_COLORS + 1]; // if 1 color, then need Z below and above, so n+1
            int[] zColors = new int[NUM_COLORS];
            for (int ii = 0; ii < NUM_COLORS + 1; ii++)
                zLevels[ii] = ii * getMaxValue() / NUM_COLORS;
            // generate color ramp from Blue to Red, no Green
            for (int jj = 0; jj < NUM_COLORS; jj++)
            {
                int red = jj * 255 / (NUM_COLORS - 1);
                int blue = (NUM_COLORS - 1 - jj) * 255 / (NUM_COLORS - 1);
                zColors[jj] = RGB(red, 0, blue);
            }
            return map.SetLevels(zLevels, zColors);
        }
        private void Init_Click(object sender, EventArgs e)
        {
            m_app = new Origin.ApplicationSI();
            m_app.NewProject();

            m_app.Visible = MAINWND_VISIBLE.MAINWND_SHOW;

            m_mpg = m_app.MatrixPages.Add(Default, Default);
            m_msht = m_mpg.Layers[0] as MatrixSheet;
            m_msht.Cols = NUM_COLS;
            m_msht.Rows = NUM_ROWS;

            m_mObj = m_msht.MatrixObjects.Add();
            m_mObj.DataFormat = COLDATAFORMAT.DF_USHORT; // unsign short

            m_mObj.ViewImage = true;
            //setZColormap();
            //Init.Enabled = false;//once init, we will not need to execute this again
            EnableControls(true); //once connected should update button status

        }

        private void EnableControls(bool bConnected)
        {
            SendOnce.Enabled = bConnected;
            SetColormap.Enabled = bConnected;
            SetPlotColormap.Enabled = bConnected;
            StartStop.Enabled = bConnected;

            Init.Enabled = !bConnected;
        }

        private void StartStop_Click(object sender, EventArgs e)
        {
            if (!timer1.Enabled)
            {
                timer1.Interval = Int32.Parse(comboDelayTime.Text);
                StartStop.Text = "Stop";
                timer1.Start();
            }
            else
            {
                StartStop.Text = "Start";
                timer1.Stop();
            }
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            if (m_mObj != null)
            {
                ushort[,] usData = new ushort[NUM_ROWS, NUM_COLS];
                int nn = m_nSendCount++;
                for (int nr = 0; nr < NUM_ROWS; nr++)
                {
                    for (int nc = 0; nc < NUM_COLS; nc++)
                    {
                        int kk = nc + nr;
                        int even = nn % 2; // every other time will flip the matrix
                        if (even == 1 && nr > NUM_ROWS/2)// flip only the bottom half to allow some stationary image
                            kk = getMaxValue() - kk;

                        usData[nr, nc] = (ushort)kk;
                    }
                }
                msgOutBox.Text = "Sending block " + nn.ToString() + "...";
                m_mObj.SetData(usData, 0, 0);
            }
            else
				msgOutBox.Text = "Matrix data not found.";
        }
        private void comboDelayTime_SelectedIndexChanged(object sender, EventArgs e)
        {
            // don't really need to do anything here
        }
        private void SetColormap_Click(object sender, EventArgs e)
        {
            if (m_mObj != null)
            {
                if (setZColormap(m_mObj.ColorMap))
                    msgOutBox.Text = "Matrix Colormap has been set.";
                else
                    msgOutBox.Text = "Matrix Colormap failed to set.";
            }
            else
				msgOutBox.Text = "Matrix data not found.";
        }

        private void SetPlotColormap_Click(object sender, EventArgs e)
        {
            if (null == m_plot)
            {
                GraphLayer glay = m_app.FindGraphLayer("Graph1");
                if (glay != null)
                {
                    m_plot = glay.DataPlots[0];
                }
            }
            if (m_plot != null)
            {
                if (setZColormap(m_plot.ColorMap))
                    msgOutBox.Text = "Plot Colormap has been set.";
                else
                    msgOutBox.Text = "Plot Colormap failed to set.";
            }
            else
                msgOutBox.Text = "Plot not found.  Plot the matrix in a graph window named \"Graph1\".";
        }

        private void SendOnce_Click(object sender, EventArgs e)
        {
            timer1_Tick(null, e);
        }

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

     }
}