#pragma once

// NOTE : The following MIT license applies to this file ONLY and not to the SDK as a whole. Please review the SDK documentation 
// for the description of the full license terms, which are also provided in the file "NDI License Agreement.pdf" within the SDK or 
// online at http://new.tk/ndisdk_license/. Your use of any part of this SDK is acknowledgment that you agree to the SDK license 
// terms. THe full NDI SDK may be downloaded at https://www.newtek.com/ndi/sdk/
//
//***********************************************************************************************************************************************
// 
// Copyright(c) 2014-2017 NewTek, inc
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 
// files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 
// merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is 
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//***********************************************************************************************************************************************

//**************************************************************************************************************************
// Structures and type definitions required by NDI finding
// The reference to an instance of the receiver
typedef void* NDIlib_recv_instance_t;

typedef enum NDIlib_recv_bandwidth_e
{
	NDIlib_recv_bandwidth_metadata_only = -10, // Receive metadata.
	NDIlib_recv_bandwidth_audio_only	=  10, // Receive metadata, audio.
	NDIlib_recv_bandwidth_lowest		=  0,  // Receive metadata, audio, video at a lower bandwidth and resolution.
	NDIlib_recv_bandwidth_highest		=  100 // Receive metadata, audio, video at full resolution.

}	NDIlib_recv_bandwidth_e;

typedef enum NDIlib_recv_color_format_e
{	
	NDIlib_recv_color_format_BGRX_BGRA = 0,	// No alpha channel: BGRX, Alpha channel: BGRA	
	NDIlib_recv_color_format_UYVY_BGRA = 1,	// No alpha channel: UYVY, Alpha channel: BGRA
	NDIlib_recv_color_format_RGBX_RGBA = 2,	// No alpha channel: RGBX, Alpha channel: RGBA
	NDIlib_recv_color_format_UYVY_RGBA = 3,	// No alpha channel: UYVY, Alpha channel: RGBA

#ifdef _WIN32
	// On Windows there are some APIs that require bottom to top images in RGBA format. Specifying
	// this format will return images in this format. The image data pointer will still point to the
	// "top" of the image, althought he stride will be negative. You can get the "bottom" line of the image
	// using : video_data.p_data + (video_data.yres - 1)*video_data.line_stride_in_bytes
	NDIlib_recv_color_format_BGRX_BGRA_flipped = 200,
#endif

	// Read the SDK documentation to understand the pros and cons of this format. 
	NDIlib_recv_color_format_fastest = 100,

	// Legacy definitions for backwards compatability
	NDIlib_recv_color_format_e_BGRX_BGRA = NDIlib_recv_color_format_BGRX_BGRA,
	NDIlib_recv_color_format_e_UYVY_BGRA = NDIlib_recv_color_format_UYVY_BGRA,
	NDIlib_recv_color_format_e_RGBX_RGBA = NDIlib_recv_color_format_RGBX_RGBA,
	NDIlib_recv_color_format_e_UYVY_RGBA = NDIlib_recv_color_format_UYVY_RGBA
	
}	NDIlib_recv_color_format_e;

// The creation structure that is used when you are creating a receiver
typedef struct NDIlib_recv_create_v3_t
{	// The source that you wish to connect to.
	NDIlib_source_t source_to_connect_to;

	// Your preference of color space. See above.
	NDIlib_recv_color_format_e color_format;

	// The bandwidth setting that you wish to use for this video source. Bandwidth
	// controlled by changing both the compression level and the resolution of the source.
	// A good use for low bandwidth is working on WIFI connections. 
	NDIlib_recv_bandwidth_e bandwidth;

	// When this flag is FALSE, all video that you receive will be progressive. For sources
	// that provide fields, this is de-interlaced on the receiving side (because we cannot change
	// what the up-stream source was actually rendering. This is provided as a convenience to
	// down-stream sources that do not wish to understand fielded video. There is almost no 
	// performance impact of using this function.
	bool allow_video_fields;

	// The name of the NDI receiver to create. This is a NULL terminated UTF8 string and should be 
	// the name of receive channel that you have. This is in many ways symettric with the name of
	// senders, so this might be "Channel 1" on your system.
	const char* p_ndi_name;

#if NDILIB_CPP_DEFAULT_CONSTRUCTORS
	NDIlib_recv_create_v3_t(const NDIlib_source_t source_to_connect_to_ = NDIlib_source_t(), NDIlib_recv_color_format_e color_format_ = NDIlib_recv_color_format_UYVY_BGRA,
		NDIlib_recv_bandwidth_e bandwidth_ = NDIlib_recv_bandwidth_highest, bool allow_video_fields_ = true, const char* p_ndi_name_ = NULL);
#endif // NDILIB_CPP_DEFAULT_CONSTRUCTORS

}	NDIlib_recv_create_v3_t;


// This allows you determine the current performance levels of the receiving to be able to detect whether frames have been dropped
typedef struct NDIlib_recv_performance_t
{	// The number of video frames
	int64_t video_frames;

	// The number of audio frames
	int64_t audio_frames;

	// The number of metadata frames
	int64_t metadata_frames;

#if NDILIB_CPP_DEFAULT_CONSTRUCTORS
	NDIlib_recv_performance_t(void);
#endif // NDILIB_CPP_DEFAULT_CONSTRUCTORS

}	NDIlib_recv_performance_t;

