#ifndef _CALL_FLAGS_H_
#define _CALL_FLAGS_H_

#include <glib.h>

#include "types.h"
#include "call.h"
#include "sdp.h"


struct ng_codec {
	struct rtp_payload_type input;
	struct rtp_payload_type output;
};

struct ng_media {
	str id;
	str type;
	ng_codecs_q codecs;
	str_q codec_list;
	str destination_address;
	endpoint_t destination;

};

struct ng_tag {
	str from;
	str_q to;

	struct call_monologue *from_ml;
};

TYPED_GQUEUE(tags, struct ng_tag)


#define RTPE_NG_FLAGS_STR_Q_PARAMS \
	X(from_tags) \
	X(calls) \
	X(codec_strip) \
	X(codec_ignore) \
	X(codec_offer) \
	X(codec_transcode) \
	X(codec_mask) \
	X(codec_accept) \
	X(codec_consume) \
	X(sdes_order)		/* the order, in which crypto suites are being added to the SDP */ \
	X(sdes_offerer_pref)	/* preferred crypto suites to be selected for the offerer */

#define RTPE_NG_FLAGS_SDP_ATTR_Q_PARAMS \
	X(generic_attributes)	/* top-level (not part of an m= section) SDP session attributes */ \
	X(all_attributes)	/* top-level (not part of an m= section) SDP session attributes */

#define RTPE_NG_FLAGS_STR_CASE_HT_PARAMS \
	X(rtpext_strip) \
	X(rtpext_mask) \
	X(codec_except) \
	X(sdes_no)		/* individual crypto suites which are excluded */ \
	X(sdes_only)		/* individual crypto suites which are only accepted */


struct sdp_ng_flags {
	enum ng_opmode opmode;
	enum message_type message_type;
	unsigned int code;
	str call_id;
	str to_call_id;
	str from_tag;
	str to_tag;
	str via_branch;
	str source_tag;
	str source_call_id;
	str sdp;
	str received_from_family;
	str received_from_address;
	str address_family_str;
	const struct transport_protocol *transport_protocol;
	sockaddr_t parsed_received_from;
	sockaddr_t media_address;
	str direction[2];
	str interface;
	str instance;
	sockfamily_t *address_family;
	int tos;
	str record_call_str;
	str recording_file;
	str recording_path;
	str recording_pattern;
	str metadata;
	str label;
	str set_label;
	str to_label;
	str address;
	str xmlrpc_callback;
	endpoint_t dtmf_log_dest;
	str_case_value_ht codec_set;
	int ptime,
	    rev_ptime;
	str dtls_fingerprint;

	/* keep session level attributes for internal proper parsing */
	sdp_origin session_sdp_orig;
	str session_sdp_name;

	str session_timing; /* t= line */
	struct session_bandwidth session_bandwidth;
	str_q groups_other;	/* a=group:xxx */
	str_ht bundles; // a=group:BUNDLE ...
	str session_information; // i= line
	str session_uri; // u= line
	str session_email; // e= line
	str session_phone; // p= line

	/* commands to manipulate attr lines in SDP */
	struct sdp_manipulations * sdp_manipulations[__MT_MAX];
	/* types of medias to be removed by media lvl manipulations */
	bool sdp_media_remove[__MT_MAX];

	ng_medias_q medias;

