using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using yoseen = YoseenSDKCS;

namespace YoseenDemoWpf.TempCanvasDef
{
    /// <summary>
    /// temp canvas for wpf, !!!refrence implemention
    /// </summary>
    public class TempCanvas : Canvas
    {
        internal readonly VisualCollection _visualList;
        internal readonly TempCanvasD2D _D2D;

        readonly DrawingVisual _dvMain;

        #region canvas
        protected override int VisualChildrenCount
        {
            get
            {
                return _visualList.Count;
            }
        }

        protected override Visual GetVisualChild(int index)
        {
            return _visualList[index];
        }
        #endregion

        public TempCanvas()
        {
            _visualList = new VisualCollection(this);
            _D2D = new TempCanvasD2D();

            _dvMain = new DrawingVisual();
            _visualList.Add(_dvMain);
        }

        bool _isInited;

        /// <summary>
        /// begin update, init data info
        /// </summary>
        /// <param name="dataType"></param>
        /// <param name="dataWidth"></param>
        /// <param name="dataHeight"></param>
        public void BeginUpdate(int dataType, int dataWidth, int dataHeight)
        {
            _D2D.InitData(dataType, dataWidth, dataHeight);
            this.Width = _D2D.outputWidth;
            this.Height = _D2D.outputHeight;

            _isInited = true;
        }

        /// <summary>
        /// end update, clear view
        /// </summary>
        public void EndUpdate()
        {
            if (!_isInited) return;

            //clear
            DrawingContext dc = _dvMain.RenderOpen();
            dc.Close();
            _isInited = false;
        }

        /// <summary>
        /// update data for temp-stream
        /// </summary>
        /// <param name="dataFrame"></param>
        void UpdataData_Temp(ref yoseen.DataFrame dataFrame)
        {
            //assign data pointer
            _D2D.ptrDfh = dataFrame.Head;
            _D2D.ptrDfd = dataFrame.Temp;
            _D2D.ptrBfd = dataFrame.Bmp;
            _D2D.ptrH264 = dataFrame.H264;

            // update image
            _D2D.wbImage.WritePixels(_D2D.wbImageSrcRect, _D2D.ptrBfd, _D2D.wbImageBufferSize, _D2D.wbImageStride);

            //draw image, geometry, text
            DrawingContext dc = _dvMain.RenderOpen();

            dc.DrawImage(_D2D.wbImage, _D2D.rectImage);

            dc.Close();
        }

        /// <summary>
        /// update data for video-stream
        /// </summary>
        /// <param name="dataFrame"></param>
        void UpdataData_Video(ref yoseen.DataFrame dataFrame)
        {
            //assign data pointer
            _D2D.ptrBfd = dataFrame.Bmp;
            _D2D.ptrH264 = dataFrame.H264;

            // update image
            _D2D.wbImage.WritePixels(_D2D.wbImageSrcRect, _D2D.ptrBfd, _D2D.wbImageBufferSize, _D2D.wbImageStride);

            //draw image, geometry, text
            DrawingContext dc = _dvMain.RenderOpen();

            dc.DrawImage(_D2D.wbImage, _D2D.rectImage);

            dc.Close();
        }

        /// <summary>
        /// update data
        /// </summary>
        /// <param name="dataFrame"></param>
        public void UpdateData(ref yoseen.DataFrame dataFrame)
        {
            if (!_isInited) return;

            if (_D2D.dataType == (int)yoseen.xxxdatatype.temp)
            {
                UpdataData_Temp(ref dataFrame);
            }
            else
            {
                UpdataData_Video(ref dataFrame);
            }
        }
    }


    /// <summary>
    /// config+resources+pointer used by TempCanvas
    /// </summary>
    class TempCanvasD2D
    {
        //data info
        public int dataType;//
        public int dataWidth;
        public int dataHeight;

        //output info
        public int outputWidth;
        public int outputHeight;
        public double scale;


        //resources for draw
        public WriteableBitmap wbImage;
        public Int32Rect wbImageSrcRect;
        public int wbImageBufferSize;
        public int wbImageStride;

        public Rect rectImage;

        //data pointer
        public IntPtr ptrDfh;
        public IntPtr ptrDfd;
        public IntPtr ptrBfd;
        public IntPtr ptrH264;

        public TempCanvasD2D()
        {

        }

        void initDataTemp()
        {
            scale = 1;
            outputWidth = dataWidth;
            outputHeight = dataHeight;

            rectImage.X = 0; rectImage.Y = 0;
            rectImage.Width = outputWidth; rectImage.Height = outputHeight;
        }

        void initDataVideo()
        {
            scale = 1;
            outputWidth = dataWidth;
            outputHeight = dataHeight;

            rectImage.X = 0; rectImage.Y = 0;
            rectImage.Width = outputWidth; rectImage.Height = outputHeight;
        }

        /// <summary>
        /// init data info
        /// </summary>
        /// <param name="dataType"></param>
        /// <param name="dataWidth"></param>
        /// <param name="dataHeight"></param>
        public void InitData(int dataType, int dataWidth, int dataHeight)
        {
            bool b = this.dataType == dataType && this.dataWidth == dataWidth && this.dataHeight == dataHeight;
            if (b) return;

            this.dataType = dataType;
            this.dataWidth = dataWidth;
            this.dataHeight = dataHeight;
            wbImage = new WriteableBitmap(dataWidth, dataHeight, 96, 96, PixelFormats.Bgr32, null);
            wbImageSrcRect = new Int32Rect(0, 0, dataWidth, dataHeight);
            wbImageBufferSize = dataWidth * dataHeight * 4;
            wbImageStride = dataWidth * 4;

            //
            if (dataType == (int)yoseen.xxxdatatype.temp)
            {
                initDataTemp();
            }
            else
            {
                initDataVideo();
            }

            //
            ptrDfh = IntPtr.Zero;
            ptrDfd = IntPtr.Zero;
            ptrBfd = IntPtr.Zero;
            ptrH264 = IntPtr.Zero;
        }
    }
}
