//
//  BSDatabaseTranslator.m
//  BathyScaphe
//
//  Created by Hori,Masaki on 10/10/12.
//  Copyright 2010 masakih. All rights reserved.
//

#import "BSDatabaseTranslator.h"


#import "DatabaseManager.h"
#import "BSCoreDataManager.h"

#import "BSBoardInformationObject.h"
#import "BSThreadInformationObject.h"
#import "BSFavoriteObject.h"
#import "BSBoardHistoryObject.h"



@implementation BSDatabaseTranslator

static inline NSDate *dateFromData(id data)
{
	if(data == [NSNull null]) return nil;
	return [NSDate dateWithTimeIntervalSince1970:[data doubleValue]];
}
static inline NSNumber *numberFromData(id data)
{
	if(data == [NSNull null]) return nil;
	return [NSNumber numberWithDouble:[data doubleValue]];
}
static inline id nilIfNSNull(id obj)
{
	if([NSNull null] == obj) return nil;
	return obj;
}

+ (NSString *)localizableStringsTableName
{
	return NSStringFromClass([self class]);
}
- (void)setInformationText:(NSString *)anInformation
{
	information.stringValue = anInformation;
	[information display];
}

- (void)loadPanel
{
	
	[NSBundle loadNibNamed:@"DatabaseUpdatePanel" owner:self];
	
	[self setInformationText:@""];
	
	NSRect mainScreenFrame = [[NSScreen mainScreen] visibleFrame];
	NSPoint center = NSMakePoint(NSMidX(mainScreenFrame), NSMidY(mainScreenFrame));
	
	NSRect windowFrame = [window frame];
	NSPoint origin = NSMakePoint(center.x - windowFrame.size.width / 2, center.y - windowFrame.size.height / 2 + 100);
	[window setFrameOrigin:origin];
	
	[window makeKeyAndOrderFront:nil];
	[progress setUsesThreadedAnimation:YES];
	[progress startAnimation:nil];
}
- (void)dealloc
{
	[progress stopAnimation:nil];
	[window close];
	
	[super dealloc];
}

