/*
 * Copyright (C) 2012 Andrew Mortensen
 *
 * This file is part of the sca module for Kamailio, a free SIP server.
 *
 * The sca module is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version
 *
 * The sca module is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA. 02110-1301 USA
 */
#include "../../core/str.h"

#ifndef SCA_APPEARANCE_H
#define SCA_APPEARANCE_H

#include "sca_dialog.h"

enum
{
	SCA_APPEARANCE_STATE_IDLE = 0,
	SCA_APPEARANCE_STATE_SEIZED,
	SCA_APPEARANCE_STATE_PROGRESSING,
	SCA_APPEARANCE_STATE_ALERTING,
	SCA_APPEARANCE_STATE_ACTIVE_PENDING,
	SCA_APPEARANCE_STATE_ACTIVE,
	SCA_APPEARANCE_STATE_HELD,
	SCA_APPEARANCE_STATE_HELD_PRIVATE,
	SCA_APPEARANCE_STATE_UNKNOWN = 0xff,
};

#define sca_appearance_is_held(app1)                       \
	((app1)                                                \
			&& ((app1)->state == SCA_APPEARANCE_STATE_HELD \
					|| (app1)->state == SCA_APPEARANCE_STATE_HELD_PRIVATE))

enum
{
	SCA_APPEARANCE_FLAG_DEFAULT = 0,
	SCA_APPEARANCE_FLAG_OWNER_PENDING = (1 << 0),
	SCA_APPEARANCE_FLAG_CALLEE_PENDING = (1 << 1),
};

enum
{
	SCA_APPEARANCE_OK = 0,
	SCA_APPEARANCE_ERR_NOT_IN_USE = 0x1001,
	SCA_APPEARANCE_ERR_INDEX_INVALID = 0x1002,
	SCA_APPEARANCE_ERR_INDEX_UNAVAILABLE = 0x1004,
	SCA_APPEARANCE_ERR_MALLOC = 0x1008,
	SCA_APPEARANCE_ERR_UNKNOWN = 0x1f00,
};
#define SCA_APPEARANCE_INDEX_UNAVAILABLE -2

/*
 * maximum lifetime of an active, pending appearance.
 * enough to allow retransmissions of the caller's
 * ACK. on receipt of the caller's ACK, we promote
 * the SCA callee's state to active.
 */
enum
{
	// Polycoms aggressively resubscribe line-seizes, give them time
	SCA_APPEARANCE_STATE_SEIZED_TTL = 120,

	// enough time to allow retransmissions (~32s)
	SCA_APPEARANCE_STATE_PENDING_TTL = 35,
};

extern const str SCA_APPEARANCE_INDEX_STR;
extern const str SCA_APPEARANCE_STATE_STR;
extern const str SCA_APPEARANCE_URI_STR;

extern const str SCA_APPEARANCE_STATE_STR_IDLE;
extern const str SCA_APPEARANCE_STATE_STR_SEIZED;
extern const str SCA_APPEARANCE_STATE_STR_PROGRESSING;
extern const str SCA_APPEARANCE_STATE_STR_ALERTING;
extern const str SCA_APPEARANCE_STATE_STR_ACTIVE;
extern const str SCA_APPEARANCE_STATE_STR_HELD;
extern const str SCA_APPEARANCE_STATE_STR_HELD_PRIVATE;

struct _sca_appearance_times
{
	// time of appearance creation
	time_t ctime;

	// time of last appearance state change
	time_t mtime;

	// time of last end-to-end activity
	time_t atime;
};
typedef struct _sca_appearance_times sca_appearance_times;

struct _sca_appearance_list;
struct _sca_appearance
{
	int index;
	int state;
	str uri;

	int flags;

	str owner;
	str callee;
	sca_dialog dialog;
	sca_appearance_times times;

	str prev_owner;
	str prev_callee;
	sca_dialog prev_dialog;

	struct _sca_appearance_list *appearance_list;
	struct _sca_appearance *next;
};
typedef struct _sca_appearance sca_appearance;

struct _sca_appearance_list
{
	str aor;
	int appearance_count;
	sca_appearance *appearances;
};
typedef struct _sca_appearance_list sca_appearance_list;

void sca_appearance_state_to_str(int, str *);
int sca_appearance_state_from_str(str *);

sca_appearance *sca_appearance_seize_index_unsafe(
		sca_mod *, str *, str *, int, int, int *);
int sca_appearance_seize_index(sca_mod *, str *, int, str *);
int sca_appearance_seize_next_available_index(sca_mod *, str *, str *);
sca_appearance *sca_appearance_seize_next_available_unsafe(
		sca_mod *, str *, str *, int);
void sca_appearance_update_state_unsafe(sca_appearance *, int);
int sca_appearance_update_owner_unsafe(sca_appearance *, str *);
int sca_appearance_update_callee_unsafe(sca_appearance *, str *);
int sca_appearance_update_dialog_unsafe(sca_appearance *, str *, str *, str *);
int sca_appearance_update_unsafe(
		sca_appearance *, int, str *, str *, sca_dialog *, str *, str *);
int sca_appearance_update_index(
		sca_mod *, str *, int, int, str *, str *, sca_dialog *);
int sca_appearance_release_index(sca_mod *, str *, int);
int sca_appearance_owner_release_all(str *, str *);
int sca_appearance_state_for_index(sca_mod *, str *, int);
sca_appearance *sca_appearance_for_index_unsafe(sca_mod *, str *, int, int);
sca_appearance *sca_appearance_for_dialog_unsafe(
		sca_mod *, str *, sca_dialog *, int);
sca_appearance *sca_appearance_for_tags_unsafe(
		sca_mod *, str *, str *, str *, str *, int);

int sca_appearance_register(sca_mod *, str *);
int sca_appearance_unregister(sca_mod *, str *);
void sca_appearance_list_insert_appearance(
		sca_appearance_list *, sca_appearance *);
sca_appearance *sca_appearance_list_unlink_index(sca_appearance_list *, int);
int sca_appearance_list_unlink_appearance(
		sca_appearance_list *, sca_appearance **);
sca_appearance *sca_appearance_unlink_by_tags(
		sca_mod *, str *, str *, str *, str *);

sca_appearance *sca_appearance_create(int, str *);
void sca_appearance_free(sca_appearance *);

int sca_uri_is_shared_appearance(sca_mod *, str *);
int sca_uri_lock_shared_appearance(sca_mod *, str *);
int sca_uri_lock_if_shared_appearance(sca_mod *, str *, int *);

void sca_appearance_purge_stale(unsigned int, void *);
#endif // SCA_APPEARANCE_H