//==============================================================================
//
//  OvenMediaEngine
//
//  Created by Hyunjun Jang
//  Copyright (c) 2020 AirenSoft. All rights reserved.
//
//==============================================================================
#pragma once

#include "bypass_if_match.h"

namespace cfg
{
	namespace vhost
	{
		namespace app
		{
			namespace oprf
			{
				struct VideoProfile : public Item
				{
				protected:
					ov::String _name;
					bool _bypass = false;
					ov::String _codec;
					ov::String _modules;
					
					int _width = 0;
					int _height = 0;
					int _bitrate = 0;
					ov::String _bitrate_string;
					double _framerate = 0.0;
					ov::String _preset;
					int _thread_count = -1;
					int _key_frame_interval = 0;
					ov::String _key_frame_interval_type = "frame";
					int _b_frames = 0;
					BypassIfMatch _bypass_if_match;
					ov::String _profile;
					int _lookahead = -1;

					// SkipFrames 
					// If the set value is greater than or equal to 0, the skip frame is automatically calculated. 
					// The skip frame is not less than the value set by the user.
					// -1 : No SkipFrame
					// 0 ~ 120 : minimum value of SkipFrames. it is automatically calculated and the SkipFrames value is changed.
					int _skip_frames = -1;

				public:
					CFG_DECLARE_CONST_REF_GETTER_OF(GetName, _name)
					CFG_DECLARE_CONST_REF_GETTER_OF(IsBypass, _bypass)
					CFG_DECLARE_CONST_REF_GETTER_OF(GetModules, _modules);
					CFG_DECLARE_CONST_REF_GETTER_OF(GetCodec, _codec)
					CFG_DECLARE_CONST_REF_GETTER_OF(GetWidth, _width)
					CFG_DECLARE_CONST_REF_GETTER_OF(GetHeight, _height)
					CFG_DECLARE_CONST_REF_GETTER_OF(GetBitrate, _bitrate)
					CFG_DECLARE_CONST_REF_GETTER_OF(GetBitrateString, _bitrate_string)
					CFG_DECLARE_CONST_REF_GETTER_OF(GetFramerate, _framerate)
					CFG_DECLARE_CONST_REF_GETTER_OF(GetPreset, _preset)
					CFG_DECLARE_CONST_REF_GETTER_OF(GetThreadCount, _thread_count)
					CFG_DECLARE_CONST_REF_GETTER_OF(GetKeyFrameInterval, _key_frame_interval)
					CFG_DECLARE_CONST_REF_GETTER_OF(GetKeyFrameIntervalType, _key_frame_interval_type)
					CFG_DECLARE_CONST_REF_GETTER_OF(GetBFrames, _b_frames)
					CFG_DECLARE_CONST_REF_GETTER_OF(GetBypassIfMatch, _bypass_if_match)
					CFG_DECLARE_CONST_REF_GETTER_OF(GetProfile, _profile)
					CFG_DECLARE_CONST_REF_GETTER_OF(GetSkipFrames, _skip_frames)
					CFG_DECLARE_CONST_REF_GETTER_OF(GetLookahead, _lookahead)

					void SetName(const ov::String &name){_name = name;}
					void SetBypass(bool bypass){_bypass = bypass;}
					void SetCodec(const ov::String &codec){_codec = codec;}
					void SetWidth(int width){_width = width;}
					void SetHeight(int height){_height = height;}
					void SetBitrate(int bitrate){_bitrate = bitrate;}
					void SetBitrateString(const ov::String &bitrate_string){_bitrate_string = bitrate_string;}
					void SetFramerate(double framerate){_framerate = framerate;}
					void SetPreset(const ov::String &preset){_preset = preset;}
					void SetThreadCount(int thread_count){_thread_count = thread_count;}
					void SetKeyFrameInterval(int key_frame_interval){_key_frame_interval = key_frame_interval;}
					void SetBFrames(int b_frames){_b_frames = b_frames;}
					void SetLookahead(int lookahead){_lookahead = lookahead;}

