#include <xcap/common_policy.h>

cp_unknown_t *create_unknown(int data_size)
{
	cp_unknown_t *u = cds_malloc(sizeof(cp_unknown_t) + data_size);
	u->next = NULL;
	return u;
}

/* ------- freeing used memory for common-rules ------- */

static void free_identity(cp_identity_t *id)
{
	cp_id_t *i, *ni;
	cp_domain_t *d, *nd;
	cp_except_t *e, *ne;
	cp_except_domain_t *ed, *ned;

	if(!id)
		return;

	i = id->ids;
	while(i) {
		ni = i->next;
		str_free_content(&i->entity);
		cds_free(i);
		i = ni;
	}

	d = id->domains;
	while(d) {
		nd = d->next;
		str_free_content(&d->domain);
		cds_free(d);
		d = nd;
	}

	e = id->excepts;
	while(e) {
		ne = e->next;
		str_free_content(&e->entity);
		cds_free(e);
		e = ne;
	}

	if(id->any_identity) {
		d = id->any_identity->domains;
		while(d) {
			nd = d->next;
			str_free_content(&d->domain);
			cds_free(d);
			d = nd;
		}

		ed = id->any_identity->except_domains;
		while(ed) {
			ned = ed->next;
			str_free_content(&ed->domain);
			cds_free(ed);
			ed = ned;
		}
	}

	cds_free(id);
}

static void free_conditions(cp_conditions_t *c)
{
	cp_sphere_t *s, *n;
	if(!c)
		return;
	if(c->validity)
		cds_free(c->validity);
	if(c->identity)
		free_identity(c->identity);
	s = c->spheres;
	while(s) {
		n = s->next;
		str_free_content(&s->value);
		cds_free(s);
		s = n;
	}
	cds_free(c);
}


static void free_transformations(cp_transformations_t *t)
{
	cp_unknown_t *u, *nu;

	if(!t)
		return;

	u = t->unknown;
	while(u) {
		nu = u->next;
		cds_free(u);
		u = nu;
	}
	cds_free(t);
}

void free_cp_rule(cp_rule_t *r, cp_free_actions_func free_actions)
{
	if(!r)
		return;
	if(r->conditions)
		free_conditions(r->conditions);
	if(r->actions)
		free_actions(r->actions);
	if(r->transformations)
		free_transformations(r->transformations);
	str_free_content(&r->id);
	cds_free(r);
}

void free_common_rules(cp_ruleset_t *r, cp_free_actions_func free_actions)
{
	cp_rule_t *rule, *n;

	if(!r)
		return;
	rule = r->rules;
	while(rule) {
		n = rule->next;
		free_cp_rule(rule, free_actions);
		rule = n;
	}
	cds_free(r);
}

static void parse_uri(const str_t *uri, str_t *user, str_t *domain)
{
	char *a;
	char *d;
	str_t s;

	str_clear(user);
	str_clear(domain);
	if(uri->len > 0) {
		d = str_strchr(uri, ':');
		if(d) {
			s.s = d + 1;
			s.len = uri->len - (s.s - uri->s);
		} else
			s = *uri;
		a = str_strchr(&s, '@');
		if(a) {
			user->s = s.s;
			user->len = a - s.s;
		}
		domain->s = s.s + user->len;
		if(a)
			domain->s++;
		domain->len = uri->len - (domain->s - uri->s);

		/*		TRACE_LOG("parse uri \'%.*s\': user=\'%.*s\' domain=\'%.*s\'\n",
				FMT_STR(*uri), FMT_STR(*user), FMT_STR(*domain));*/
	}
}


/* returns 1 if rule is used for uri */
int is_rule_for_uri(cp_rule_t *rule, const str_t *uri)
{
	cp_identity_t *id;
	int ok = 0;
	str_t domain, user;
	str_t d_, u_;
	cp_domain_t *d;
	cp_id_t *i;
	cp_except_t *e;
	cp_except_domain_t *ed;

	if(!rule)
		return 0;
	if(!rule->conditions)
		return 1; /* FIXME: ??? */
	id = rule->conditions->identity;
	if(!id)
		return 0;

	parse_uri(uri, &user, &domain);

	i = id->ids;
	while(i) {
		parse_uri(&i->entity, &u_, &d_);
		/*		TRACE_LOG("comparing uris \'%.*s\' \'%.*s\' "
				"domains \'%.*s\' \'%.*s\'\n",
				FMT_STR(user), FMT_STR(u_),
				FMT_STR(domain), FMT_STR(d_));*/
		if(str_case_equals(&user, &u_) == 0) {
			if(str_nocase_equals(&domain, &d_) == 0) {
				/*				TRACE_LOG("id found\n");*/
				return 1;
			}
		}
		i = i->next;
	}

	d = id->domains;
	while(d) {
		/*		TRACE_LOG("comparing domains \'%.*s\' \'%.*s\'\n",
				FMT_STR(domain), FMT_STR(d->domain));*/
		if(str_nocase_equals(&domain, &d->domain) == 0)
			ok = 1;
		d = d->next;
	}
	if(ok) {
		e = id->excepts;
		while(e) {
			if(str_case_equals(&user, &e->entity) == 0)
				return 0; /* excepts matched */
			e = e->next;
		}
		/*		TRACE_LOG("domain found and excepts not matched\n");*/
		return 1;
	}

	if(id->any_identity) {
		d = id->any_identity->domains;
		while(d) {
			if(str_nocase_equals(&domain, &d->domain) == 0) {
				/*				TRACE_LOG("domain matches for anonymous\n");*/
				return 1;
			}
			d = d->next;
		}

		ed = id->any_identity->except_domains;
		while(ed) {
			if(str_nocase_equals(&domain, &d->domain) == 0)
				return 0;
			ed = ed->next;
		}
	}
	return 0;
}
