using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenNI;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;

namespace Kinect_viewer.Projection
{
    
    /// <summary>
    /// Depth_projection is derrived form AProjection class a nd implements methods of IProjection interface
    /// </summary>
    internal class Depth_projection : AProjection, IProjection
    {
        private Form1 form;        
        private DepthMetaData depthMD;
        private int[] hist = new int[10000];
        /// <summary>
        /// Constructor of this object
        /// </summary>
        /// <param name="form"></param>
        public Depth_projection(Form1 form)
            : base()
        {
            this.form = form;
            this.histogram = new int[this.depth.DeviceMaxDepth];
           
        }
        /// <summary>
        /// This reads all depth data a crates histogram
        /// </summary>
        public unsafe void ReaderThread()
        {
            depthMD = new DepthMetaData();
            while (this.ShouldRun)
            {
                try
                {
                    this.context.WaitAnyUpdateAll();
                }
                catch (Exception e)
                {
                    throw e;
                }
                this.depth.GetMetaData(depthMD);
                CreateHistogramData(depthMD);
                lock (imageBitmap)
                {
                    // Debug.WriteLine(depthMD[153280].ToString());
                    lock (imageBitmap)
                    {
                        Rectangle rect = new Rectangle(0, 0, this.ImageBitmap.Width, this.ImageBitmap.Height);
                        BitmapData data = this.ImageBitmap.LockBits(rect, ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); 
                    
                    byte* pSrc = (byte*)image.ImageMapPtr.ToPointer();
                    ushort* pDepth = (ushort*)this.depth.DepthMapPtr.ToPointer();
                    for (int y = 0; y < depthMD.YRes; ++y)
                    {//Scan0 vrátí hodnotu prvního řádku a stride postupně načte všechny řádky
                        byte* pDest = (byte*)data.Scan0.ToPointer() + y * data.Stride;
                       // byte* pDest2 = (byte*)imageData.Scan0.ToPointer() + y * imageData.Stride;
                        for (int x = 0; x < depthMD.XRes; ++x, ++pDepth, pDest += 3,  pSrc += 3)
                        {//Setting projection color
                            byte pixel = (byte)this.histogram[*pDepth];
                            pDest[0] = 0;//B
                            pDest[1] = pixel;//G
                            pDest[2] = pixel;//R
                        }
                    }
                    this.ImageBitmap.UnlockBits(data);
                    }
                    //Thread.Sleep(100);
                   // this.imageBitmap.UnlockBits(imageData);  
                   // ((Form1)form).SetDepthDataToDraw(this.ImageBitmap);
                    ((Form1)form).SetDepthDataToDraw(this.ImageBitmap); 
                }
                //Překreslení           
                //((Form1)form).SetHist(hist);
                //Thread.Sleep(20);
                
                Thread.Sleep(100);
                
                
            }
        }
        /// <summary>
        /// Creates histogram data and conveting tis to the values up to 256
        /// </summary>
        /// <param name="depthMD"></param>
        private unsafe void CreateHistogramData(DepthMetaData depthMD)
        {
            //Clear this histogram.
            for (int i = 0; i < this.histogram.Length; ++i)
            {
                this.histogram[i] = 0;
                this.hist[i] = 0;
            }

            ushort* pDepth = (ushort*)depthMD.DepthMapPtr.ToPointer();

            int points = 0;
            for (int y = 0; y < depthMD.YRes; ++y)
            {
                for (int x = 0; x < depthMD.XRes; ++x, ++pDepth)
                {
                    ushort depthVal = *pDepth;
                    if (depthVal != 0)
                    {
                        this.histogram[depthVal]++;
                        //
                        this.hist[depthVal]++;
                        //
                        points++;
                    }
                }
            }
            //((Form1)form).SetHist(histogram);
            for (int i = 1; i < this.histogram.Length; i++)
            {
                this.histogram[i] += this.histogram[i - 1];
            }
            if (points > 0)
            {
                for (int i = 1; i < this.histogram.Length; i++)
                {
                    this.histogram[i] = (int)(256 * (1.0f - (this.histogram[i] / (float)points)));
                }
            }
        }
    }
}
