/*
  Сервис интеграции ПП Парус 8 с WEB API
  Модели данных: описатель объекта конфигурации приложения
*/

//----------------------
// Подключение библиотек
//----------------------

const Schema = require("validate"); //Схемы валидации

//----------
// Константы
//----------

//Уровни протоколирования подключения Kafka
const SKAFKA_LOG_LEVEL_NOTHING = "NOTHING"; //Протоколирование отключено
const SKAFKA_LOG_LEVEL_ERROR = "ERROR"; //Протоколирование ошибок
const SKAFKA_LOG_LEVEL_WARN = "WARN"; //Протоколирование предупреждений
const SKAFKA_LOG_LEVEL_INFO = "INFO"; //Протоколирование общей информации

//Уровни протоколирования подключения MQTT
const SMQTT_LOG_LEVEL_NOTHING = "NOTHING"; //Протоколирование отключено
const SMQTT_LOG_LEVEL_ERROR = "ERROR"; //Протоколирование ошибок
const SMQTT_LOG_LEVEL_INFO = "INFO"; //Протоколирование информации

//-------------
//  Тело модуля
//-------------

//Функция проверки длины значения наименование сервера приложений
const validateServerName = val => val.length <= 40;

//Функция проверки значения таймаута останова сервера
const validateTerminateTimeout = val => val >= 1000 && val <= 120000 && Number.isInteger(val);

//Функция проверки значения размера блока одновременно обрабатываемых исходящих сообщений
const validateMaxWorkers = val => val >= 1 && val <= 100 && Number.isInteger(val);

//Функция проверки значения интервала проверки наличия исходящих сообщений
const validateCheckTimeout = val => val >= 1 && val <= 60000 && Number.isInteger(val);

//Функция проверки значения порта сервера обслуживания входящих сообщений
const validateInComingPort = val => val >= 0 && val <= 65535 && Number.isInteger(val);

//Функция проверки значения порта сервера обслуживания входящих сообщений
const validateMsgMaxSize = val => val >= 1 && val <= 1000 && Number.isInteger(val);

//Функция проверки значения минимального размера пула подключений к БД для обработчика исходящих сообщений
const validatePoolMinOutGoing = val => val >= 0 && val <= 10;

//Функция проверки значения максимального размера пула подключений к БД для обработчика исходящих сообщений
const validatePoolMaxOutGoing = val => val >= 1 && val <= 10;

//Функция проверки значения шага инкремента подключений к БД в пуле обработчика исходящих сообщений
const validatePoolIncrementOutGoing = val => val >= 0 && val <= 10;

//Функция проверки значения минимального размера пула подключений к БД для обработчика входящих сообщений
const validatePoolMinInComing = val => val >= 0 && val <= 1000;

//Функция проверки значения максимального размера пула подключений к БД для обработчика входящих сообщений
const validatePoolMaxInComing = val => val >= 1 && val <= 1000;

//Функция проверки значения шага инкремента подключений к БД в пуле обработчика входящих сообщений
const validatePoolIncrementInComing = val => val >= 0 && val <= 1000;

//Функция проверки значения времени ожидания отработки входящего сообщения для обработчика входящих сообщений
const validateTimeoutInComing = val => val >= 0;

//Функция проверки значения таймаута параллельного процесса обработчика исходящих сообщений
const validateTimeoutWorkerOutGoing = val => val >= 0 && Number.isInteger(val);

//Функция проверки значения времени ожидания успешного подключения Kafka
const validateTimeoutKafka = val => val >= 0;

//Функция проверки значения максимального ожидания между попытками переподключения Kafka
const validateMaxRetryTimeKafka = val => val >= 0;

//Функция проверки значения максимального ожидания между попытками переподключения Kafka
const validateInitialRetryTimeKafka = val => val >= 0;

//Функция проверки значения времени ожидания успешного подключения к MQTT
const validateConnectTimeoutMQTT = val => val >= 0;

//Функция проверки значения времени ожидания между попытками переподключения к MQTT
const validateReconnectPeriodMQTT = val => val >= 0;

