using System;
using System.ComponentModel;

namespace OpenCVStudio_v0
{
    /// <summary>
    /// Параметры фильтрации найденных контуров.
    /// </summary>
    public sealed class ContourFilterBlockProperties
    {
        private readonly ProjectManager projectManager;
        private readonly ProjectBlock projectBlock;
        private double minimumArea;
        private double maximumArea;
        private int minimumWidth;
        private int maximumWidth;
        private int minimumHeight;
        private int maximumHeight;
        private double minimumPerimeter;
        private double maximumPerimeter;

        public ContourFilterBlockProperties(ProjectManager projectManager, ProjectBlock projectBlock)
        {
            this.projectManager = projectManager ?? throw new ArgumentNullException(nameof(projectManager));
            this.projectBlock = projectBlock ?? throw new ArgumentNullException(nameof(projectBlock));
            minimumArea = projectManager.GetBlockParameter(projectBlock.Id, "MinimumArea", 100.0);
            maximumArea = projectManager.GetBlockParameter(projectBlock.Id, "MaximumArea", 1_000_000.0);
            minimumWidth = projectManager.GetBlockParameter(projectBlock.Id, "MinimumWidth", 5);
            maximumWidth = projectManager.GetBlockParameter(projectBlock.Id, "MaximumWidth", 100_000);
            minimumHeight = projectManager.GetBlockParameter(projectBlock.Id, "MinimumHeight", 5);
            maximumHeight = projectManager.GetBlockParameter(projectBlock.Id, "MaximumHeight", 100_000);
            minimumPerimeter = projectManager.GetBlockParameter(projectBlock.Id, "MinimumPerimeter", 0.0);
            maximumPerimeter = projectManager.GetBlockParameter(projectBlock.Id, "MaximumPerimeter", 1_000_000.0);
        }

        [Category("Площадь")]
        [DisplayName("Минимальная площадь")]
        [Description("Контуры с площадью меньше этого значения будут удалены.")]
        public double MinimumArea
        {
            get => minimumArea;
            set
            {
                double newValue = Math.Max(0.0, value);
                if (newValue > maximumArea) newValue = maximumArea;
                if (Math.Abs(minimumArea - newValue) < double.Epsilon) return;
                minimumArea = newValue;
                projectManager.SetBlockParameter(projectBlock.Id, "MinimumArea", newValue);
            }
        }

        [Category("Площадь")]
        [DisplayName("Максимальная площадь")]
        [Description("Контуры с площадью больше этого значения будут удалены.")]
        public double MaximumArea
        {
            get => maximumArea;
            set
            {
                double newValue = Math.Max(0.0, value);
                if (newValue < minimumArea) newValue = minimumArea;
                if (Math.Abs(maximumArea - newValue) < double.Epsilon) return;
                maximumArea = newValue;
                projectManager.SetBlockParameter(projectBlock.Id, "MaximumArea", newValue);
            }
        }

        [Category("Размер")]
        [DisplayName("Минимальная ширина")]
        [Description("Минимальная ширина ограничивающего прямоугольника контура.")]
        public int MinimumWidth
        {
            get => minimumWidth;
            set
            {
                int newValue = Math.Max(0, value);
                if (newValue > maximumWidth) newValue = maximumWidth;
                if (minimumWidth == newValue) return;
                minimumWidth = newValue;
                projectManager.SetBlockParameter(projectBlock.Id, "MinimumWidth", newValue);
            }
        }

        [Category("Размер")]
        [DisplayName("Максимальная ширина")]
        [Description("Максимальная ширина ограничивающего прямоугольника контура.")]
        public int MaximumWidth
        {
            get => maximumWidth;
            set
            {
                int newValue = Math.Max(0, value);
                if (newValue < minimumWidth) newValue = minimumWidth;
                if (maximumWidth == newValue) return;
                maximumWidth = newValue;
                projectManager.SetBlockParameter(projectBlock.Id, "MaximumWidth", newValue);
            }
        }

        [Category("Размер")]
        [DisplayName("Минимальная высота")]
        [Description("Минимальная высота ограничивающего прямоугольника контура.")]
        public int MinimumHeight
        {
            get => minimumHeight;
            set
            {
                int newValue = Math.Max(0, value);
                if (newValue > maximumHeight) newValue = maximumHeight;
                if (minimumHeight == newValue) return;
                minimumHeight = newValue;
                projectManager.SetBlockParameter(projectBlock.Id, "MinimumHeight", newValue);
            }
        }

        [Category("Размер")]
        [DisplayName("Максимальная высота")]
        [Description("Максимальная высота ограничивающего прямоугольника контура.")]
        public int MaximumHeight
        {
            get => maximumHeight;
            set
            {
                int newValue = Math.Max(0, value);
                if (newValue < minimumHeight) newValue = minimumHeight;
                if (maximumHeight == newValue) return;
                maximumHeight = newValue;
                projectManager.SetBlockParameter(projectBlock.Id, "MaximumHeight", newValue);
            }
        }

        [Category("Периметр")]
        [DisplayName("Минимальный периметр")]
        [Description("Контуры с меньшим периметром будут удалены.")]
        public double MinimumPerimeter
        {
            get => minimumPerimeter;
            set
            {
                double newValue = Math.Max(0.0, value);
                if (newValue > maximumPerimeter) newValue = maximumPerimeter;
                if (Math.Abs(minimumPerimeter - newValue) < double.Epsilon) return;
                minimumPerimeter = newValue;
                projectManager.SetBlockParameter(projectBlock.Id, "MinimumPerimeter", newValue);
            }
        }

        [Category("Периметр")]
        [DisplayName("Максимальный периметр")]
        [Description("Контуры с большим периметром будут удалены.")]
        public double MaximumPerimeter
        {
            get => maximumPerimeter;
            set
            {
                double newValue = Math.Max(0.0, value);
                if (newValue < minimumPerimeter) newValue = minimumPerimeter;
                if (Math.Abs(maximumPerimeter - newValue) < double.Epsilon) return;
                maximumPerimeter = newValue;
                projectManager.SetBlockParameter(projectBlock.Id, "MaximumPerimeter", newValue);
            }
        }

        [Category("Блок")]
        [DisplayName("Название")]
        [ReadOnly(true)]
        public string BlockName => projectBlock.Name;

        [Category("Блок")]
        [DisplayName("Тип")]
        [ReadOnly(true)]
        public string BlockType => projectBlock.BlockType;

        [Category("Блок")]
        [DisplayName("Позиция")]
        [ReadOnly(true)]
        public int Position => projectBlock.Order + 1;
    }
}