/*
dbRW
Copyright (c) 2005-2009 Robert Rainwater

This program 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.

This program 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
#include "dbrw.h"

static CRITICAL_SECTION csContactsDb;
static SortedList sContactList;

static int contacts_compare(void* p1, void* p2);

enum {
	SQL_CTC_STMT_DELETE=0,
	SQL_CTC_STMT_ADD,
	SQL_CTC_STMT_NUM
};
static char *ctc_stmts[SQL_CTC_STMT_NUM] = {
	"DELETE FROM dbrw_contacts WHERE id = ?;",
	"INSERT INTO dbrw_contacts VALUES(NULL,?);"
};
static sqlite3_stmt *ctc_stmts_prep[SQL_CTC_STMT_NUM] = {0};

void contacts_init() {
	InitializeCriticalSection(&csContactsDb);
	ZeroMemory(&sContactList, sizeof(sContactList));
	sContactList.increment = 50;
	sContactList.sortFunc = contacts_compare;
	sql_prepare_add(ctc_stmts, ctc_stmts_prep, SQL_CTC_STMT_NUM);
	{
		sqlite3_stmt *st = NULL;
		int id, idx;

		if (sql_prepare(g_sqlite, "SELECT * FROM dbrw_contacts;", &st)!=SQLITE_OK) {
			return;
		}
		while (sql_step(st)==SQLITE_ROW) {
			id = (int)sqlite3_column_int(st, 0);
			if(!li.List_GetIndex(&sContactList, (void*)id, &idx)) {
				li.List_Insert(&sContactList, (void*)id, idx);
			}
		}
		sql_finalize(st);
	}
}

void contacts_destroy() {
	li.List_Destroy(&sContactList);
	DeleteCriticalSection(&csContactsDb);
}

static int contacts_compare(void* p1, void* p2) {
	return (int)p1-(int)p2;
}

static int contacts_isRealContact(int id) {
	int idx;

	if(li.List_GetIndex(&sContactList, (void*)id, &idx))
		return 1;
	log1("Invalid contact id requested (%d)", id);
	return 0;
}

INT_PTR contacts_getCount(WPARAM wParam, LPARAM lParam) {
	int rc;

	EnterCriticalSection(&csContactsDb);
	rc = sContactList.realCount;
	LeaveCriticalSection(&csContactsDb);
	return rc;
}

INT_PTR contacts_findFirst(WPARAM wParam, LPARAM lParam) {
	int rc;

	EnterCriticalSection(&csContactsDb);
	if (sContactList.realCount==0) {
		LeaveCriticalSection(&csContactsDb);
		return 0;
	}
	rc = (int)sContactList.items[0];
	LeaveCriticalSection(&csContactsDb);
	return rc;
}

INT_PTR contacts_findNext(WPARAM wParam, LPARAM lParam) {
	int id = (int)wParam;
	int rc, idx;

	EnterCriticalSection(&csContactsDb);
	if (sContactList.realCount==0) {
		LeaveCriticalSection(&csContactsDb);
		return 0;
	}
	if(!li.List_GetIndex(&sContactList, (void*)id, &idx)) {
		LeaveCriticalSection(&csContactsDb);
		return 0;
	}
	if (idx>=(sContactList.realCount-1)) {
		LeaveCriticalSection(&csContactsDb);
		return 0;
	}
	rc = (int)sContactList.items[idx+1];
	LeaveCriticalSection(&csContactsDb);
	return rc;
}

INT_PTR contacts_delete(WPARAM wParam, LPARAM lParam) {
	int id = (int)wParam;
	int rc = 0;
	
	EnterCriticalSection(&csContactsDb);
	if (!contacts_isRealContact(id)) {
		rc = 1;
	}
	else {
		int idx;
		
        LeaveCriticalSection(&csContactsDb);
		NotifyEventHooks(hContactDeletedEvent, wParam, 0);
        EnterCriticalSection(&csContactsDb);
		li.List_GetIndex(&sContactList, (void*)id, &idx);
		li.List_Remove(&sContactList, idx);
		
        // Begin Transaction
        sql_stmt_begin();
        
		// Delete contact
		sqlite3_bind_int(ctc_stmts_prep[SQL_CTC_STMT_DELETE], 1, id);
		sql_step(ctc_stmts_prep[SQL_CTC_STMT_DELETE]);
		sql_reset(ctc_stmts_prep[SQL_CTC_STMT_DELETE]);
        
		// Delete contact's settings
		settings_deleteContactData((HANDLE)id);

		// Delete contact's events
        events_deleteContactData((HANDLE)id);
        
        // Commit transaction
        sql_stmt_end();
        log1("Deleted contact (%d) and associated data", id);
	}
	LeaveCriticalSection(&csContactsDb);
	return rc;
}

INT_PTR contacts_add(WPARAM wParam, LPARAM lParam) {
	int id = 0;
	int idx;

	EnterCriticalSection(&csContactsDb);
	sqlite3_bind_int(ctc_stmts_prep[SQL_CTC_STMT_ADD], 1, time(NULL));
	if (sql_step(ctc_stmts_prep[SQL_CTC_STMT_ADD])==SQLITE_DONE) {
		id = (int)sqlite3_last_insert_rowid(g_sqlite);
		if (!li.List_GetIndex(&sContactList, (void*)id, &idx))
			li.List_Insert(&sContactList, (void*)id, idx);
	}
	sql_reset(ctc_stmts_prep[SQL_CTC_STMT_ADD]);
	LeaveCriticalSection(&csContactsDb);
	if (id)
		NotifyEventHooks(hContactAddedEvent, (WPARAM)id, 0);
    else 
        log0("Error creating contact");
	return id;
}

INT_PTR contacts_isContact(WPARAM wParam, LPARAM lParam) {
	int id = (int)wParam;
	int rc = 0;

	EnterCriticalSection(&csContactsDb);
	if (contacts_isRealContact(id))
		rc = 1;
	LeaveCriticalSection(&csContactsDb);
	return rc;
}