using System;
using System.Collections.Generic;
using System.Text;

using System.ComponentModel;
namespace OpenCVStudio_v0
{
    public sealed class CannyBlockProperties
    {
        private readonly ProjectManager projectManager; private readonly ProjectBlock projectBlock;
        private double threshold1; private double threshold2; private int apertureSize; private bool l2Gradient;
        public CannyBlockProperties(ProjectManager projectManager, ProjectBlock projectBlock)
        {
            this.projectManager = projectManager ?? throw new ArgumentNullException(nameof(projectManager));
            this.projectBlock = projectBlock ?? throw new ArgumentNullException(nameof(projectBlock));
            threshold1 = projectManager.GetBlockParameter(projectBlock.Id, "Threshold1", 50.0);
            threshold2 = projectManager.GetBlockParameter(projectBlock.Id, "Threshold2", 150.0);
            apertureSize = projectManager.GetBlockParameter(projectBlock.Id, "ApertureSize", 3);
            l2Gradient = projectManager.GetBlockParameter(projectBlock.Id, "L2Gradient", false);
        }
        [Category("Пороги")]
        [DisplayName("Нижний порог")]
        [Description("Слабые границы ниже этого значения отбрасываются.")]
        public double Threshold1
        {
            get => threshold1;
            set
            {
                ValidateThreshold(value, "Нижний порог");
                if (Math.Abs(threshold1 - value) < double.Epsilon) return;
                threshold1 = value;
                projectManager.SetBlockParameter(projectBlock.Id, "Threshold1", value);
                if (threshold2 <= threshold1)
                {
                    threshold2 = threshold1 + 1;
                    projectManager.SetBlockParameter(projectBlock.Id, "Threshold2", threshold2);
                }
            }
        }
        [Category("Пороги")]
        [DisplayName("Верхний порог")]
        [Description("Границы выше этого значения считаются надёжными.")]
        public double Threshold2
        {
            get => threshold2;
            set
            {
                ValidateThreshold(value, "Верхний порог");
                if (value <= threshold1) throw new ArgumentException("Верхний порог должен быть больше нижнего.");
                if (Math.Abs(threshold2 - value) < double.Epsilon) return;
                threshold2 = value;
                projectManager.SetBlockParameter(projectBlock.Id, "Threshold2", value);
            }
        }
        [Category("Алгоритм")]
        [DisplayName("Размер Sobel")]
        [Description("Допустимы значения 3, 5 или 7.")]
        public int ApertureSize
        {
            get => apertureSize;
            set
            {
                ValidateApertureSize(value);
                if (apertureSize == value) return;
                apertureSize = value;
                projectManager.SetBlockParameter(projectBlock.Id, "ApertureSize", value);
            }
        }
        [Category("Алгоритм")]
        [DisplayName("Точный градиент L2")]
        [Description("Использует более точный расчёт величины градиента.")]
        public bool L2Gradient
        {
            get => l2Gradient;
            set
            {
                if (l2Gradient == value) return;
                l2Gradient = value;
                projectManager.SetBlockParameter(projectBlock.Id, "L2Gradient", 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;
        private static void ValidateThreshold(double value, string parameterName)
        {
            if (double.IsNaN(value) || double.IsInfinity(value) || value < 0 || value > 10000)
                throw new ArgumentOutOfRangeException(nameof(value), value, $"{parameterName} должен находиться от 0 до 10000.");
        }
        private static void ValidateApertureSize(int value)
        {
            if (value != 3 && value != 5 && value != 7)
                throw new ArgumentOutOfRangeException(nameof(value), value, "Размер Sobel может быть только 3, 5 или 7.");
        }
    }
}