//
//  KMLinkHanlder.m
//  BathyScaphe
//
//  Created by 堀 昌樹 on 12/07/02.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#import "KMLinkHanlder.h"


#import "KMBSLogViewController.h"
#import <SGAppKit/NSWorkspace-SGExtensions.h>


#import "AppDefaults.h"
#import "SGDownloadLinkCommand.h"
#import "CMRHostHandler.h"
#import "CMRThreadLinkProcessor.h"
#import "CMRDocumentFileManager.h"


#define kBeProfileLinkTemplateKey	@"System - be2ch Profile URL"


@implementation KMLinkHanlder
@synthesize logViewController = _logViewController;


- (void)openMessagesWithIndexes:(NSIndexSet *)indexes
{
	if (!indexes || [indexes count] == 0) {
        return;
    }
	
    NSURL *boardURL = self.logViewController.doc.boardURL;
    CMRHostHandler *handler = [CMRHostHandler hostHandlerForURL:self.logViewController.doc.boardURL];
	NSURL *url = [handler readURLWithBoard:boardURL
								   datName:self.logViewController.doc.datIdentifier
									 start:[indexes firstIndex]+1
									   end:[indexes lastIndex]+1
								   nofirst:YES];
	
    if (url) {
        [[NSWorkspace sharedWorkspace] openURL:url inBackground:[CMRPref openInBg]];
	}
}

#pragma mark Previewing (or Downloading) Link
static inline NSString *urlPathExtension(NSURL *url)
{
	CFStringRef extensionRef = CFURLCopyPathExtension((CFURLRef)url);
	if (!extensionRef) {
		return nil;
	}
	NSString *extension = [(NSString *)extensionRef lowercaseString];
	CFRelease(extensionRef);
	return extension;
}

- (NSDictionary *)refererThreadInfoForLinkDownloader
{
    return [NSDictionary dictionaryWithObjectsAndKeys:self.logViewController.doc.threadTitle, kRefererTitleKey, [self.logViewController.doc.threadURL absoluteString], kRefererURLKey, NULL];
}

- (BOOL)previewOrDownloadURL:(NSURL *)url
{
    if (!url || [[url scheme] isEqualToString:@"mailto"]) {
        return NO;
    }
	
	NSArray		*extensions = [CMRPref linkDownloaderExtensionTypes];
	NSString	*linkExtension = urlPathExtension(url);
	
	if (linkExtension && [extensions containsObject:linkExtension]) {
		SGDownloadLinkCommand *dlCmd = [SGDownloadLinkCommand functorWithObject:[url absoluteString]];
		[dlCmd setRefererThreadInfo:[self refererThreadInfoForLinkDownloader]];
		[dlCmd execute:self];
		return YES;
	}
	
	
    id<BSLinkPreviewing> previewer = [CMRPref sharedLinkPreviewer];
    if (previewer) {
        return [previewer validateLink:url] ? [previewer previewLink:url] : NO;
    } else {
        id<BSImagePreviewerProtocol> oldPreviewer = [CMRPref sharedImagePreviewer];
        if (oldPreviewer) {
            return [oldPreviewer validateLink:url] ? [oldPreviewer showImageWithURL:url] : NO;
        }
    }
    return NO;
}

- (void)openURLsWithAppStore:(NSArray *)array
{
    [[NSWorkspace sharedWorkspace] openURLs:array
                    withAppBundleIdentifier:@"com.apple.appstore"
                                    options:NSWorkspaceLaunchDefault
             additionalEventParamDescriptor:nil
                          launchIdentifiers:NULL];
}

