using Cosmos.Common;
using Cosmos.ServiceProvider;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace SPC.Kiosk.Common
{
    /// <summary>
    /// SignPad.xaml에 대한 상호 작용 논리
    /// </summary>
    public partial class SignPad : UserControl
    {
        
        #region [ Member ]
        /// <summary>
        /// Brush Color
        /// </summary>
        public static readonly DependencyProperty BrushColorProperty =
                 DependencyProperty.Register(nameof(BrushColor), typeof(System.Windows.Media.Color), typeof(SignPad), new PropertyMetadata(Colors.Black, new PropertyChangedCallback(OnBrushColorPropertyChanged)));
        /// <summary>
        /// Brush Size
        /// </summary>
        public static readonly DependencyProperty BrushSizeProperty =
                 DependencyProperty.Register(nameof(BrushSize), typeof(double), typeof(SignPad), new PropertyMetadata(5d, new PropertyChangedCallback(OnBrushSizePropertyChanged)));
        /// <summary>
        /// Background Color
        /// </summary>
        public static readonly DependencyProperty BackgroundColorProperty =
                 DependencyProperty.Register(nameof(BackgroundColor), typeof(System.Windows.Media.Color), typeof(SignPad), new PropertyMetadata(Colors.White, new PropertyChangedCallback(OnBackgroundColorPropertyChanged)));
        /// <summary>
        /// Saved File
        /// </summary>
        public static readonly DependencyProperty SavedFileProperty =
                 DependencyProperty.Register(nameof(SavedFile), typeof(string), typeof(SignPad), new PropertyMetadata(string.Empty));
        /// <summary>
        /// SignData
        /// </summary>
        public static readonly DependencyProperty SignDataProperty =
                 DependencyProperty.Register(nameof(SignData), typeof(string), typeof(SignPad), new PropertyMetadata(string.Empty));
        /// <summary>
        /// SignPoints
        /// </summary>
        public static readonly DependencyProperty SignPointsProperty =
                 DependencyProperty.Register(nameof(SignPoints), typeof(long), typeof(SignPad), new PropertyMetadata(0L, new PropertyChangedCallback(OnSignPointsPropertyChanged)));
        /// <summary>
        /// Useable Sign
        /// </summary>
        public static readonly DependencyProperty UseableSignProperty =
                 DependencyProperty.Register(nameof(UseableSign), typeof(bool), typeof(SignPad), new PropertyMetadata(false));
        /// <summary>
        /// TimeOutSeconds
        /// </summary>
        public static readonly DependencyProperty TimeOutSecondsProperty =
                 DependencyProperty.Register(nameof(TimeOutSeconds), typeof(double), typeof(SignPad), new PropertyMetadata(0d, new PropertyChangedCallback(OnTimeOutSecondsPropertyChanged)));
        /// <summary>
        /// SignReset
        /// </summary>
        public static readonly DependencyProperty SignResetProperty =
                 DependencyProperty.Register(nameof(SignReset), typeof(bool), typeof(SignPad), new PropertyMetadata(false, new PropertyChangedCallback(OnSignResetPropertyChanged)));
        /// <summary>
        /// SignEnd
        /// </summary>
        public static readonly DependencyProperty SignEndProperty =
                 DependencyProperty.Register(nameof(SignEnd), typeof(bool), typeof(SignPad), new PropertyMetadata(false, new PropertyChangedCallback(OnSignEndPropertyChanged)));
        /// <summary>
        /// Brush Color
        /// </summary>
        public System.Windows.Media.Color BrushColor
        {
            get { return (System.Windows.Media.Color)GetValue(BrushColorProperty); }
            set { SetValue(BrushColorProperty, value); }
        }
        /// <summary>
        /// Brush Size
        /// </summary>
        public double BrushSize
        {
            get { return (double)GetValue(BrushSizeProperty); }
            set { SetValue(BrushSizeProperty, value); }
        }

        /// <summary>
        /// Background Color
        /// </summary>
        public System.Windows.Media.Color BackgroundColor
        {
            get { return (System.Windows.Media.Color)GetValue(BackgroundColorProperty); }
            set { SetValue(BackgroundColorProperty, value); }
        }

        /// <summary>
        /// Saved File
        /// </summary>
        public string SavedFile
        {
            get { return (string)GetValue(SavedFileProperty); }
            set { SetValue(SavedFileProperty, value); }
        }
        /// <summary>
        /// Sign Data
        /// </summary>
        public string SignData
        {
            get { return (string)GetValue(SignDataProperty); }
            set { SetValue(SignDataProperty, value); }
        }
        /// <summary>
        /// SignPoints
        /// </summary>
        public long SignPoints
        {
            get { return (long)GetValue(SignPointsProperty); }
            set { SetValue(SignPointsProperty, value); }
        }
        /// <summary>
        /// Useable Sign
        /// </summary>
        public bool UseableSign
        {
            get { return (bool)GetValue(UseableSignProperty); }
            set { SetValue(UseableSignProperty, value); }
        }
        /// <summary>
        /// TimeOutSeconds
        /// </summary>
        public double TimeOutSeconds
        {
            get { return (double)GetValue(TimeOutSecondsProperty); }
            set { SetValue(TimeOutSecondsProperty, value); }
        }
        /// <summary>
        /// SignReset
        /// </summary>
        public bool SignReset
        {
            get { return (bool)GetValue(SignResetProperty); }
            set { SetValue(SignResetProperty, value); }
        }
        /// <summary>
        /// SignEnd
        /// </summary>
        public bool SignEnd
        {
            get { return (bool)GetValue(SignEndProperty); }
            set { SetValue(SignEndProperty, value); }
        }
        private DateTime LastAccessTime { get; set; } = DateTime.Now;
        private DispatcherTimer SignTimer;
        #endregion
        #region [ Ctor / Etc]
        public SignPad()
        {
            try
            {
                InitializeComponent();
                StrokeCollectionChangedEventHandler strokes_StrokesChanged = Strokes_StrokesChanged;
                inkCanvas.Strokes.StrokesChanged += strokes_StrokesChanged;
                inkCanvas.DefaultDrawingAttributes.Color = BrushColor;
                inkCanvas.DefaultDrawingAttributes.Height = BrushSize;
                inkCanvas.DefaultDrawingAttributes.Width = BrushSize;
                inkCanvas.DefaultDrawingAttributes.IgnorePressure = false;
                inkCanvas.DefaultDrawingAttributes.IsHighlighter = false;
                inkCanvas.DefaultDrawingAttributes.StylusTip = StylusTip.Ellipse;
                inkCanvas.Background = new SolidColorBrush(BackgroundColor);
            }
            catch (Exception ex)
            {
                CommonLog.ErrorLogWrite(this, "Ctor", "Fail !!", string.Format("{0}\n{1}", ex.Message, ex.StackTrace));
            }
        }

        private void SignPad_Unloaded(object sender, RoutedEventArgs e)
        {
            if (this.SignTimer != null)
            {
                SignTimer.Stop();
                SignTimer.Tick -= SignTimer_Tick;
                SignTimer = null;
            }
        }
        #endregion

        #region [ Methods ]
        private void TimerEnable()
        {
            if (DesignerProperties.GetIsInDesignMode(this)) return;

            if (this.SignTimer != null)
            {
                LastAccessTime = DateTime.Now;
                this.SignTimer.Start();
            }
            else
            {
                this.SignTimer = new DispatcherTimer
                {
                    Interval = TimeSpan.FromSeconds(1),
                };
                SignTimer.Tick += SignTimer_Tick;
                LastAccessTime = DateTime.Now;
                SignTimer.Start();
            }
        }
        private void TimerDisable()
        {
            if (this.SignTimer != null)
            {
                this.SignTimer.Stop();
                LastAccessTime = DateTime.Now;
            }
        }

        private void ConvertToBitmapSource()
        {
            try
            {
                var width = CommonValue.SignWidth;
                var height = CommonValue.SignHeight;
                var target = new RenderTargetBitmap((int)(inkCanvas.RenderSize.Width), (int)(inkCanvas.RenderSize.Height), 96, 96, PixelFormats.Default);
                var brush = new VisualBrush(inkCanvas);

                var visual = new DrawingVisual();
                var drawingContext = visual.RenderOpen();


                drawingContext.DrawRectangle(brush, null, new Rect(new System.Windows.Point(0, 0),
                                            new System.Windows.Point(inkCanvas.RenderSize.Width, inkCanvas.RenderSize.Height)));

                drawingContext.Close();
                target.Render(visual);

                var bitmapSource = (BitmapSource)target.Clone();
                var memoryStream = new MemoryStream();
                var bmpBitmapEncoder = new BmpBitmapEncoder();
                var bitmapFrame = BitmapFrame.Create(bitmapSource);
                bmpBitmapEncoder.Frames.Add(bitmapFrame);
                bmpBitmapEncoder.Save(memoryStream);
                using (var bitMap = new Bitmap(memoryStream))
                {

                    var targetSize = new System.Drawing.Size(width, height);
                    var sizedImage = new Bitmap(bitMap, targetSize);
                    var targetRectangle = new System.Drawing.Rectangle(0, 0, width, height);
                    var lastImg = sizedImage.Clone(targetRectangle, System.Drawing.Imaging.PixelFormat.Format1bppIndexed);

                    var filePath = ResourceManager.SignDataPath;
                    if (!Directory.Exists(filePath)) Directory.CreateDirectory(filePath);
                    var savedFile = System.IO.Path.Combine(filePath, CommonValue.SignFileName);
                    lastImg.Save(savedFile, System.Drawing.Imaging.ImageFormat.Bmp);
                    if (File.Exists(savedFile))
                    {
                        var sManager = new SManager();
                        var m_cSignPad = (ISignPadUs)sManager.InitServiceInstance(ServiceLists.AGENT_OLEDEVICE.DLL, ServiceLists.AGENT_OLEDEVICE.DEVICE_SIGNPAD);
                        var signData = string.Empty;
                        if (m_cSignPad.GetSign_BmpToData(savedFile, ref signData))
                        {
                            SignData = signData;
                            SavedFile = savedFile;
                        }
                        m_cSignPad = null;
                        sManager = null;
                    }
                }
            }
            catch (Exception ex)
            {
                CommonLog.ErrorLogWrite(this, "ConvertToBitmapSource()", "Fail !!", string.Format("{0}\n{1}", ex.Message, ex.StackTrace));
            }

        }
        private void CheckSignOK(long strokePoints)
        {
            if (strokePoints < CommonValue.SingPointsMin)
            {
                UseableSign = false;
            }
            else if (strokePoints >= CommonValue.SingPointsMin && strokePoints < CommonValue.SingPointsMax)
            {
                UseableSign = true;
            }
            else
            {
                UseableSign = false;
            }


        }
        #endregion

        #region  [ Event Handlers ]
        private void SignTimer_Tick(object sender, EventArgs e)
        {
            if ((DateTime.Now - LastAccessTime) > TimeSpan.FromSeconds(TimeOutSeconds))
            {
                TimerDisable();
                if (UseableSign)
                {
                    ConvertToBitmapSource();
                    inkCanvas.Strokes.Clear();
                }
                else
                {
                    TimerEnable();
                }
            }
        }
        private static void OnSignEndPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is SignPad target)
            {
                if (e.NewValue is bool newValue && newValue)
                {
                    target.TimerDisable();
                    target.ConvertToBitmapSource();
                    target.inkCanvas.Strokes.Clear();
                    target.SignEnd = false;
                }
            }
        }

        private static void OnSignResetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is SignPad target)
            {
                if (e.NewValue is bool newValue && newValue)
                {
                    target.LastAccessTime = DateTime.Now;
                    target.inkCanvas.Strokes.Clear();
                    target.SignReset = false;
                }
            }
        }

        private static void OnTimeOutSecondsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is SignPad target)
            {
                if (e.NewValue is double newTimeout && newTimeout > 0 )
                {
                    target.TimerEnable();

                }
            }
        }
    
        private static void OnBrushColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is SignPad target)
            {
                target.inkCanvas.DefaultDrawingAttributes.Color = (System.Windows.Media.Color)e.NewValue;
            }
        }
        private static void OnBackgroundColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is SignPad target)
            {
                target.inkCanvas.Background = new SolidColorBrush((System.Windows.Media.Color)e.NewValue);
            }
        }
        private static void OnBrushSizePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is SignPad target)
            {
                target.inkCanvas.DefaultDrawingAttributes.Height = (double)e.NewValue < 1 ? 1 : (double)e.NewValue;
                target.inkCanvas.DefaultDrawingAttributes.Width = (double)e.NewValue < 1 ? 1 : (double)e.NewValue;
            }
        }
        private static void OnSignPointsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is SignPad target)
            {
                if (e.NewValue is long strokePoints)
                {
                    target.CheckSignOK(strokePoints);
                }
            }
        }

        private void Strokes_StrokesChanged(object sender, StrokeCollectionChangedEventArgs e)
        {
            LastAccessTime = DateTime.Now;
            var signPoints = 0L;
            foreach (var aStroke in inkCanvas.Strokes)
            {
                signPoints += aStroke.StylusPoints.Count;
            }
            SignPoints = signPoints;
        } 
        #endregion

    }

}