//Схема валидации общих параметров сервера приложений
const common = new Schema({
    //Наименование сервера приложений
    sServerName: {
        type: String,
        required: false,
        use: { validateServerName },
        message: {
            type: path => `Наименование сервера приложений (${path}) имеет некорректный тип данных (ожидалось - String)`,
            validateServerName: path => `Длина наименования сервера приложений (${path}) не может превышать 40 символов`
        }
    },
    //Версия сервера приложений
    sVersion: {
        type: String,
        required: true,
        message: {
            type: path => `Версия сервера приложений (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указана версия сервера приложений (${path})`
        }
    },
    //Релиз сервера приложений
    sRelease: {
        type: String,
        required: true,
        message: {
            type: path => `Релиз сервера приложений (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указан релиз сервера приложений (${path})`
        }
    },
    //Таймаут останова сервера (мс)
    nTerminateTimeout: {
        type: Number,
        required: true,
        use: { validateTerminateTimeout },
        message: {
            type: path => `Таймаут останова сервера (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указан таймаут останова сервера (${path})`,
            validateTerminateTimeout: path => `Таймаут останова сервера (${path}) должен быть целым числом в диапазоне от 1000 до 120000`
        }
    },
    //Контроль версии Системы
    bControlSystemVersion: {
        type: Boolean,
        required: true,
        message: {
            type: path => `Признак контроля версии Системы (${path}) имеет некорректный тип данных (ожидалось - Boolean)`,
            required: path => `Не указан признак контроля версии Системы (${path})`
        }
    }
});

//Схема валидации параметров подключения к БД
const dbConnect = new Schema({
    //Пользователь БД
    sUser: {
        type: String,
        required: true,
        message: {
            type: path => `Имя пользователя БД (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указано имя пользователя БД (${path})`
        }
    },
    //Пароль пользователя БД
    sPassword: {
        type: String,
        required: true,
        message: {
            type: path => `Пароль пользователя БД (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указан пароль пользователя БД (${path})`
        }
    },
    //Схема размещения используемых объектов БД
    sSchema: {
        type: String,
        required: true,
        message: {
            type: path => `Схема размещения используемых объектов БД (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указана схема размещения используемых объектов БД (${path})`
        }
    },
    //Строка подключения к БД
    sConnectString: {
        type: String,
        required: true,
        message: {
            type: path => `Строка подключения к БД (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указана строка подключения к БД (${path})`
        }
    },
    //Наименование сервера приложений в сессии БД
    sSessionAppName: {
        type: String,
        required: true,
        message: {
            type: path => `Наименование сервера приложений в сессии БД (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указано наименование сервера приложений в сессии БД (${path})`
        }
    },
    //Наименование подключаемого модуля обслуживания БД
    sConnectorModule: {
        type: String,
        required: true,
        message: {
            type: path => `Наименование подключаемого модуля обслуживания БД (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указано наименование подключаемого модуля обслуживания БД (${path})`
        }
    },
    //Признак применения "тонкого" (Thin) или "толстого" (Thick) режима подключения к БД
    bOraUseThinMode: {
        type: Boolean,
        required: true,
        message: {
            type: path => `Признак режима подключения (Thin/Thick) к БД (${path}) имеет некорректный тип данных (ожидалось - Boolean)`,
            required: path => `Не указан признак режима подключения (Thin/Thick) к БД (${path})`
        }
    },
    //Путь к домашней директории Oracle Client
    sOraClient: {
        type: String,
        required: false,
        message: {
            type: path => `Путь к домашней директории Oracle Client (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указан путь к домашней директории Oracle Client (${path})`
        }
    }
});

