/*
 * MultiMail offline mail reader
 * address book

 Copyright (c) 1996 Kolossvary Tamas <thomas@vma.bme.hu>
 Copyright (c) 1999 William McBrine <wmcbrine@clark.net>

 Distributed under the GNU General Public License.
 For details, see the file COPYING in the parent directory. */

#include "interfac.h"

Person::Person(const char *sname, const char *saddr)
{
	if (saddr && (*saddr == 'I')) {
		netmail_addr.isInternet = true;
		saddr++;
	}
	netmail_addr = saddr;
	Init(sname);
}

Person::Person(const char *sname, net_address &naddr)
{
	netmail_addr = naddr;
	Init(sname);
}

void Person::Init(const char *sname)
{
	if (sname) {
		strncpy(name, sname, 44);
		name[44] = '\0';
	}
	next = 0;
}

void Person::dump(FILE *fd)
{
	fprintf(fd, (netmail_addr.isInternet ? "%s\nI%s\n\n" :
		"%s\n%s\n\n"), name, (const char *) netmail_addr);
}

AddressBook::AddressBook()
{
	NumOfPersons = 0;
}

AddressBook::~AddressBook()
{
	DestroyChain();
}

void AddressBook::MakeActive(bool NoEnterA)
{
	NoEnter = NoEnterA;

	list_max_y = LINES - 12;
	list_max_x = COLS - 6;

	int npos = list_max_x - 39;

	list = new InfoWin(LINES - 6, COLS - 4, 2, C_ADDR1, "Addressbook",
				C_ADDR2, 6);

	list->put(list_max_y + 3, 2, "Q");
	list->put(list_max_y + 3, npos - 3, "/, .");
	list->put(list_max_y + 4, 2, "K");

	statetype s = interface->prevactive();
	if (s != address)
		inletter = ((s == letter) || (s == littlearealist)) &&
			!mm.areaList->isReplyArea();

	if (inletter)
		list->put(list_max_y + 4, npos, "L");

	list->attrib(C_ADDR2);
	list->put(1, 2,
		"Name                            Netmail address");

	list->horizline(list_max_y + 2, list_max_x);

	list->put(list_max_y + 3, 3, ": Quit addressbook");
	list->put(list_max_y + 4, 3, ": Kill current address");
	list->put(list_max_y + 3, ++npos, ": search / next");

	if (inletter)
		list->put(list_max_y + 4, npos,
			  ": pick sender name address from Letter");

	DrawAll();
}

void AddressBook::Delete()
{
	delete list;
}

void AddressBook::extrakeys(int key)
{
	switch (key) {
	case MM_ENTER:
		if (!NoEnter)
			SetLetterThings();
		break;
	case MM_PLUS:
		Move(DOWN);
		Draw();
		break;
	case MM_MINUS:
		Move(UP);
		Draw();
		break;
	case 'K':
		if (highlighted)
			kill();
		break;
	case 'L':
		if (inletter)
			AddressFromLetter();
	}
}

void AddressBook::kill()
{
	if (interface->WarningWindow("Remove this address?")) {
		if (active)
			people[active - 1]->next = highlighted->next;
		else
			head.next = highlighted->next;

		if (position)
			position--;

		NumOfPersons--;

		delete highlighted;
		delete[] people;

		MakeChain();

		FILE *fd = fopen(addfname, "wt");
		for (int x = 0; x < NumOfPersons; x++)
			people[x]->dump(fd);
		fclose(fd);
	}
	Delete();
	MakeActive(NoEnter);
}

void AddressBook::SetLetterThings()
{
	if (highlighted)
		interface->letterwindow.set_Letter_Params(
			highlighted->netmail_addr, highlighted->name);
}

void AddressBook::AddressFromLetter()
{
	net_address Address = interface->letterwindow.PickNetAddr();

	if (Address.isSet) {
		const char *Name = mm.letterList->getFrom();
		bool found = false;

		// Dupe check; also positions curr at end of list:
		curr = &head;
		while (curr->next && !found) {
			curr = curr->next;
			found = (curr->netmail_addr == Address) &&
				!strcasecmp(curr->name, Name);
		}

		if (!found) {
			curr->next = new Person(Name, Address);

			FILE *fd = fopen(addfname, "at");
			curr->next->dump(fd);
			fclose(fd);

			NumOfPersons++;
			delete[] people;
			MakeChain();

			active = NumOfPersons;
			Draw();
		} else
			interface->nonFatalError("Already in addressbook");
	} else
		interface->nonFatalError("No address found");
}

void AddressBook::oneLine(int i)
{
	int z = position + i;
	curr = (z < NumOfPersons) ? people[z] : 0;

	if (z == active)
		highlighted = curr;

	char *tmp = list->lineBuf;
	int x = curr ? sprintf(tmp, " %-31s %s", curr->name,
		(const char *) curr->netmail_addr) : 0;
	for (; x < list_max_x; x++)
		tmp[x] = ' ';
	tmp[x] = '\0';

	DrawOne(i, C_ADDR3);
}

bool AddressBook::oneSearch(int x, const char *item)
{
	const char *s;
	if (!(s = searchstr(people[x]->name, item)))
		s = searchstr(people[x]->netmail_addr, item);
	return !(!s);
}

int AddressBook::NumOfItems()
{
	return NumOfPersons;
}

int perscomp(Person **a, Person **b)
{
	return strcasecmp((*a)->name, (*b)->name);
}

void AddressBook::ReadFile()
{
	FILE *fd;
	char name[256], nmaddr[256], other[256];
	bool end = false;

	if ((fd = fopen(addfname, "rt"))) {
		curr = &head;
		while (!end) {
			do
				end = !fgets(name, sizeof name, fd);
			while (name[0] == '\n' && !end);

			end = !fgets(nmaddr, sizeof nmaddr, fd);

			if (!end) {
				strtok(name, "\n");
				strtok(nmaddr, "\n");
				curr->next = new Person(name, nmaddr);
				curr = curr->next;
				NumOfPersons++;
			}

			do
				end = !fgets(other, sizeof other, fd);
			while (other[0] != '\n' && !end);
		}
		fclose(fd);
	}

	MakeChain();

	if (NumOfPersons > 1) {
		qsort(people, NumOfPersons, sizeof(Person *), perscomp);
		ReChain();
	}
}


void AddressBook::MakeChain()
{
	if (NumOfPersons) {
		people = new Person *[NumOfPersons];
		curr = head.next;
		int c = 0;
		while (curr) {
			people[c++] = curr;
			curr = curr->next;
		}
	} else
		people = 0;
}

void AddressBook::ReChain()
{
	head.next = people[0];
	for (int c = 0; c < (NumOfPersons - 1); c++)
		people[c]->next = people[c + 1];

	people[NumOfPersons - 1]->next = 0;
}

void AddressBook::DestroyChain()
{
	while (NumOfPersons)
		delete people[--NumOfPersons];
	delete[] people;
}

void AddressBook::Init()
{
	addfname = mm.resourceObject->get(AddressFile);
	ReadFile();
}
