#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define DMID 27 // was 21
#include "dmalloc.h"
#include "mlist.h"
#include "lib.h"

#ifndef FALSE
#define FALSE 0
#endif

#ifndef TRUE
#define TRUE !FALSE
#endif

struct message {
	Pair *headers;
	time_t date;
	size_t size;
	char *subject;
	char *from;
	char *file;
	int parsed;
};

Message *message_new(char *filename, time_t date, size_t size) {
	Message *m = calloc(1,sizeof(Message));
	m->file = strdup(filename);
	m->date = date;
	m->size = size;
	return m;
}

void message_parse(Message *m) {
	char bf[BFSZ];
	char *p,*n,**prev;
	FILE *f;

	if (m->parsed) return;
	m->parsed = TRUE;

	f = fopen(m->file,"r");
	if (!f) return ;

	prev = NULL;
	while(fgets(bf,BFSZ,f)) {
		if (sisspace(bf[0])) {
			for(p = bf; sisspace(*p); p++);
			if (!*p) break;
			if (prev) {
				*prev = realloc(*prev,lib_strlen(*prev)+lib_strlen(p)+2);
				strcat(*prev," ");
				strcat(*prev,p);
			}
			continue;
		}
		p = strchr(bf,':');
		if (!p) continue;
		for(*p++ = 0; sisspace(*p); p++);
		for(n = bf; sisspace(*n); n++);
		p = strtrm(p);

		if (strcmpnc(n,"From")==0) assign(&m->from,p);
		else if (strcmpnc(n,"Subject")==0) assign(&m->subject,p);
		else if (!m->from && strcmpnc(n,"Return-Path")==0) assign(&m->from,p);
		pair_add(&m->headers,n,p);
		prev = &m->headers->val;
	}

	fclose(f);
}

void message_free(Message **m) {
	if (!m || !*m) return ;
	pair_free(&(*m)->headers);
	free((*m)->subject);
	free((*m)->from);
	free((*m)->file);	
	free(*m);
}

int message_sort_file(Message **p1, Message **p2) { return strcmp((*p1)->file,(*p2)->file); }
int message_sort_date(Message **p1, Message **p2) { return (int) ((*p1)->date - (*p2)->date); }
int message_sort_size(Message **p1, Message **p2) { return (int) ((*p1)->size - (*p2)->size); }
int message_sort_from(Message **p1, Message **p2) { message_parse((*p1)); message_parse((*p2)); return strcmp((*p1)->from?(*p1)->from:"",(*p2)->from?(*p2)->from:""); }
int message_sort_subject(Message **p1, Message **p2) { message_parse((*p1)); message_parse((*p2)); return strcmp((*p1)->subject?(*p1)->subject:"",(*p2)->subject?(*p2)->subject:""); }

char *message_header(Message *m, char *header) {
	if (!m) return NULL;
	if (!m->parsed) message_parse(m);
	return pair_find_null(m->headers,header);
}

char *message_subject(Message *m) {
	if (!m) return NULL;
	if (!m->parsed) message_parse(m);
	return m->subject;
}

char *message_from(Message *m) {
	if (!m) return NULL;
	if (!m->parsed) message_parse(m);
	return m->from;
}

time_t message_date(Message *m) {
	if (!m) return 0;
	return m->date;
}

char *message_file(Message *m) {
	if (!m) return NULL;
	return m->file;
}

int message_size(Message *m) {
	if (!m) return 0;
	return (int) m->size;
}

/*
	ML_SORT_FILENAME,
	ML_SORT_DATE,
	ML_SORT_SIZE,
	ML_SORT_FROM,
	ML_SORT_SUBJECT	
*/

Array *mlist_list(char *path, char *mask, int(*match)(void *, Message *), void *mdata, int from, int size, int sort, int reverse, int *max) {
	Array *list = NULL;
	WILD_HANDLE *h;
	WILD_DATA data;
	char bf[BFSZ];
	Message *m;
	int count;
	int found;
	int r;

	count = found = 0;
	make_path(path,mask,bf,BFSZ);
	for(r = wild_first(&h,bf,&data); r; r = wild_next(h,&data)) {
		if (strcmp(data.name,"..")==0) continue;
		if (strcmp(data.name,".")==0) continue;

		if (count++ < from) continue;
		if (size && found >= size) continue;

		make_path(path,data.name,bf,BFSZ);
		m = message_new(bf,data.time_create,data.size);

		if (match && !match(mdata,m)) continue;

		found++;

		if (!list) {
			list = array_new(250);			
			array_setup_free(list,(void (*)(void **))message_free);
			if (sort == ML_SORT_FILENAME) array_setup_compare(list,(int (*)(void **, void **))message_sort_file);
			else if (sort == ML_SORT_DATE) array_setup_compare(list,(int (*)(void **, void **))message_sort_date);
			else if (sort == ML_SORT_SIZE) array_setup_compare(list,(int (*)(void **, void **))message_sort_size);
			else if (sort == ML_SORT_FROM) array_setup_compare(list,(int (*)(void **, void **))message_sort_from);
			else if (sort == ML_SORT_SUBJECT) array_setup_compare(list,(int (*)(void **, void **))message_sort_subject);
		}
		
		array_add(list,m);
	}
	wild_end(&h);

	array_sort(list);
	if (reverse) array_reverse(list);

	if (max) *max = count;

	return list;
}
