#if NETFX || NETCORE

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace Apewer.Surface
{

    /// <summary>
    /// 
    /// </summary>
    public class BlockImageViewer : BaseControl
    {

        private PictureBox _picture = new PictureBox();
        private Point _start = new Point(0, 0);
        private Point _flow;
        private int _padding = 0;
        private bool _moving = false;
        private bool _inimage = false;

        /// <summary>
        /// 
        /// </summary>
        public BlockImageViewer()
        {
            this.Controls.Add(_picture);

            this.Dock = DockStyle.Fill;
            this.BackColor = FormsUtility.GraceWall;

            _picture.Location = new Point(0, 0);
            _picture.Size = Size;
            _picture.BackColor = FormsUtility.GraceWall;

            Stretch = true;
            _flow = new Point(this.Width - _picture.Left, this.Height - _picture.Top);

            Adjust();

            this.BackColorChanged += Event_This_BackColorChanged;
            this.Resize += Event_Main_Resize;
            this.MouseEnter += Event_This_MouseEnter;
            MouseDown += Event_Picture_Down;
            MouseMove += Event_Picture_Move;
            MouseUp += Event_Picture_Up;
            MouseWheel += Event_Main_Wheel;
            _picture.MouseDown += Event_Picture_Down;
            _picture.MouseMove += Event_Picture_Move;
            _picture.MouseUp += Event_Picture_Up;
            _picture.MouseWheel += Event_Picture_Wheel;
            _picture.MouseHover += Event_Picture_Hover;
            _picture.MouseLeave += Event_Picture_Leave;
        }

        private void Event_This_MouseEnter(object sender, EventArgs e)
        {
            if (this.IsHandleCreated) this.Focus();
        }

        private void Event_This_BackColorChanged(object sender, EventArgs e)
        {
            _picture.BackColor = this.BackColor;
        }

        private void Event_Picture_Hover(object sender, EventArgs e)
        {
            _inimage = true;
        }

        private void Event_Picture_Leave(object sender, EventArgs e)
        {
            _inimage = false;
        }

        private void Event_Main_Wheel(object sender, MouseEventArgs e)
        {
            if (!_inimage)
            {
                int vp = BodyPadding;
                int vw, vh, vl, vt;
                vl = _picture.Width / 2 + _picture.Left;
                vt = _picture.Height / 2 + _picture.Top;
                if (e.Delta > 0)
                {
                    vw = (int)(_picture.Width * 1.2);
                    vh = (int)(_picture.Height * 1.2);
                    if (vw > (this.Width * 10))
                    {
                        vw = this.Width * 10;
                        vh = this.Height * 10;
                    }
                }
                else
                {
                    vw = (int)(_picture.Width * 0.8);
                    vh = (int)(_picture.Height * 0.8);
                    if (vw < (this.Width * 0.5))
                    {
                        vw = (int)(this.Width * 0.5);
                        vh = (int)(this.Height * 0.5);
                    }
                }
                _picture.Size = new Size(vw, vh);
                _picture.Left = (int)(vl - _picture.Width / 2);
                _picture.Top = (int)(vt - _picture.Height / 2);
            }
        }

        private void Event_Picture_Wheel(object sender, MouseEventArgs e)
        {
            int vp = BodyPadding;
            int vw, vh, vl, vt;
            double vx, vy;
            vx = (double)e.X / (double)_picture.Width;
            vy = (double)e.Y / (double)_picture.Height;
            vl = e.X + _picture.Left;
            vt = e.Y + _picture.Top;
            if (e.Delta > 0)
            {
                vw = (int)(_picture.Width * 1.2);
                vh = (int)(_picture.Height * 1.2);
                if (vw > (this.Width * 10))
                {
                    vw = this.Width * 10;
                    vh = this.Height * 10;
                }
            }
            else
            {
                vw = (int)(_picture.Width * 0.8);
                vh = (int)(_picture.Height * 0.8);
                if (vw < (this.Width * 0.5))
                {
                    vw = (int)(this.Width * 0.5);
                    vh = (int)(this.Height * 0.5);
                }
            }
            _picture.Size = new Size(vw, vh);
            _picture.Left = (int)(vl - _picture.Width * vx);
            _picture.Top = (int)(vt - _picture.Height * vy);
        }

        private void Event_Picture_Down(object sender, MouseEventArgs e)
        {
            switch (e.Button)
            {
                case MouseButtons.Left:
                    _start.X = Cursor.Position.X - _picture.Left;
                    _start.Y = Cursor.Position.Y - _picture.Top;
                    _moving = true; break;
                case MouseButtons.Right:
                    _moving = false;
                    Adjust();
                    break;
            }
        }

        private void Event_Picture_Move(object sender, MouseEventArgs e)
        {
            if (_moving)
            {
                _picture.Left = Cursor.Position.X - _start.X;
                _picture.Top = Cursor.Position.Y - _start.Y;
            }
        }

        private void Event_Picture_Up(object sender, MouseEventArgs e)
        {
            switch (e.Button)
            {
                case MouseButtons.Left:
                    _moving = false;
                    break;
            }
        }

        private void Event_Main_Resize(object sender, EventArgs e) { Adjust(); }

        /// <summary>
        /// 
        /// </summary>
        public void Adjust()
        {
            int vp = BodyPadding;
            _picture.Width = this.Width - vp * 2;
            _picture.Height = this.Height - vp * 2;
            _picture.Location = new Point(vp, vp);
        }

        /// <summary>
        /// 
        /// </summary>
        public int BodyPadding
        {
            get
            {
                int vw = this.Width / 2 - 2;
                int vh = this.Height / 2 - 2;
                int vm = (vw > vh) ? vh : vw;
                return (_padding > vm) ? vm : _padding;
            }
            set
            {
                if (value >= 0) _padding = value;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public Image GetImage()
        {
            return _picture.BackgroundImage;
        }

        /// <summary>
        /// 
        /// </summary>
        public void LoadImage(byte[] image)
        {
            Clear();

            if (image.Length < 1) return;
            if (!this.IsHandleCreated) return;
            if (!_picture.IsHandleCreated) return;

            Invoke(new Invoker(delegate ()
            {
                var memory = new MemoryStream(image);
                var bitmap = new Bitmap(memory);
                _picture.BackgroundImage = bitmap;
            }));
        }

        /// <summary>
        /// 
        /// </summary>
        public void LoadImage(Image image)
        {
            Clear();
            _picture.BackgroundImage = image;
        }

        /// <summary></summary>
        public void LoadImage(string path)
        {
            if (File.Exists(path))
            {
                try
                {
                    var vdata = File.ReadAllBytes(path);
                    LoadImage(vdata);
                }
                catch { Clear(); }
            }
            else { Clear(); }
        }

        /// <summary>
        /// 
        /// </summary>
        public void Clear()
        {
            if (_picture.BackgroundImage != null) _picture.BackgroundImage.Dispose();
            _picture.BackgroundImage = null;
        }

        /// <summary>
        /// 
        /// </summary>
        public void Clean()
        {
            Clear();
        }

        /// <summary>
        /// 
        /// </summary>
        public bool Stretch
        {
            get
            {
                return (_picture.BackgroundImageLayout == ImageLayout.Stretch) ? true : false;
            }
            set
            {
                if (value) _picture.BackgroundImageLayout = ImageLayout.Stretch;
                else _picture.BackgroundImageLayout = ImageLayout.Zoom;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public Size ImageSize
        {
            get
            {
                if (_picture.BackgroundImage != null) return _picture.BackgroundImage.Size;
                else return new Size(0, 0);
            }
        }

    }
}

#endif