				protected:
					void MakeList() override
					{
						Register<Optional>("Name", &_name);
						Register<Optional>("Bypass", &_bypass);
						Register<Optional>("Codec", &_codec, 
							[=]() -> std::shared_ptr<ConfigError> {
								// <Codec> is an option when _bypass is true
								return (_bypass) ? nullptr : CreateConfigErrorPtr("Codec must be specified when bypass is false");
							});
						Register<Optional>("Modules", &_modules);
						Register<Optional>("Bitrate", &_bitrate_string,	
							[=]() -> std::shared_ptr<ConfigError> {
								// <Bitrate> is an option when _bypass is true
								return (_bypass) ? nullptr : CreateConfigErrorPtr("Bitrate must be specified when bypass is false");
							},
							[=]() -> std::shared_ptr<ConfigError> {
								auto bitrate_string = _bitrate_string.UpperCaseString();
								int multiplier = 1;
								if (bitrate_string.HasSuffix("K"))
								{
									multiplier = 1024;
								}
								else if (bitrate_string.HasSuffix("M"))
								{
									multiplier = 1024 * 1024;
								}

								_bitrate = static_cast<int>(ov::Converter::ToFloat(bitrate_string) * multiplier);

								return (_bitrate > 0) ? nullptr : CreateConfigErrorPtr("Bitrate must be greater than 0");
							});
						Register<Optional>("Width", &_width);
						Register<Optional>("Height", &_height);
						Register<Optional>("Framerate", &_framerate);
						Register<Optional>("SkipFrames", &_skip_frames, nullptr, 
							[=]() -> std::shared_ptr<ConfigError> {

								if(_framerate > 0 && _skip_frames > 0) {
									logw("Config", "Use SkipFrames in the settings, the Framerate is ignored.");
								}

								return (_skip_frames >= 0 && _skip_frames <= 120) ? nullptr : CreateConfigErrorPtr("SkipFrames must be between 0 and 120");
							});
						Register<Optional>("Preset", &_preset, nullptr, 
							[=]() -> std::shared_ptr<ConfigError> {
								auto preset = _preset.LowerCaseString();
								if(preset == "slower" || preset == "slow" || preset == "medium" || preset == "fast" || preset == "faster")
								{
									return nullptr;
								}
								return CreateConfigErrorPtr("Preset must be slower, slow, medium, fast, or faster");
							});
						Register<Optional>("ThreadCount", &_thread_count);
						Register<Optional>("KeyFrameIntervalType", &_key_frame_interval_type, nullptr, 
							[=]() -> std::shared_ptr<ConfigError> {
								auto key_frame_interval_type = _key_frame_interval_type.LowerCaseString();
								if(key_frame_interval_type == "frame" || key_frame_interval_type == "time")
								{
									return nullptr;
								}

								return CreateConfigErrorPtr("KeyFrameIntervalType must be frame or time");
							});						
						Register<Optional>("KeyFrameInterval", &_key_frame_interval, nullptr, 
							[=]() -> std::shared_ptr<ConfigError> {
								if(_key_frame_interval_type == "time")
								{
									return (_key_frame_interval > 0 && _key_frame_interval <= 10000) ? nullptr : CreateConfigErrorPtr("KeyFrameInterval must be between 0 and 10000");
								}

								return (_key_frame_interval >= 0 && _key_frame_interval <= 600) ? nullptr : CreateConfigErrorPtr("KeyFrameInterval must be between 0 and 600");
							});

						Register<Optional>("BFrames", &_b_frames, nullptr, 
							[=]() -> std::shared_ptr<ConfigError> {
								return (_b_frames >= 0 && _b_frames <= 16) ? nullptr : CreateConfigErrorPtr("BFrames must be between 0 and 16");
							});
						Register<Optional>("BypassIfMatch", &_bypass_if_match);
						Register<Optional>("Profile", &_profile, nullptr, 
							[=]() -> std::shared_ptr<ConfigError> {
							auto profile = _profile.LowerCaseString();
							if(profile == "baseline" || profile == "main" || profile == "high")
							{
								return nullptr;
							}
							return CreateConfigErrorPtr("Profile must be baseline, main or high");
						});
						Register<Optional>("Lookahead", &_lookahead);

					}
				};
			}  // namespace oprf
		} // namespace app
	} // namespace vhost
}  // namespace cfg