using System;
using System.ComponentModel;

namespace OpenCVStudio_v0
{
    /// <summary>
    /// Параметры блока аппроксимации контуров.
    /// </summary>
    public sealed class ApproxPolyDPBlockProperties
    {
        private readonly ProjectManager projectManager;
        private readonly ProjectBlock projectBlock;
        private ApproxPolyDPEpsilonMode epsilonMode;
        private double epsilon;
        private bool closed;

        public ApproxPolyDPBlockProperties(ProjectManager projectManager, ProjectBlock projectBlock)
        {
            this.projectManager = projectManager ?? throw new ArgumentNullException(nameof(projectManager));
            this.projectBlock = projectBlock ?? throw new ArgumentNullException(nameof(projectBlock));
            epsilonMode = projectManager.GetBlockParameter(projectBlock.Id, "EpsilonMode", ApproxPolyDPEpsilonMode.PerimeterPercent);
            epsilon = projectManager.GetBlockParameter(projectBlock.Id, "Epsilon", 1.0);
            closed = projectManager.GetBlockParameter(projectBlock.Id, "Closed", true);
        }

        [Category("Аппроксимация")]
        [DisplayName("Режим точности")]
        [Description("Pixels — точность задаётся в пикселях. PerimeterPercent — точность задаётся в процентах от периметра каждого контура.")]
        public ApproxPolyDPEpsilonMode EpsilonMode
        {
            get => epsilonMode;
            set
            {
                if (epsilonMode == value) return;
                epsilonMode = value;
                projectManager.SetBlockParameter(projectBlock.Id, "EpsilonMode", value);
            }
        }

        [Category("Аппроксимация")]
        [DisplayName("Точность Epsilon")]
        [Description("Допустимое отклонение упрощённого контура. В режиме Pixels значение задаётся в пикселях. В режиме PerimeterPercent — в процентах от периметра контура. Чем больше значение, тем меньше точек останется.")]
        public double Epsilon
        {
            get => epsilon;
            set
            {
                double newValue = Math.Clamp(value, 0.001, 100_000.0);
                if (Math.Abs(epsilon - newValue) < double.Epsilon) return;
                epsilon = newValue;
                projectManager.SetBlockParameter(projectBlock.Id, "Epsilon", newValue);
            }
        }

        [Category("Аппроксимация")]
        [DisplayName("Замкнутый контур")]
        [Description("Указывает, является ли аппроксимируемый контур замкнутым. Для результатов FindContours обычно следует оставить значение True.")]
        public bool Closed
        {
            get => closed;
            set
            {
                if (closed == value) return;
                closed = value;
                projectManager.SetBlockParameter(projectBlock.Id, "Closed", value);
            }
        }

        [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;
    }
}