/* maybe.c */
#include <maybe.h>

void zero(int8 *str, int16 size) {
	int16 n;
	int8 *p;

	for (p=str, n=size; n; p++, n--)
		*p = 0;
	
	return;
}

Maybe *maybe(bool hasval, void *val) {
	Maybe *p;
	int16 size;

	size = sizeof(struct s_maybe);
	p = (Maybe *)alloc(size);
	assert(p);
	zero($1 p, size);

	if (!hasval) {
		p->type = false;
		p->val = $v 0;
	}
	else {
		p->type = true;
		p->val = val;
	}

	return p;
}

void showmaybe(int8 *str, Maybe *m) {
	if (!m)
		return;
	
	printf("(Maybe *)%s = ", str);
	fflush(stdout);

	if (empty(m))
		printf("Nothing\n");
	else
		printf("Just (%.08x)\n", $i m->val);

	return;
}

int16 stringlen(int8 *str) {
	int16 n;
	int8 *p;

	assert(str);
	for (n=0, p=str; *p; p++, n++);

	return n;
}

bool findchar(int8 *str, int8 c) {
	bool found;
	int8 *p;

	assert(str);
	for (found=false, p=str; *p; p++)
		if (*p == c) {
			found = true;
			break;
		}

	return found;
}

Maybe *hasat(int8 *str) {
	return maybe(findchar(str, (int8)'@'), $v 0);
}
Maybe *hasdot(int8 *str) {
	return maybe(findchar(str, (int8)'.'), $v 0);
}
Maybe *checklength(int8 *str) {
	int16 len;

	len = stringlen(str);
	return maybe(
		!((len < 3) || (len > 16)), $v 0
	);
}

Maybe *validate(int8 *email) {
	Maybe *m1, *m2, *m3, *ret;

	m1 = hasat(email);
	m2 = hasdot(email);
	m3 = checklength(email);

	if (all(m1, m2, m3))
		ret = maybe(true, $v email);
	else
		ret = maybe(false, $v 0);

	destroy(m1);
	destroy(m2);
	destroy(m3);
	
	return ret;
}

bool _all(Maybe *arg1, ...) {
	int8 *p;
	Maybe **pp;
	Maybe *m;

	p = $1 &arg1;
	pp = (Maybe **)p;
	if (!pp)
		return false;
	m = *pp;
	if (!m)
		return false;

	for (; m; p += 4, pp = (Maybe **)p) {
		m = *pp;

		if (m)
			if (!m->type)
				return false;
	}

	return true;
}

int main(int argc, char *argv[])
{
	int8 *str;
	Maybe *m;

	if (argc < 2)
		return 0;
	else
		str = $1 argv[1];

	m = validate(str);
	show(m);
	destroy(m);

	return 0;
}