- (BOOL)hasCoreData
{
	BOOL hasCoreData = NO;
	
	BSCoreDataManager *coreDataManager = [BSCoreDataManager defaultManager];
	NSManagedObjectContext *context = coreDataManager.managedObjectContext;
	NSFetchRequest *fetch = [[[NSFetchRequest alloc] init] autorelease];
	NSEntityDescription *entity = [NSEntityDescription entityForName:BSCoreDataModelThreadInformationName
											  inManagedObjectContext:context];
	[fetch setEntity:entity];
	[fetch setFetchLimit:1];
	
	NSError *error = nil;
	NSArray *result = [context executeFetchRequest:fetch
											 error:&error];
	if(!result) {
		if(error) {
			NSLog(@"Can not execute request: %@", error);
		} else {
			NSLog(@"Can not execute request.");
		}
		NSBeep();
		exit(-4);
	}
	if(0 != [result count]) {
		hasCoreData = YES;
	}
	
	return hasCoreData;
}
- (void)translateBoard
{
	SQLiteDB *db = [[DatabaseManager defaultManager] databaseForCurrentThread];
	BSCoreDataManager *coreDataManager = [BSCoreDataManager defaultManager];
	NSManagedObjectContext *context = coreDataManager.managedObjectContext;
	
	id <SQLiteCursor> cursor = nil;
	NSString *query = nil;
	
	NSUInteger i, rowCount;
	
	// translate board
	if([db beginTransaction]) {
		
		query = [NSString stringWithFormat:
				 @"SELECT * FROM %@",
				 BoardInfoTableName];
		
		cursor = [db cursorForSQL:query];
		
		progress.maxValue = [cursor rowCount];
		
		for(i = 0, rowCount = [cursor rowCount]; i < rowCount; i++) {
			NSAutoreleasePool *pool01 = [[NSAutoreleasePool alloc] init];
			id <SQLiteRow> row = [cursor rowAtIndex:i];
			
			progress.doubleValue += 1;
			
			// dummyのデータを除去
			if([[row valueForColumn:BoardIDColumn] integerValue] == 0) continue;
			
			BSBoardInformationObject *obj = [NSEntityDescription insertNewObjectForEntityForName:BSCoreDataModelBoardInformationName
																		  inManagedObjectContext:context];
			obj.boardID = numberFromData([row valueForColumn:BoardIDColumn]);
			obj.boardName = [row valueForColumn:BoardNameColumn];
			obj.boardURL = [row valueForColumn:BoardURLColumn];
			
			// translate thread
			query = [NSString stringWithFormat:
					 @"SELECT * FROM %@ WHERE %@ = %@",
					 ThreadInfoTableName, BoardIDColumn, obj.boardID];
			id <SQLiteCursor> cursor02 = [db cursorForSQL:query];
			NSUInteger j, threadCount;
			for(j = 0, threadCount = [cursor02 rowCount]; j < threadCount; j++) {
				NSAutoreleasePool *pool02 = [[NSAutoreleasePool alloc] init];
				id <SQLiteRow> thread = [cursor02 rowAtIndex:j];
				
				BSThreadInformationObject *obj02 = [NSEntityDescription insertNewObjectForEntityForName:BSCoreDataModelThreadInformationName
																				 inManagedObjectContext:context];
				obj02.board = obj;
				obj02.threadID = [thread valueForColumn:ThreadIDColumn];
				obj02.threadName = [thread valueForColumn:ThreadNameColumn];
				obj02.numberOfAll = numberFromData([thread valueForColumn:NumberOfAllColumn]);
				obj02.numberOfRead = numberFromData([thread valueForColumn:NumberOfReadColumn]);
				obj02.modifiedDate = dateFromData([thread valueForColumn:ModifiedDateColumn]);
				obj02.threadStatus = numberFromData([thread valueForColumn:ThreadStatusColumn]);
				obj02.threadLabel = numberFromData([thread valueForColumn:ThreadLabelColumn]);
				obj02.lastWrittenDate = dateFromData([thread valueForColumn:LastWrittenDateColumn]);
				obj02.isDatOchi = numberFromData([thread valueForColumn:IsDatOchiColumn]);
								
				[pool02 release];
			}
			
			[pool01 release];
		}
		[db commitTransaction];
	} else {
		NSLog(@"Can not begin transaction for translate board");
		NSBeep();
		exit(-3);
	}
}
- (void)translateFavorite
{
	SQLiteDB *db = [[DatabaseManager defaultManager] databaseForCurrentThread];
	BSCoreDataManager *coreDataManager = [BSCoreDataManager defaultManager];
	NSManagedObjectContext *context = coreDataManager.managedObjectContext;
	
	id <SQLiteCursor> cursor = nil;
	NSString *query = nil;
	
	NSUInteger i, rowCount;
	
	if([db beginTransaction]) {
		query = [NSString stringWithFormat:
				 @"SELECT * FROM %@",
				 FavoritesTableName];
		
		NSPredicate *predicateFormat = [NSPredicate predicateWithFormat:
										@"%K = $THREAD_ID AND %K = $BOARD_ID",
										@"threadID",
										@"board.boardID"];
		
		cursor = [db cursorForSQL:query];
		progress.maxValue = [cursor rowCount];
		
		for(i = 0, rowCount = [cursor rowCount]; i < rowCount; i++) {
			NSAutoreleasePool *pool01 = [[NSAutoreleasePool alloc] init];
			progress.doubleValue += 1;
			
			id <SQLiteRow> row = [cursor rowAtIndex:i];
			
			NSPredicate *predicate = [predicateFormat predicateWithSubstitutionVariables:
									  [NSDictionary dictionaryWithObjectsAndKeys:
									   [row valueForColumn:ThreadIDColumn], @"THREAD_ID",
									   numberFromData([row valueForColumn:BoardIDColumn]), @"BOARD_ID",
									   nil]];
			NSArray *result = nil;
			@try {
				result = [coreDataManager fetchDataForEntityName:BSCoreDataModelThreadInformationName
													   predicate:predicate];
			}
			@catch (id ex) {
				@throw;
			}
			if(0 == [result count]) {
				NSLog(@"Can not find target thread object.");
				continue;
			}
			
			BSFavoriteObject *obj = [NSEntityDescription insertNewObjectForEntityForName:BSCoreDataModelFavoriteName
																  inManagedObjectContext:context];
			obj.thread = [result lastObject];
			obj.index = [NSNumber numberWithInteger:(i + 1) * 100];
			
			[pool01 release];
		}
		
		[db commitTransaction];
	} else {
		NSLog(@"Can not begin transaction for translate favorite");
		NSBeep();
		exit(-3);
	}
}
- (void)translateBoardHistory
{
	SQLiteDB *db = [[DatabaseManager defaultManager] databaseForCurrentThread];
	BSCoreDataManager *coreDataManager = [BSCoreDataManager defaultManager];
	NSManagedObjectContext *context = coreDataManager.managedObjectContext;
	
	id <SQLiteCursor> cursor = nil;
	NSString *query = nil;
	
	NSUInteger i, rowCount;
	
	if([db beginTransaction]) {
		
		query = [NSString stringWithFormat:
				 @"SELECT * FROM %@",
				 BoardInfoHistoryTableName];
		
		NSPredicate *predicateFormat = [NSPredicate predicateWithFormat:
										@"%K = $BOARD_ID",
										@"boardID"];
		
		cursor = [db cursorForSQL:query];
		progress.maxValue = [cursor rowCount];
		
		for(i = 0, rowCount = [cursor rowCount]; i < rowCount; i++) {
			NSAutoreleasePool *pool01 = [[NSAutoreleasePool alloc] init];
			
			progress.doubleValue += 1;
			
			id <SQLiteRow> row = [cursor rowAtIndex:i];
			
			NSPredicate *predicate = [predicateFormat predicateWithSubstitutionVariables:
									  [NSDictionary dictionaryWithObjectsAndKeys:
									   numberFromData([row valueForColumn:BoardIDColumn]), @"BOARD_ID",
									   nil]];
			NSArray *result = nil;
			@try {
				result = [coreDataManager fetchDataForEntityName:BSCoreDataModelBoardInformationName
													   predicate:predicate];
			}
			@catch (id ex) {
				@throw;
			}
			if(0 == [result count]) {
				NSLog(@"Can not find target board object.");
				continue;
			}
			
			BSBoardHistoryObject *obj = [NSEntityDescription insertNewObjectForEntityForName:BSCoreDataModelBoardHistoryName
																	  inManagedObjectContext:context];
			obj.board = [result lastObject];
			obj.boardURL = nilIfNSNull([row valueForColumn:BoardURLColumn]);
			obj.boardName = nilIfNSNull([row valueForColumn:BoardNameColumn]);
			
			[pool01 release];
		}
		[db commitTransaction];
	} else {
		NSLog(@"Can not begin transaction for translate board");
		NSBeep();
		exit(-3);
	}
}
- (void)translate
{
	NSDate *date01 = [NSDate dateWithTimeIntervalSinceNow:0.0];
	
	if([self hasCoreData]) return;
	
	[self loadPanel];
	
//	[self setInformationText:[self localizedString:@"translate board."]];
	progress.doubleValue = 0;
	[progress setIndeterminate:NO];
	[progress display];
	[self translateBoard];
	
//	[self setInformationText:[self localizedString:@"translate favorites."]];
	progress.doubleValue = 0;
	[progress display];
	[self translateFavorite];
	
//	[self setInformationText:[self localizedString:@"translate board history."]];
	progress.doubleValue = 0;
	[progress display];
	[self translateBoardHistory];
	
//	[self setInformationText:[self localizedString:@"finalize database"]];
	[progress setIndeterminate:YES];
	[progress startAnimation:nil];
	
	[[BSCoreDataManager defaultManager] saveAction:nil];
	
	NSDate *date02 = [NSDate dateWithTimeIntervalSinceNow:0.0];
	
	NSLog(@"Translate time -> %.3f", [date02 timeIntervalSinceDate:date01]);
}
@end
