//
//  QuranDatabase.m
//  QuranSearch
//
//  Created by Ahmed El-Helw on 10/21/10.
//  Copyright 2010 None. All rights reserved.
//

#import "Ayah.h"
#import "QuranDatabase.h"


@implementation QuranDatabase

- (void)initialize {
	NSString *path = [NSString stringWithFormat:@"%@/transliteration.db",
					  [[NSBundle mainBundle] resourcePath]];
	if (sqlite3_open([path UTF8String], &database) != SQLITE_OK){
		sqlite3_close(database);
		database = nil;
		NSAssert1(0, @"failed to open database with message '%s'.",
				  sqlite3_errmsg(database));
	}
}

- (NSArray*)autocomplete:(NSString *)query {
	NSArray* words = [query componentsSeparatedByString: @" "];

	int count = [words count];
	if (count == 1)
		return [self search:[words objectAtIndex: 0]]; 
	else if (count == 2)
		return [self search:[words objectAtIndex:0]
			 withSecondWord:[words objectAtIndex: 1]];
	else return [self search:[words objectAtIndex:(count-3)]
			  withSecondWord:[words objectAtIndex:(count-2)]
			   withThirdWord:[words objectAtIndex:(count-1)]];
}

- (NSArray*)search:(NSString *)query {
	static sqlite3_stmt *stmt;
	
	if (stmt == nil){
		const char* sql = "select word, matches from cache \
						  where word like ? limit 25";
		if (sqlite3_prepare_v2(database, sql, -1, &stmt, NULL) != SQLITE_OK)
			NSAssert1(0, @"failed to open prepare statement with message '%s'.",
					  sqlite3_errmsg(database));
	}
	
	NSString* qterm = [[NSString alloc] initWithFormat:@"%s%%",
					   [query UTF8String]];
	NSMutableArray* possibleResults = [[NSMutableArray alloc] init];
	sqlite3_bind_text(stmt, 1, [qterm UTF8String], -1, SQLITE_TRANSIENT);
	while (sqlite3_step(stmt) == SQLITE_ROW){
		NSString* matches = [NSString
				stringWithUTF8String:(char*)sqlite3_column_text(stmt, 1)];
		NSArray* verses = [matches componentsSeparatedByString: @","];
		[possibleResults addObject:verses];
	}
	sqlite3_reset(stmt);
	[qterm release];
	
	NSMutableArray* results = [self getResults:possibleResults];
	[possibleResults release];
	
	return [[[NSArray alloc] initWithArray: results] autorelease];
}

- (NSArray*)search:(NSString *)query withSecondWord:query2 {
	static sqlite3_stmt *stmt;
	
	if (stmt == nil){
		const char* sql = "select word, second_word, matches from \
						  cache_l2 where word=? and second_word like ?";
		if (sqlite3_prepare_v2(database, sql, -1, &stmt, NULL) != SQLITE_OK)
			NSAssert1(0, @"failed to open prepare statement with message '%s'.",
					  sqlite3_errmsg(database));
	}
	
	NSString* qterm = [[NSString alloc] initWithFormat:@"%s%%",
					   [query2 UTF8String]];
	NSMutableArray* possibleResults = [[NSMutableArray alloc] init];
	sqlite3_bind_text(stmt, 1, [query UTF8String], -1, SQLITE_TRANSIENT);
	sqlite3_bind_text(stmt, 2, [qterm UTF8String], -1, SQLITE_TRANSIENT);
	while (sqlite3_step(stmt) == SQLITE_ROW){
		NSString* matches = [NSString
					stringWithUTF8String:(char*)sqlite3_column_text(stmt, 2)];
		NSArray* verses = [matches componentsSeparatedByString: @","];
		[possibleResults addObject:verses];
	}
	sqlite3_reset(stmt);
	[qterm release];
	
	NSMutableArray* results = [self getResults:possibleResults];
	[possibleResults release];
	
	return [[[NSArray alloc] initWithArray: results] autorelease];
}

- (NSArray*)search:(NSString *)query withSecondWord:query2
									 withThirdWord:query3 {
	static sqlite3_stmt *stmt;
	
	if (stmt == nil){
		const char* sql = "select word, second_word, third_word, matches \
						   from cache_l3 where word=? and second_word=? and \
						   third_word like ?";
		if (sqlite3_prepare_v2(database, sql, -1, &stmt, NULL) != SQLITE_OK)
			NSAssert1(0, @"failed to open prepare statement with message '%s'.",
					  sqlite3_errmsg(database));
	}
	
	NSString* qterm = [[NSString alloc] initWithFormat:@"%s%%",
					   [query3 UTF8String]];
	NSMutableArray* possibleResults = [[NSMutableArray alloc] init];
	sqlite3_bind_text(stmt, 1, [query UTF8String], -1, SQLITE_TRANSIENT);
	sqlite3_bind_text(stmt, 2, [query2 UTF8String], -1, SQLITE_TRANSIENT);
	sqlite3_bind_text(stmt, 3, [qterm UTF8String], -1, SQLITE_TRANSIENT);

	while (sqlite3_step(stmt) == SQLITE_ROW){
		NSString* matches = [NSString
					stringWithUTF8String:(char*)sqlite3_column_text(stmt, 3)];
		NSArray* verses = [matches componentsSeparatedByString: @","];
		[possibleResults addObject:verses];
	}
	sqlite3_reset(stmt);
	[qterm release];
	
	NSMutableArray* results = [self getResults:possibleResults];
	[possibleResults release];
	
	return [[[NSArray alloc] initWithArray: results] autorelease];
}

- (NSMutableArray*) getResults: (NSMutableArray*) possibleResults {
	int index = 0;
	int added = 0;
	int total = 0;
	NSMutableString* elems = [[NSMutableString alloc] initWithString:@""];
	do {
		added = 0;
		for (int i=0; i<[possibleResults count]; i++) {
			if ([[possibleResults objectAtIndex:i] count] > index){
				if (added + total > 0) [elems appendString: @","];
				[elems appendString: [[possibleResults objectAtIndex:i]
									  objectAtIndex:index]];
				added++;
			}
		}
		total += added;
		index++;
	} while ((added > 0) && (total < 25));
	
	NSMutableArray* results = [self getVerses:elems];
	NSLog(@"about to return with count %d", [results count]);
	[elems release];
	return results;
}

- (NSMutableArray*)getVerses:(NSString *)verses {
	char* query;
	asprintf(&query, "select %s from transliteration where versenum in(%s)",
			 "versenum, suranum, ayahnum, ayahtext", [verses UTF8String]);
	
	sqlite3_stmt *statement;
	if (sqlite3_prepare_v2(database, query, -1, &statement, NULL) != SQLITE_OK)
		NSAssert1(0, @"failed to open prepare statement with message '%s'.",
				  sqlite3_errmsg(database));
	NSMutableArray* results = [[NSMutableArray alloc] init];
	
	while (sqlite3_step(statement) == SQLITE_ROW){
		Ayah* ayah = [Ayah alloc];
		ayah.vid = sqlite3_column_int(statement, 0);
		ayah.sura = sqlite3_column_int(statement, 1);
		ayah.ayah = sqlite3_column_int(statement, 2);
		ayah.translation = [NSString
				stringWithUTF8String:(char*)sqlite3_column_text(statement, 3)];
		[results addObject:[ayah autorelease]];
	}
	free(query);
	
	return [results autorelease];
}

- (void) close {
	if (database != nil){
		sqlite3_close(database);
		database = nil;
	}
}

@end