- (BOOL)handleExternalLink:(id)aLink forView:(NSView *)aView
{
	BOOL			shouldPreviewWithNoModifierKey = [CMRPref previewLinkWithNoModifierKey];
	BOOL			isOptionKeyPressed;
	BOOL			isFileURL;
	NSURL			*url = [NSURL URLWithLink:aLink];
	NSEvent			*theEvent;
	
	if(!url) return NO;
	
	theEvent = [[aView window] currentEvent];
	UTILAssertNotNil(theEvent);
	
	isOptionKeyPressed = (([theEvent modifierFlags] & NSAlternateKeyMask) == NSAlternateKeyMask);
	isFileURL = [url isFileURL];
	
    if ([CMRPref convertsHttpToItmsIfNeeded] && [[url host] isEqualToString:@"itunes.apple.com"]) {
        NSMutableString *tmp = [[url absoluteString] mutableCopy];
        if ([tmp hasSuffix:@"?mt=12"]) { // Mac App Store URL ?
            [tmp replaceCharactersInRange:NSMakeRange(0,4) withString:@"macappstore"];
            NSURL *newURL2 = [NSURL URLWithString:tmp];
            [tmp release];
			
            // App Store.app が既に起動しているかどうか？
            NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
            id hoge = [apps valueForKey:@"NSApplicationBundleIdentifier"];
            if ([hoge containsObject:@"com.apple.appstore"]) {
                // 既に起動しているなら直ちに開かせる
                [self openURLsWithAppStore:[NSArray arrayWithObject:newURL2]];
                return YES;
            } else {
                // App Store.app の起動を試みる
                BOOL launched = [[NSWorkspace sharedWorkspace] launchAppWithBundleIdentifier:@"com.apple.appstore"
                                                                                     options:NSWorkspaceLaunchWithoutActivation
                                                              additionalEventParamDescriptor:nil
                                                                            launchIdentifier:NULL];
                if (launched) {
                    // 起動できたら、遅延実行で当該アプリのページを開かせる（遅延させないとうまくいかない）
                    NSAlert *alert = [[[NSAlert alloc] init] autorelease];
                    [alert setAlertStyle:NSInformationalAlertStyle];
                    [alert setMessageText:[self localizedString:@"App Store Waiting Msg"]];
                    [alert setInformativeText:[self localizedString:@"App Store Waiting Info"]];
                    [alert addButtonWithTitle:[self localizedString:@"App Store Continue"]];
                    [alert addButtonWithTitle:[self localizedString:@"App Store Cancel"]];
                    if ([alert runModal] == NSAlertFirstButtonReturn) {
                        [self openURLsWithAppStore:[NSArray arrayWithObject:newURL2]];
                    }
                    return YES;
                } else {
                    // App Store.app が存在しない環境か、他の何らかの理由で起動に失敗。URL を通常通り Web ブラウザで開かせる。
                    return [[NSWorkspace sharedWorkspace] openURL:url inBackground:[CMRPref openInBg]];
                }
            }
        } else {
            [tmp replaceCharactersInRange:NSMakeRange(0,4) withString:@"itms"];
            NSURL *newURL = [NSURL URLWithString:tmp];
            [tmp release];
            [[NSWorkspace sharedWorkspace] openURLs:[NSArray arrayWithObject:newURL]
							withAppBundleIdentifier:@"com.apple.iTunes"
											options:NSWorkspaceLaunchDefault
					 additionalEventParamDescriptor:nil launchIdentifiers:NULL];
            return YES;
        }
    }
	
	if (shouldPreviewWithNoModifierKey) {
		if (!isOptionKeyPressed && !isFileURL) {
			if ([self previewOrDownloadURL:url]) return YES;
		}
	} else {
		if (isOptionKeyPressed && !isFileURL) {
			if ([self previewOrDownloadURL:url]) return YES;
		}
	}
	return [[NSWorkspace sharedWorkspace] openURL:url inBackground:[CMRPref openInBg]];
}

- (NSIndexSet *)isStandardMessageLink:(id)aLink
{
	NSURL			*link_;
	CMRHostHandler	*handler_;
	NSString		*bbs_;
	NSString		*key_;
	
	NSUInteger	stIndex_;
	NSUInteger	endIndex_;
	NSRange			moveRange_;
	
	link_ = [NSURL URLWithLink:aLink];
	handler_ = [CMRHostHandler hostHandlerForURL:link_];
	if (!handler_) return nil;
	
	if (![handler_ parseParametersWithReadURL:link_
										  bbs:&bbs_
										  key:&key_
										start:&stIndex_
										   to:&endIndex_
									showFirst:NULL]) {
		return nil;
	}
	
	if (NSNotFound != stIndex_) {
		moveRange_.location = stIndex_ -1;
		moveRange_.length = (endIndex_ - stIndex_) +1;
	} else {
		return nil;		
	}
	
	// 同じ掲示板の同じスレッドならメッセージ移動処理
	if ([self.logViewController.doc.bbsIdentifier isEqualToString:bbs_] && [self.logViewController.doc.datIdentifier isEqualToString:key_]) {
		return [NSIndexSet indexSetWithIndexesInRange:moveRange_];
	}
	
	return nil;
}