	enum {
		ICE_DEFAULT = 0,
		ICE_REMOVE,
		ICE_FORCE,
		ICE_FORCE_RELAY,
		ICE_OPTIONAL,
	} ice_option:3;
	enum {
		ICE_LITE_DEFAULT = 0,
		ICE_LITE_OFF,
		ICE_LITE_FWD,
		ICE_LITE_BKW,
		ICE_LITE_BOTH,
	} ice_lite_option:3;
	enum {
		MEO_DEFAULT = 0,
		MEO_BLACKHOLE,
		MEO_FWD,
		MEO_BKW,
		MEO_BOTH,
	} media_echo:3;
	enum {
		ALL_NONE = 0,
		ALL_ALL,
		ALL_OFFER_ANSWER,
		ALL_NON_OFFER_ANSWER,
		ALL_FLOWS,
	} all:3;
	enum {
		AP_DEFAULT = 0,
		AP_OFF,
		AP_TRANSCODING,
		AP_FORCE,
	} audio_player:2;
	enum {
		AK_NONE = 0,
		AK_SDP,
		AK_ADDRESS,
	} alias_key:2;
	enum endpoint_learning el_option;
	enum block_dtmf_mode block_dtmf_mode;
	int delay_buffer;
	GArray *frequencies;
	int volume;
	char digit;
	str trigger;
	enum block_dtmf_mode block_dtmf_mode_trigger;
	str trigger_end;
	enum block_dtmf_mode block_dtmf_mode_trigger_end;
	int trigger_end_digits;
	int trigger_end_ms;
	int dtmf_delay;
	int media_rec_slot_offer;
	int media_rec_slot_answer;
	int media_rec_slots;
	int repeat_times;
	long long repeat_duration;
	int delete_delay;
	str file;
	str moh_file;
	str blob;
	str blob64;
	str moh_blob;
	long long db_id;
	long long moh_db_id;
	long long duration;
	long long pause;
	long long start_pos;
	str vsc_start_rec;
	str vsc_stop_rec;
	str vsc_start_stop_rec;
	str vsc_pause_rec;
	str vsc_pause_resume_rec;
	str vsc_start_pause_resume_rec;
	int t38_version;
	tags_q tags;

#define X(x) str_q x;
RTPE_NG_FLAGS_STR_Q_PARAMS
#undef X

#define X(x) sdp_attr_q x;
RTPE_NG_FLAGS_SDP_ATTR_Q_PARAMS
#undef X

#define X(x) str_case_ht x;
RTPE_NG_FLAGS_STR_CASE_HT_PARAMS
#undef X

	bool         asymmetric:1,
		     rtpp_flags:1,
	             protocol_accept:1,
	             no_redis_update:1,
	             unidirectional:1,
	             trust_address:1,
	             port_latching:1,
	             no_port_latching:1,
	             replace_origin:1,
	             replace_origin_full:1,
	             replace_sdp_version:1,
	             force_inc_sdp_ver:1,
	             replace_username:1,
	             replace_sess_name:1,
	             replace_zero_address:1,
	             rtcp_mux_offer:1,
	             rtcp_mux_require:1,
	             rtcp_mux_demux:1,
	             rtcp_mux_accept:1,
	             rtcp_mux_reject:1,
	             bundle_offer:1,
	             bundle_require:1,
	             bundle_accept:1,
	             bundle_reject:1,
	             bundle_strict:1,
		     ice_reject:1,
		     rtcp_mirror:1,
		     mix:1,
		     trickle_ice:1,
	             no_rtcp_attr:1,
	             no_tls_id:1,
	             full_rtcp_attr:1,
	             generate_rtcp:1,
	             generate_rtcp_off:1,
	             generate_mid:1,
	             strict_source:1,
	             media_handover:1,
	             dtls_passive:1,
	             dtls_reverse_passive:1,
	             osrtp_accept_legacy:1,
	             osrtp_accept_rfc:1,
	             osrtp_offer:1,
	             osrtp_offer_legacy:1,
	             reset:1,
		     egress:1,
		     siprec:1,
	             fragment:1,
	             record_call:1,
		     discard_recording:1,
		     exclude_recording:1,
		     skip_recording_db:1,
		     recording_vsc:1,
		     recording_announcement:1,
		     debug:1,
		     inactive:1,
	             loop_protect:1,
	             original_sendrecv:1,
	             single_codec:1,
		     reuse_codec:1,
		     static_codecs:1,
		     allow_no_codec_media:1,
		     allow_transcoding:1,
		     force_transcoding:1,
		     allow_asymmetric_codecs:1,
		     early_media:1,
		     accept_any:1,
	             inject_dtmf:1,
		     detect_dtmf:1,
		     block_dtmf:1,
		     block_egress:1,
	             t38_decode:1,
	             t38_force:1,
	             t38_stop:1,
	             t38_no_ecm:1,
	             t38_no_v17:1,
	             t38_no_v27ter:1,
	             t38_no_v29:1,
	             t38_no_v34:1,
	             t38_no_iaf:1,
	             t38_fec:1,
	             supports_load_limit:1,
	             dtls_off:1,
	             sdes_off:1,
	             sdes_unencrypted_srtp:1,
	             sdes_unencrypted_srtcp:1,
	             sdes_unauthenticated_srtp:1,
	             sdes_encrypted_srtp:1,
	             sdes_encrypted_srtcp:1,
	             sdes_authenticated_srtp:1,
	             sdes_lifetime:1,
	             sdes_pad:1,
	             sdes_static:1,
	             sdes_nonew:1,
	             sdes_prefer:1,
		     recrypt:1,
	             drop_traffic_start:1,
	             drop_traffic_stop:1,
	             passthrough_on:1,
	             passthrough_off:1,
		     block_short:1,
	             disable_jb:1,
		     nat_wait:1,
		     pierce_nat:1,
		     directional:1,
		     bidirectional:1,
		     unsubscribe:1,
		     fatal:1,
		     fast:1,
		     new_branch:1,
		     provisional:1,
		     /* to_tag is used especially by delete handling */
		     to_tag_flag:1,
		     moh_zero_connection:1,
		     /* by default sendonly */
		     moh_sendrecv:1,
		     moh_reflect:1,
		     /* prevents double MoH holds */
		     moh_double_hold:1;
};