//Схема валидации параметров обработки очереди исходящих сообщений
const outGoing = new Schema({
    //Проверять SSL-сертификаты адресов отправки сообщений (самоподписанные сертификаты будут отвергнуты)
    bValidateSSL: {
        type: Boolean,
        required: true,
        message: {
            type: path =>
                `Признак проверки SSL-сертификатов адресов отправки сообщений (${path}) имеет некорректный тип данных (ожидалось - Boolean)`,
            required: path => `Не указан признак проверки SSL-сертификатов адресов отправки сообщений (${path})`
        }
    },
    //Количество одновременно обрабатываемых исходящих сообщений
    nMaxWorkers: {
        type: Number,
        required: true,
        use: { validateMaxWorkers },
        message: {
            type: path => `Количество одновременно обрабатываемых исходящих сообщений (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указано количество одновременно обрабатываемых исходящих сообщений (${path})`,
            validateMaxWorkers: path =>
                `Количество одновременно обрабатываемых исходящих сообщений (${path}) должно быть целым числом в диапазоне от 1 до 100`
        }
    },
    //Интервал проверки наличия исходящих сообщений (мс)
    nCheckTimeout: {
        type: Number,
        required: true,
        use: { validateCheckTimeout },
        message: {
            type: path => `Интервал проверки наличия исходящих сообщений (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указан интервал проверки наличия исходящих сообщений (${path})`,
            validateCheckTimeout: path =>
                `Значение интервала проверки наличия исходящих сообщений (${path}) должно быть целым числом в диапазоне от 100 до 60000`
        }
    },
    //Минимальный размер пула подключений к БД для обработчика исходящих сообщений
    nPoolMin: {
        type: Number,
        required: true,
        use: { validatePoolMinOutGoing },
        message: {
            type: path =>
                `Минимальный размер пула подключений к БД для обработчика исходящих сообщений (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указан минимальный размер пула подключений к БД для обработчика исходящих сообщений (${path})`,
            validatePoolMinOutGoing: path =>
                `Значение минимального размера пула подключений к БД для обработчика исходящих сообщений (${path}) должно быть целым числом в диапазоне от 0 до 10`
        }
    },
    //Максимальный размер пула подключений к БД для обработчика исходящих сообщений
    nPoolMax: {
        type: Number,
        required: true,
        use: { validatePoolMaxOutGoing },
        message: {
            type: path =>
                `Максимальный размер пула подключений к БД для обработчика исходящих сообщений (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указан максимальный размер пула подключений к БД для обработчика исходящих сообщений (${path})`,
            validatePoolMaxOutGoing: path =>
                `Значение максимального размера пула подключений к БД для обработчика исходящих сообщений (${path}) должно быть целым числом в диапазоне от 1 до 10`
        }
    },
    //Шаг инкремента подключений к БД в пуле обработчика исходящих сообщений
    nPoolIncrement: {
        type: Number,
        required: true,
        use: { validatePoolIncrementOutGoing },
        message: {
            type: path =>
                `Шаг инкремента подключений к БД в пуле обработчика исходящих сообщений (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указан шаг инкремента подключений к БД в пуле обработчика исходящих сообщений (${path})`,
            validatePoolIncrementOutGoing: path =>
                `Значение шага инкремента подключений к БД в пуле обработчика исходящих сообщений (${path}) должно быть целым числом в диапазоне от 0 до 10`
        }
    },
    //Глобальный адрес прокси-сервера
    sProxy: {
        type: String,
        required: false,
        message: {
            type: path => `Адрес прокси-сервера приложения (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указан глобальный адрес прокси-сервера (${path})`
        }
    },
    //Таймаут параллельного процесса обработки исходящего сообщения (мс)
    nWorkerTimeout: {
        type: Number,
        required: false,
        use: { validateTimeoutWorkerOutGoing },
        message: {
            type: path =>
                `Таймаут параллельного процесса обработки исходящего сообщения (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            validateTimeoutWorkerOutGoing: path =>
                `Таймаут параллельного процесса обработки исходящего сообщения (${path}) должен быть неотрицательным целым числом`
        }
    }
});

//Схема валидации параметров обработки очереди входящих сообщений
const inComing = new Schema({
    //Порт сервера входящих сообщений
    nPort: {
        type: Number,
        required: true,
        use: { validateInComingPort },
        message: {
            type: path => `Порт сервера входящих сообщений (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указан порт сервера входящих сообщений (${path})`,
            validateInComingPort: path => `Порт сервера входящих сообщений (${path}) должен быть целым числом в диапазоне от  0 до 65535`
        }
    },
    sHost: {
        type: String,
        required: true,
        message: {
            type: path => `IP-адрес сервера приложений (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указан IP-адрес сервера приложений (${path})`
        }
    },
    //Максимальный размер входящего сообщения (мб)
    nMsgMaxSize: {
        type: Number,
        required: true,
        use: { validateMsgMaxSize },
        message: {
            type: path => `Максимальный размер входящего сообщения (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указан максимальный размер входящего сообщения (${path})`,
            validateMsgMaxSize: path => `Максимальный размер входящего сообщения (${path}) должен быть целым числом в диапазоне от  1 до 1000`
        }
    },
    //Каталог размещения статических ресурсов
    sStaticDir: {
        type: String,
        required: true,
        message: {
            type: path => `Каталог размещения статических ресурсов (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указан каталог размещения статических ресурсов (${path})`
        }
    },
    //Минимальный размер пула подключений к БД для обработчика входящих сообщений
    nPoolMin: {
        type: Number,
        required: true,
        use: { validatePoolMinInComing },
        message: {
            type: path =>
                `Минимальный размер пула подключений к БД для обработчика входящих сообщений (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указан минимальный размер пула подключений к БД для обработчика входящих сообщений (${path})`,
            validatePoolMinInComing: path =>
                `Значение минимального размера пула подключений к БД для обработчика входящих сообщений (${path}) должно быть целым числом в диапазоне от 0 до 1000`
        }
    },
    //Максимальный размер пула подключений к БД для обработчика входящих сообщений
    nPoolMax: {
        type: Number,
        required: true,
        use: { validatePoolMaxInComing },
        message: {
            type: path =>
                `Максимальный размер пула подключений к БД для обработчика входящих сообщений (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указан максимальный размер пула подключений к БД для обработчика входящих сообщений (${path})`,
            validatePoolMaxInComing: path =>
                `Значение максимального размера пула подключений к БД для обработчика входящих сообщений (${path}) должно быть целым числом в диапазоне от 1 до 1000`
        }
    },
    //Шаг инкремента подключений к БД в пуле обработчика входящих сообщений
    nPoolIncrement: {
        type: Number,
        required: true,
        use: { validatePoolIncrementInComing },
        message: {
            type: path =>
                `Шаг инкремента подключений к БД в пуле обработчика входящих сообщений (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указан шаг инкремента подключений к БД в пуле обработчика входящих сообщений (${path})`,
            validatePoolIncrementInComing: path =>
                `Значение шага инкремента подключений к БД в пуле обработчика входящих сообщений (${path}) должно быть целым числом в диапазоне от 0 до 1000`
        }
    },
    //Время ожидания отработки входящего сообщения (мс)
    nTimeout: {
        type: Number,
        required: true,
        use: { validateTimeoutInComing },
        message: {
            type: path => `Время ожидания отработки входящего сообщения (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указано время ожидания отработки входящего сообщения (${path})`,
            validateTimeoutInComing: path => `Время ожидания отработки входящего сообщения (${path}) должно быть неотрицательным целым числом`
        }
    }
});

//Схема валидации параметров SSL подключения к Kafka
const kafkaSSL = new Schema({
    //Запрещать использование самоподписанных сертификатов (true - запретить, false - разрешить)
    bRejectUnauthorized: {
        type: Boolean,
        required: true,
        message: {
            type: path =>
                `Признак запрета использования самоподписанных сертификатов SSL подключения к Kafka (${path}) имеет некорректный тип данных (ожидалось - Boolean)`,
            required: path => `Не указан признак запрета использования самоподписанных сертификатов SSL подключения к Kafka (${path})`
        }
    },
    //Путь к корневому сертификату с информацией об удостоверяющем центре
    sPathCa: {
        type: String,
        required: false,
        message: {
            type: path => `Путь к корневому сертификату SSL подключения к Kafka (${path}) имеет некорректный тип данных (ожидалось - String)`
        }
    },
    //Путь к закрытому ключу
    sPathKey: {
        type: String,
        required: false,
        message: {
            type: path => `Путь к закрытому ключу SSL подключения к Kafka (${path}) имеет некорректный тип данных (ожидалось - String)`
        }
    },
    //Путь к сертификату
    sPathCert: {
        type: String,
        required: false,
        message: {
            type: path => `Путь к сертификату SSL подключения к Kafka (${path}) имеет некорректный тип данных (ожидалось - String)`
        }
    }
});

//Схема валидации параметров подключения Kafka
const kafka = new Schema({
    //Мнемокод сервиса обмена
    sService: {
        type: String,
        required: false,
        message: {
            type: path => `Мнемокод сервиса обмена подключения Kafka (${path}) имеет некорректный тип данных (ожидалось - String)`
        }
    },
    //ID клиента-отправителя
    sClientIdSender: {
        type: String,
        required: true,
        message: {
            type: path => `ID клиента-отправителя подключения Kafka (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указан ID клиента-отправителя подключения Kafka (${path})`
        }
    },
    //ID клиента-получателя
    sClientIdRecipient: {
        type: String,
        required: true,
        message: {
            type: path => `ID клиента-получателя подключения Kafka (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указан ID клиента-получателя подключения Kafka (${path})`
        }
    },
    //Группа получателя
    sGroupId: {
        type: String,
        required: true,
        message: {
            type: path => `Группа получателя подключения Kafka (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указана группа получателя подключения Kafka (${path})`
        }
    },
    //Время ожидания успешного подключения (мс)
    nConnectionTimeout: {
        type: Number,
        required: true,
        use: { validateTimeoutKafka },
        message: {
            type: path => `Время ожидания успешного подключения к Kafka (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указано время ожидания успешного подключения к Kafka (${path})`,
            validateTimeoutKafka: path => `Время ожидания успешного подключения Kafka (${path}) должно быть неотрицательным целым числом`
        }
    },
    //Необходимость попытки переподключения при потере соединения
    bRestartOnFailure: {
        type: Boolean,
        required: true,
        message: {
            type: path => `Признак необходимости попытки переподключения к Kafka (${path}) имеет некорректный тип данных (ожидалось - Boolean)`,
            required: path => `Не указан признак необходимости попытки переподключения к Kafka (${path})`
        }
    },
    //Время максимального ожидания между попытками переподключения (мс)
    nMaxRetryTime: {
        type: Number,
        required: true,
        use: { validateMaxRetryTimeKafka },
        message: {
            type: path =>
                `Время максимального ожидания между попытками переподключения к Kafka (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указано время максимального ожидания между попытками переподключения к Kafka (${path})`,
            validateMaxRetryTimeKafka: path =>
                `Время максимального ожидания между попытками переподключения к Kafka (${path}) должно быть неотрицательным целым числом`
        }
    },
    //Время ожидания между попытками переподключения (мс)
    nInitialRetryTime: {
        type: Number,
        required: true,
        use: { validateInitialRetryTimeKafka },
        message: {
            type: path => `Время ожидания между попытками переподключения к Kafka (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указано время ожидания между попытками переподключения к Kafka (${path})`,
            validateInitialRetryTimeKafka: path =>
                `Время ожидания между попытками переподключения к Kafka (${path}) должно быть неотрицательным целым числом`
        }
    },
    //Уровень протоколирования подключения
    sLogLevel: {
        type: String,
        enum: [SKAFKA_LOG_LEVEL_NOTHING, SKAFKA_LOG_LEVEL_ERROR, SKAFKA_LOG_LEVEL_WARN, SKAFKA_LOG_LEVEL_INFO],
        required: true,
        message: {
            type: path => `Уровень протоколирования подключения к Kafka (${path}) имеет некорректный тип данных (ожидалось - String)`,
            enum: path => `Значение уровня протоколирования подключения к Kafka (${path}) не поддерживается`,
            required: path => `Не указан уровень протоколирования подключения к Kafka (${path})`
        }
    },
    //Использовать аутентификацию по SSL-сертификату
    bAuthSSL: {
        type: Boolean,
        required: true,
        message: {
            type: path => `Признак использования аутентификации по SSL к Kafka (${path}) имеет некорректный тип данных (ожидалось - Boolean)`,
            required: path => `Не указан признак использования аутентификации по SSL к Kafka (${path})`
        }
    },
    //Параметры аутентификации по SSL-сертификату
    ssl: {
        schema: kafkaSSL,
        required: true,
        message: {
            required: path => `Не указаны параметры аутентификации по SSL к Kafka (${path})`
        }
    }
});

//Описатель схемы валидации подключения к Kafka
const defKafka = (bRequired, sName) => {
    return {
        type: Array,
        required: bRequired,
        each: kafka,
        message: {
            type: `Список подключений Kafka (${sName}) имеет некорректный тип данных (ожидалось - Array)`,
            required: `Не указан список подключений Kafka (${sName})`
        }
    };
};

//Схема валидации параметров подключения MQTT
const mqtt = new Schema({
    //Мнемокод сервиса обмена
    sService: {
        type: String,
        required: false,
        message: {
            type: path => `Мнемокод сервиса обмена подключения MQTT (${path}) имеет некорректный тип данных (ожидалось - String)`
        }
    },
    //ID клиента-отправителя
    sClientIdSender: {
        type: String,
        required: true,
        message: {
            type: path => `ID клиента-отправителя подключения MQTT (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указан ID клиента-отправителя подключения MQTT (${path})`
        }
    },
    //ID клиента-получателя
    sClientIdRecipient: {
        type: String,
        required: true,
        message: {
            type: path => `ID клиента-получателя подключения MQTT (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указан ID клиента-получателя подключения MQTT (${path})`
        }
    },
    //Время ожидания успешного подключения (мс)
    nConnectTimeout: {
        type: Number,
        required: true,
        use: { validateConnectTimeoutMQTT },
        message: {
            type: path => `Время ожидания успешного подключения к MQTT (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указано время ожидания успешного подключения к MQTT (${path})`,
            validateConnectTimeoutMQTT: path => `Время ожидания успешного подключения к MQTT (${path}) должно быть неотрицательным целым числом`
        }
    },
    //Время ожидания между попытками переподключения (мс)
    nReconnectPeriod: {
        type: Number,
        required: true,
        use: { validateReconnectPeriodMQTT },
        message: {
            type: path => `Время ожидания между попытками переподключения к MQTT (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указано время ожидания между попытками переподключения к MQTT (${path})`,
            validateReconnectPeriodMQTT: path =>
                `Время ожидания между попытками переподключения к MQTT (${path}) должно быть неотрицательным целым числом`
        }
    },
    //Уровень протоколирования подключения
    sLogLevel: {
        type: String,
        enum: [SMQTT_LOG_LEVEL_NOTHING, SMQTT_LOG_LEVEL_ERROR, SMQTT_LOG_LEVEL_INFO],
        required: true,
        message: {
            type: path => `Уровень протоколирования подключения к MQTT (${path}) имеет некорректный тип данных (ожидалось - String)`,
            enum: path => `Значение уровня протоколирования подключения к MQTT (${path}) не поддерживается`,
            required: path => `Не указан уровень протоколирования подключения к MQTT (${path})`
        }
    }
});

//Описатель схемы валидации подключения к MQTT
const defMQTT = (bRequired, sName) => {
    return {
        type: Array,
        required: bRequired,
        each: mqtt,
        message: {
            type: `Список подключений MQTT (${sName}) имеет некорректный тип данных (ожидалось - Array)`,
            required: `Не указан список подключений MQTT (${sName})`
        }
    };
};

//Схема валидации параметров отправки E-Mail уведомлений
const mail = new Schema({
    //Адреc сервера SMTP
    sHost: {
        type: String,
        required: false,
        message: {
            type: path => `Адреc сервера SMTP (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указан aдреc сервера SMTP (${path})`
        }
    },
    //Порт сервера SMTP
    nPort: {
        type: Number,
        required: false,
        message: {
            type: path => `Порт сервера SMTP (${path}) имеет некорректный тип данных (ожидалось - Number)`,
            required: path => `Не указан порт сервера SMTP (${path})`
        }
    },
    //Использовать безопасное соединение STMP
    bSecure: {
        type: Boolean,
        required: true,
        message: {
            type: path => `Признак использования безопасного соединения SMTP (${path}) имеет некорректный тип данных (ожидалось - Boolean)`,
            required: path => `Не указан признак использования безопасного соединения SMTP (${path})`
        }
    },
    //Имя пользователя SMTP-сервера
    sUser: {
        type: String,
        required: false,
        message: {
            type: path => `Имя пользователя SMTP-сервера (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указано имя пользователя SMTP-сервера (${path})`
        }
    },
    //Пароль пользователя SMTP-сервера
    sPass: {
        type: String,
        required: false,
        message: {
            type: path => `Пароль пользователя SMTP-сервера (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указан пароль пользователя SMTP-сервера (${path})`
        }
    },
    //Поддерживать самоподписанные сертификаты при проверке безопасности
    bRejectUnauthorized: {
        type: Boolean,
        required: true,
        message: {
            type: path => `Признак поддержки самоподписанных сертификатов SMTP (${path}) имеет некорректный тип данных (ожидалось - Boolean)`,
            required: path => `Не указан признак поддержки самоподписанных сертификатов SMTP (${path})`
        }
    },
    //Наименование отправителя для исходящих сообщений
    sFrom: {
        type: String,
        required: false,
        message: {
            type: path => `Наименование отправителя для исходящих сообщений (${path}) имеет некорректный тип данных (ожидалось - String)`,
            required: path => `Не указано наименование отправителя для исходящих сообщений (${path})`
        }
    }
});

//Схема валидации файла конфигурации
const config = new Schema({
    //Общие параметры
    common: {
        schema: common,
        required: true,
        message: {
            required: path => `Не указаны общие параметры конфигурации сервера приложений (${path})`
        }
    },
    //Параметры подключения к БД
    dbConnect: {
        schema: dbConnect,
        required: true,
        message: {
            required: path => `Не указаны параметры подключения к БД (${path})`
        }
    },
    //Параметры обработки очереди исходящих сообщений
    outGoing: {
        schema: outGoing,
        required: true,
        message: {
            required: path => `Не указаны параметры обработки очереди исходящих сообщений (${path})`
        }
    },
    //Параметры обработки очереди входящих сообщений
    inComing: {
        schema: inComing,
        required: true,
        message: {
            required: path => `Не указаны параметры обработки очереди входящих сообщений (${path})`
        }
    },
    //Параметры подключения к Kafka
    kafka: {
        schema: defKafka(true, "kafka"),
        required: true,
        message: {
            required: path => `Не указаны параметры подключения Kafka (${path})`
        }
    },
    //Параметры подключения к MQTT
    mqtt: {
        schema: defMQTT(true, "mqtt"),
        required: true,
        message: {
            required: path => `Не указаны параметры подключения MQTT (${path})`
        }
    },
    //Параметры отправки E-Mail уведомлений
    mail: {
        schema: mail,
        required: true,
        message: {
            required: path => `Не указаны параметры отправки E-Mail уведомлений (${path})`
        }
    }
});

//------------------
//  Интерфейс модуля
//------------------

//Схема валидации общих параметров сервера приложений
exports.common = common;
//Схема валидации записи журнала работы сервиса обмена
exports.dbConnect = dbConnect;
//Схема валидации параметров обработки очереди исходящих сообщений
exports.outGoing = outGoing;
//Схема валидации параметров обработки очереди входящих сообщений
exports.inComing = inComing;
//Схема валидации параметров отправки E-Mail уведомлений
exports.mail = mail;
//Схема валидации файла конфигурации
exports.config = config;
