//
//  PBRemoteProgressSheetController.m
//  GitX
//
//  Created by Nathan Kinsinger on 12/6/09.
//  Copyright 2009 Nathan Kinsinger. All rights reserved.
//

#import "PBRemoteProgressSheet.h"
#import "PBGitWindowController.h"
#import "PBGitRepository.h"
#import "PBGitBinary.h"
#import "PBEasyPipe.h"



NSString * const kGitXProgressDescription        = @"PBGitXProgressDescription";
NSString * const kGitXProgressSuccessDescription = @"PBGitXProgressSuccessDescription";
NSString * const kGitXProgressSuccessInfo        = @"PBGitXProgressSuccessInfo";
NSString * const kGitXProgressErrorDescription   = @"PBGitXProgressErrorDescription";
NSString * const kGitXProgressErrorInfo          = @"PBGitXProgressErrorInfo";



@interface PBRemoteProgressSheet ()

- (void) beginRemoteProgressSheetForArguments:(NSArray *)args title:(NSString *)theTitle description:(NSString *)theDescription inDir:(NSString *)dir windowController:(PBGitWindowController *)controller;
- (void) showSuccessMessage;
- (void) showErrorMessage;

- (NSString *) progressTitle;
- (NSString *) successTitle;
- (NSString *) successDescription;
- (NSString *) errorTitle;
- (NSString *) errorDescription;
- (NSString *) commandDescription;
- (NSString *) standardOutputDescription;
- (NSString *) standardErrorDescription;

@end



@implementation PBRemoteProgressSheet


@synthesize progressDescription;
@synthesize progressIndicator;



#pragma mark -
#pragma mark PBRemoteProgressSheet

+ (void) beginRemoteProgressSheetForArguments:(NSArray *)args title:(NSString *)theTitle description:(NSString *)theDescription inDir:(NSString *)dir windowController:(PBGitWindowController *)windowController
{
	PBRemoteProgressSheet *sheet = [[self alloc] initWithWindowNibName:@"PBRemoteProgressSheet"];
	[sheet beginRemoteProgressSheetForArguments:args title:theTitle description:theDescription inDir:dir windowController:windowController];
}


+ (void) beginRemoteProgressSheetForArguments:(NSArray *)args title:(NSString *)theTitle description:(NSString *)theDescription  inRepository:(PBGitRepository *)repo
{
	[PBRemoteProgressSheet beginRemoteProgressSheetForArguments:args title:theTitle description:theDescription inDir:[repo workingDirectory] windowController:repo.windowController];
}


- (void) beginRemoteProgressSheetForArguments:(NSArray *)args title:(NSString *)theTitle description:(NSString *)theDescription inDir:(NSString *)dir windowController:(PBGitWindowController *)windowController
{
	controller  = windowController;
	arguments   = args;
	title       = theTitle;
	description = theDescription;

	[self window]; // loads the window (if it wasn't already)
	[self.progressDescription setStringValue:[self progressTitle]];
	[self.progressIndicator startAnimation:nil];
	[NSApp beginSheet:[self window] modalForWindow:[controller window] modalDelegate:self didEndSelector:nil contextInfo:nil];

	gitTask = [PBEasyPipe taskForCommand:[PBGitBinary path] withArgs:arguments inDir:dir];
	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskCompleted:) name:NSTaskDidTerminateNotification object:gitTask];

	// having intermittent problem with long running git tasks not sending a termination notice, so periodically check whether the task is done
	taskTimer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(checkTask:) userInfo:nil repeats:YES];

	[gitTask launch];
}



#pragma mark Notifications

- (void) taskCompleted:(NSNotification *)notification
{
	[taskTimer invalidate];
	[[NSNotificationCenter defaultCenter] removeObserver:self];

	[self.progressIndicator stopAnimation:nil];
	[NSApp endSheet:[self window]];
	[[self window] orderOut:self];

	returnCode = [gitTask terminationStatus];
	if (returnCode)
		[self showErrorMessage];
	else
		[self showSuccessMessage];

	if ([controller respondsToSelector:@selector(repository)])
		[controller.repository reloadRefs];
}



#pragma mark taskTimer

- (void) checkTask:(NSTimer *)timer
{
	if (![gitTask isRunning]) {
		NSLog(@"[%@ %s] gitTask terminated without notification", [self class], _cmd);
		[self taskCompleted:nil];
	}
}



#pragma mark Messages

- (void) showSuccessMessage
{
	NSMutableString *info = [NSMutableString string];
	[info appendString:[self successDescription]];
	[info appendString:[self commandDescription]];
	[info appendString:[self standardOutputDescription]];

	[(PBGitWindowController *)controller showMessageSheet:[self successTitle] infoText:info];
}


- (void) showErrorMessage
{
	NSMutableString *info = [NSMutableString string];
	[info appendString:[self errorDescription]];
	[info appendString:[self commandDescription]];
	[info appendString:[self standardOutputDescription]];
	[info appendString:[self standardErrorDescription]];

	NSDictionary *errorUserInfo = [NSDictionary dictionaryWithObjectsAndKeys:
								   [self errorTitle], NSLocalizedDescriptionKey,
								   info, NSLocalizedRecoverySuggestionErrorKey,
								   nil];
	NSError *error = [NSError errorWithDomain:PBGitRepositoryErrorDomain code:0 userInfo:errorUserInfo];

	[(PBGitWindowController *)controller showErrorSheet:error];
}



#pragma mark Display Strings

- (NSString *) progressTitle
{
	NSString *progress = description;
	if (!progress)
		progress = @"Operation in progress.";

	return progress;
}


- (NSString *) successTitle
{
	NSString *success = title;
	if (!success)
		success = @"Operation";

	return [success stringByAppendingString:@" completed."];
}


- (NSString *) successDescription
{
	NSString *info = description;
	if (!info)
		return @"";

	return [info stringByAppendingString:@" completed successfully.\n\n"];
}


- (NSString *) errorTitle
{
	NSString *error = title;
	if (!error)
		error = @"Operation";

	return [error stringByAppendingString:@" failed."];
}


- (NSString *) errorDescription
{
	NSString *info = description;
	if (!info)
		return @"";

	return [info stringByAppendingString:@" encountered an error.\n\n"];
}


- (NSString *) commandDescription
{
	if (!arguments || ([arguments count] == 0))
		return @"";

	return [NSString stringWithFormat:@"command: git %@", [arguments componentsJoinedByString:@" "]];
}


- (NSString *) standardOutputDescription
{
	if (!gitTask || [gitTask isRunning])
		return @"";

	NSData *data = [[[gitTask standardOutput] fileHandleForReading] readDataToEndOfFile];
	NSString *standardOutput = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

	if ([standardOutput isEqualToString:@""])
		return @"";

	return [NSString stringWithFormat:@"\n\n%@", standardOutput];
}


- (NSString *) standardErrorDescription
{
	if (!gitTask || [gitTask isRunning])
		return @"";

	NSData *data = [[[gitTask standardError] fileHandleForReading] readDataToEndOfFile];
	NSString *standardError = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

	if ([standardError isEqualToString:@""])
		return [NSString stringWithFormat:@"\nerror = %d", returnCode];

	return [NSString stringWithFormat:@"\n\n%@\nerror = %d", standardError, returnCode];
}


@end