extern bool trust_address_def;
extern bool dtls_passive_def;


void call_ng_flags_init(sdp_ng_flags *out, enum ng_opmode opmode);
void call_ng_free_flags(sdp_ng_flags *flags);

G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(sdp_ng_flags, call_ng_free_flags)


const char *call_ng_flags_flags(str *s, unsigned int, helper_arg arg);
const char *call_ng_main_flags(const ng_parser_t *, str *key, parser_arg value, helper_arg);
const char *call_ng_codec_flags(const ng_parser_t *, str *key, parser_arg value, helper_arg);

const char *call_ng_process_flags(sdp_ng_flags *out, ng_command_ctx_t *ctx);


INLINE struct sdp_manipulations *sdp_manipulations_get_by_id(struct sdp_manipulations * const array[__MT_MAX],
		enum media_type id)
{
	if (id < 0 || id >= __MT_MAX)
		return NULL;
	return array[id];
}
INLINE struct sdp_manipulations *sdp_manipulations_get_create_by_id(struct sdp_manipulations * array[__MT_MAX],
		enum media_type id)
{
	if (id < 0 || id >= __MT_MAX)
		return NULL;
	if (!array[id])
		array[id] = g_new0(__typeof(*array[id]), 1);
	return array[id];
}
INLINE struct sdp_manipulations *sdp_manipulations_get_by_name(struct sdp_manipulations * array[__MT_MAX],
		const str *s) {
	if (!str_cmp(s, "none") || !str_cmp(s, "global"))
		return sdp_manipulations_get_create_by_id(array, MT_UNKNOWN);
	enum media_type id = codec_get_type(s);
	if (id == MT_OTHER)
		return NULL;
	return sdp_manipulations_get_create_by_id(array, id);
}


// set all WebRTC-specific attributes
INLINE void ng_flags_webrtc(sdp_ng_flags *f) {
	f->transport_protocol = &transport_protocols[PROTO_UDP_TLS_RTP_SAVPF];
	f->ice_option = ICE_FORCE;
	f->trickle_ice = 1;
	f->rtcp_mux_offer = 1;
	f->rtcp_mux_require = 1;
	f->no_rtcp_attr = 1;
	f->sdes_off = 1;
	f->generate_mid = 1;
	f->bundle_offer = 1;
	f->bundle_require = 1;
}


#endif