// Get the current queue depths
typedef struct NDIlib_recv_queue_t
{	// The number of video frames
	int video_frames;

	// The number of audio frames
	int audio_frames;

	// The number of metadata frames
	int metadata_frames;

#if NDILIB_CPP_DEFAULT_CONSTRUCTORS
	NDIlib_recv_queue_t(void);
#endif // NDILIB_CPP_DEFAULT_CONSTRUCTORS

}	NDIlib_recv_queue_t;

//**************************************************************************************************************************
// Create a new receiver instance. This will return NULL if it fails.
PROCESSINGNDILIB_API
NDIlib_recv_instance_t NDIlib_recv_create_v3(const NDIlib_recv_create_v3_t* p_create_settings);

// This will destroy an existing receiver instance.
PROCESSINGNDILIB_API
void NDIlib_recv_destroy(NDIlib_recv_instance_t p_instance);

// This will allow you to receive video, audio and metadata frames.
// Any of the buffers can be NULL, in which case data of that type
// will not be captured in this call. This call can be called simultaneously
// on separate threads, so it is entirely possible to receive audio, video, metadata
// all on separate threads. This function will return NDIlib_frame_type_none if no
// data is received within the specified timeout and NDIlib_frame_type_error if the connection is lost.
// Buffers captured with this must be freed with the appropriate free function below.
PROCESSINGNDILIB_API
NDIlib_frame_type_e NDIlib_recv_capture_v2(
	NDIlib_recv_instance_t p_instance,   // The library instance
	NDIlib_video_frame_v2_t* p_video_data,  // The video data received (can be NULL)
	NDIlib_audio_frame_v2_t* p_audio_data,  // The audio data received (can be NULL)
	NDIlib_metadata_frame_t* p_metadata, // The metadata received (can be NULL)
	uint32_t timeout_in_ms);             // The amount of time in milliseconds to wait for data.

// Free the buffers returned by capture for video
PROCESSINGNDILIB_API
void NDIlib_recv_free_video_v2(NDIlib_recv_instance_t p_instance, const NDIlib_video_frame_v2_t* p_video_data);

// Free the buffers returned by capture for audio
PROCESSINGNDILIB_API 
void NDIlib_recv_free_audio_v2(NDIlib_recv_instance_t p_instance, const NDIlib_audio_frame_v2_t* p_audio_data);

// Free the buffers returned by capture for metadata
PROCESSINGNDILIB_API
void NDIlib_recv_free_metadata(NDIlib_recv_instance_t p_instance, const NDIlib_metadata_frame_t* p_metadata);

// This will free a string that was allocated and returned by NDIlib_recv (for instance the NDIlib_recv_get_web_control) function.
PROCESSINGNDILIB_API
void NDIlib_recv_free_string(NDIlib_recv_instance_t p_instance, const char* p_string);

// This function will send a meta message to the source that we are connected too. This returns FALSE if we are
// not currently connected to anything.
PROCESSINGNDILIB_API
bool NDIlib_recv_send_metadata(NDIlib_recv_instance_t p_instance, const NDIlib_metadata_frame_t* p_metadata);

// Set the up-stream tally notifications. This returns FALSE if we are not currently connected to anything. That
// said, the moment that we do connect to something it will automatically be sent the tally state.
PROCESSINGNDILIB_API
bool NDIlib_recv_set_tally(NDIlib_recv_instance_t p_instance, const NDIlib_tally_t* p_tally);

// Get the current performance structures. This can be used to determine if you have been calling NDIlib_recv_capture fast
// enough, or if your processing of data is not keeping up with real-time. The total structure will give you the total frame
// counts received, the dropped structure will tell you how many frames have been dropped. Either of these could be NULL.
PROCESSINGNDILIB_API
void NDIlib_recv_get_performance(NDIlib_recv_instance_t p_instance, NDIlib_recv_performance_t* p_total, NDIlib_recv_performance_t* p_dropped);

// This will allow you to determine the current queue depth for all of the frame sources at any time. 
PROCESSINGNDILIB_API
void NDIlib_recv_get_queue(NDIlib_recv_instance_t p_instance, NDIlib_recv_queue_t* p_total);

// Connection based metadata is data that is sent automatically each time a new connection is received. You queue all of these
// up and they are sent on each connection. To reset them you need to clear them all and set them up again. 
PROCESSINGNDILIB_API
void NDIlib_recv_clear_connection_metadata(NDIlib_recv_instance_t p_instance);

// Add a connection metadata string to the list of what is sent on each new connection. If someone is already connected then
// this string will be sent to them immediately.
PROCESSINGNDILIB_API
void NDIlib_recv_add_connection_metadata(NDIlib_recv_instance_t p_instance, const NDIlib_metadata_frame_t* p_metadata);

// Is this receiver currently connected to a source on the other end, or has the source not yet been found or is no longe ronline.
// This will normally return 0 or 1
PROCESSINGNDILIB_API
int NDIlib_recv_get_no_connections(NDIlib_recv_instance_t p_instance);

// Get the URL that might be used for configuration of this input. Note that it might take a second or two after the connection for 
// this value to be set. This function will return NULL if there is no web control user interface. You should call NDIlib_recv_free_string
// to free the string that is returned by this function. The returned value will be a fully formed URL, for instamce "http://10.28.1.192/configuration/"
// To avoid the need to poll this function, you can know when the value of this function might have changed when the 
// NDILib_recv_capture* call would return NDIlib_frame_type_status_change
PROCESSINGNDILIB_API
const char* NDIlib_recv_get_web_control(NDIlib_recv_instance_t p_instance);