using System;
using System.ComponentModel;

namespace OpenCVStudio_v0
{
    public sealed class PyrDownBlockProperties
    {
        private const int MinimumLevels = 1;
        private const int MaximumLevels = 8;

        private readonly ProjectManager projectManager;
        private readonly ProjectBlock projectBlock;

        private int levels;
        private RotateBorderMode borderMode;

        public PyrDownBlockProperties(ProjectManager projectManager, ProjectBlock projectBlock)
        {
            this.projectManager = projectManager ?? throw new ArgumentNullException(nameof(projectManager));
            this.projectBlock = projectBlock ?? throw new ArgumentNullException(nameof(projectBlock));

            levels = projectManager.GetBlockParameter(projectBlock.Id, "Levels", 1);
            borderMode = projectManager.GetBlockParameter(projectBlock.Id, "BorderMode", RotateBorderMode.Reflect101);
        }

        [Category("Пирамида изображения")]
        [DisplayName("Количество уровней")]
        [Description("Количество последовательных уменьшений изображения. Каждый уровень уменьшает ширину и высоту примерно в два раза. Допустимый диапазон: от 1 до 8.")]
        public int Levels
        {
            get => levels;

            set
            {
                ValidateLevels(value);

                if (levels == value)
                    return;

                levels = value;

                projectManager.SetBlockParameter(projectBlock.Id, "Levels", value);
            }
        }

        [Category("Границы изображения")]
        [DisplayName("Обработка границ")]
        [Description("Способ вычисления пикселей за пределами изображения. Для PyrDown режим Constant не поддерживается.")]
        public RotateBorderMode BorderMode
        {
            get => borderMode;

            set
            {
                ValidateBorderMode(value);

                if (borderMode == value)
                    return;

                borderMode = value;

                projectManager.SetBlockParameter(projectBlock.Id, "BorderMode", value);
            }
        }

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

        [Category("Блок")]
        [DisplayName("Тип")]
        [Description("Внутренний идентификатор типа блока.")]
        [ReadOnly(true)]
        public string BlockType => projectBlock.BlockType;

        [Category("Блок")]
        [DisplayName("Позиция")]
        [Description("Положение блока в конвейере обработки.")]
        [ReadOnly(true)]
        public int Position => projectBlock.Order + 1;

        private static void ValidateLevels(int value)
        {
            if (value < MinimumLevels || value > MaximumLevels)
                throw new ArgumentOutOfRangeException(nameof(value), value, $"Количество уровней должно находиться в диапазоне от {MinimumLevels} до {MaximumLevels}.");
        }

        private static void ValidateBorderMode(RotateBorderMode value)
        {
            if (!Enum.IsDefined(value))
                throw new ArgumentOutOfRangeException(nameof(value), value, "Неизвестный режим обработки границ.");

            if (value == RotateBorderMode.Constant)
                throw new ArgumentException("Режим Constant не поддерживается блоком PyrDown.", nameof(value));
        }
    }
}