- (BOOL)isMessageLink:(id)aLink messageIndexes:(NSIndexSet **)indexesPtr
{
	NSIndexSet		*indexes;
	if (!aLink) return NO;
	
	if ([CMRThreadLinkProcessor isMessageLinkUsingLocalScheme:aLink messageIndexes:indexesPtr]) {
		return YES;
	} else if ((indexes = [self isStandardMessageLink:aLink])) {
		if (indexesPtr != NULL) *indexesPtr = indexes;
		return YES;
	}
	
	return NO;
}

- (BOOL)clickedOnLink:(id)aLink
{
	NSString		*boardName_;
	NSURL			*boardURL_;
	NSString		*filepath_;
    NSString *host_;
	NSString		*beParam_;
	NSIndexSet		*indexes;
	
	// 同じスレッドのレスへのアンカー
    if ([self isMessageLink:aLink messageIndexes:&indexes]) {
		NSInteger action = [CMRPref threadViewerLinkType];
		if ([indexes firstIndex] != NSNotFound) {
			switch (action) {
				case ThreadViewerMoveToIndexLinkType:
					[self.logViewController scrollMessageAtIndex:[indexes firstIndex]];
					break;
				case ThreadViewerOpenBrowserLinkType:
					[self openMessagesWithIndexes:indexes];
					break;
				case ThreadViewerResPopUpLinkType:
					break;
				default:
					break;
            }
        }
        
        return YES;
	}
	
	// be Profile
	if ([CMRThreadLinkProcessor isBeProfileLinkUsingLocalScheme:aLink linkParam:&beParam_]) {
		NSString	*template_ = SGTemplateResource(kBeProfileLinkTemplateKey);
		NSString	*thURL_ = [self.logViewController.doc.threadURL absoluteString];
		// #warning 64BIT: Check formatting arguments
		// 2010-03-28 tsawada2 検証済
		NSString	*tmpURL_ = [NSString stringWithFormat:template_, beParam_, thURL_];
		
		NSURL	*accessURL_ = [NSURL URLWithString:tmpURL_];
		
		return [[NSWorkspace sharedWorkspace] openURL:accessURL_ inBackground:[CMRPref openInBg]];
	}
	
	// 2ch thread
	if ([CMRThreadLinkProcessor parseThreadLink:aLink boardName:&boardName_ boardURL:&boardURL_ filepath:&filepath_ parsedHost:&host_]) {
		CMRDocumentFileManager	*dm;
		NSDictionary			*contentInfo_;
		NSString				*datIdentifier_;
		
		dm = [CMRDocumentFileManager defaultManager];
		datIdentifier_ = [dm datIdentifierWithLogPath:filepath_];
		contentInfo_ = [NSDictionary dictionaryWithObjectsAndKeys:
						[boardURL_ absoluteString], BoardPlistURLKey,
						boardName_, ThreadPlistBoardNameKey,
						datIdentifier_, ThreadPlistIdentifierKey,
						host_, @"candidateHost",
						nil];
		
		[dm ensureDirectoryExistsWithBoardName:boardName_];
		//		return [[CMRDocumentController sharedDocumentController] showDocumentWithContentOfFile:[NSURL fileURLWithPath:filepath_] boardInfo:contentInfo_];
		NSError *error = nil;
		KMDocument *document = [[NSDocumentController sharedDocumentController] openDocumentWithContentsOfURL:[NSURL fileURLWithPath:filepath_]
																									  display:NO
																										error:&error];
		if(!document) {
			NSLog(@"2ch Link open Error.\n%@", error);
			return NO;
		}
#warning THIS IS TEST IMPLEMENTATION
		NSLog(@"########   THIS IS TEST IMPLEMENTATION.   #######");
		[document addWindowController:self.logViewController.view.window.windowController];
		[document showWindows];
		
		return YES;
	}
	
	// 2ch (or other) BBS
	if ([CMRThreadLinkProcessor parseBoardLink:aLink boardName:&boardName_ boardURL:&boardURL_]) {
		[[NSApp delegate] showThreadsListForBoard:boardName_ selectThread:nil addToListIfNeeded:YES];
		return YES;
	}
	
	// 外部リンクと判断
	return [self handleExternalLink:aLink forView:self.logViewController.documentView];
}
@end
