The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
//
//  FPAppWindow.m
//  Fuse-PDF-App
//
//  Created by Chris Dolan on 11/29/07.
//  Copyright 2007, All rights reserved.
//

#import "AppDelegate.h"
#import "BundledTask.h"
#import "FPAppWindow.h"

@interface NSAttributedString (Hyperlink)
+(id)hyperlinkFromString:(NSString*)inString withURL:(NSURL*)aURL;
@end

@implementation NSAttributedString (Hyperlink)
+(id)hyperlinkFromString:(NSString*)inString withURL:(NSURL*)aURL
{
   NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString: inString];
   NSRange range = NSMakeRange(0, [attrString length]);
   
   [attrString beginEditing];
   [attrString addAttribute:NSLinkAttributeName value:[aURL absoluteString] range:range];
   
   // make the text appear in blue
   [attrString addAttribute:NSForegroundColorAttributeName value:[NSColor blueColor] range:range];
   
   // next make the text appear with an underline
   [attrString addAttribute:
            NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:NSSingleUnderlineStyle] range:range];
   
   [attrString endEditing];
   
   return [attrString autorelease];
}
@end

@implementation FPAppWindow

static FPAppWindow *sharedController = nil;

+ (id)sharedController {
   if (!sharedController)
      sharedController = [[FPAppWindow allocWithZone:nil] init];
   [sharedController showWindow:nil];
   return sharedController;
}

- (id)init {
   self = [self initWithWindowNibName:@"FPAppWindow"];
   return self;
}

- (void)windowDidLoad {
   printf("window loaded\n");
   [[self window] setExcludedFromWindowsMenu:YES];
   [[NSApplication sharedApplication] removeWindowsItem:[self window]];
   [super windowDidLoad];
   [self setup];
   
}

-(void) parseVersion: (NSString*)result {
   //printf("result: %s\n", result ? [result UTF8String] : [@"nil" UTF8String]);
   if (result) {
      NSRange versionLoc = [result rangeOfString:@"version "];
      if (NSNotFound != versionLoc.location) {
         NSRange near = {versionLoc.location - 10, versionLoc.length + 50};
         printf("found version near '%s'\n", [[result substringWithRange: near] UTF8String]);
         NSRange spaceSearch = {versionLoc.location + versionLoc.length, 100};
         printf("looking for space at %d+%d\n", spaceSearch.location, spaceSearch.length);
         if (spaceSearch.location >= [result length]) {
            printf("end of string\n");
            return;
         }
         NSRange nextSpace = [result rangeOfString:@"\n" options:0 range:spaceSearch];
         if (NSNotFound != nextSpace.location) {
            NSRange numberLoc = {spaceSearch.location, nextSpace.location - spaceSearch.location};
            [fuseVersion release];
            fuseVersion = [result substringWithRange:numberLoc];
            [fuseVersion retain];
            printf("number version = %s\n", [fuseVersion UTF8String]);
            [fuseStatus setObjectValue:[@"present, v" stringByAppendingString:fuseVersion]];
            return;
         } else {printf("missing space\n");}
      } else {printf("missing versionloc\n");}
   } else {printf("nil result\n");}
}

-(void)getFuseVersion {
   Callback *callback = [Callback create:self method:@selector(parseVersion:)];
   NSArray *cmd = [NSArray arrayWithObjects:@"/System/Library/Filesystems/fusefs.fs/Support/mount_fusefs", @"-v", nil];
   [BundledTask run:cmd callback:callback];
}

-(void)parseArch:(NSString*)arch {
   NSRange r = [arch rangeOfString:@"\n"];
   if (NSNotFound != r.location) {
      NSRange begin = {0, r.location};
      arch = [arch substringWithRange:begin];
   }
   printf("arch: %s\n", [arch UTF8String]);
   archext = [[@"." stringByAppendingString:arch] retain];
}
-(void)getPerlArch {
   Callback *callback = [Callback create:self method:@selector(parseArch:)];
   //NSArray *cmd = [NSArray arrayWithObjects:@"/usr/bin/perl", @"-e", @"use Config; print @Config{myarchname}", nil];
   NSArray *cmd = [NSArray arrayWithObject:@"/usr/bin/arch"];
   [BundledTask run:cmd callback:callback];
}

-(void)setup {
   [self getPerlArch];

   [unmountButton setEnabled:NO];

   //NSString *urlStr = [fuseLink stringValue];
   NSString *urlStr = @"http://code.google.com/p/macfuse";
   // both are needed, otherwise hyperlink won't accept mousedown
   [fuseLink setAllowsEditingTextAttributes: YES];
   [fuseLink setSelectable: YES];
   NSURL* url = [NSURL URLWithString:urlStr];
   NSMutableAttributedString* string = [[NSMutableAttributedString alloc] init];
   [string appendAttributedString: [NSAttributedString hyperlinkFromString:urlStr withURL:url]];
   // set the attributed string to the NSTextField
   [fuseLink setAttributedStringValue: string];
   
   [dropWell registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
   [dropWell setCallback:[Callback create:self method:@selector(doMount:)]];
   
   pdfListSource = [[PDFList alloc] init];
   [pdfList setDataSource:pdfListSource];

   [self getFuseVersion];
}

-(NSString *)createMountPathForFile:(NSString *)path {
   NSString *filename = [path lastPathComponent];
   NSString *root = [@"/Volumes/" stringByAppendingString:filename];
   NSFileManager *mgr = [NSFileManager defaultManager];
   NSString *mountPath = root;
   root = [root stringByAppendingString:@"-"];
   int i = 0;
   while ([mgr fileExistsAtPath:mountPath]) {
      mountPath = [root stringByAppendingString:[NSString stringWithFormat:@"%d", ++i]];
   }
   [mgr createDirectoryAtPath:mountPath attributes:nil];
   return mountPath;
}

-(void)mountCallback:(NSString *)output fromTask:(BundledTask *)task {
   if (output)
      printf("%s\n", [output UTF8String]);
   printf("unmount\n");
   [task release];
}

-(void)doMount:(NSString*)path {
   printf("mount %s\n", [path UTF8String]);
   NSMutableArray *array = [pdfListSource array];
   NSString *mountPath = [self createMountPathForFile:path];
   @try {
      NSArray *cmd = [NSArray arrayWithObjects:[@"mount_pdf" stringByAppendingString:archext], path, mountPath, nil];
      BundledTask *t = [[BundledTask alloc] initWithCmd:cmd];
	  [t setVerbose:YES];
      Callback *callback = [Callback create:self method:@selector(mountCallback:fromTask:) data:t];
      [t start:callback];
      [array addObject:mountPath];
      [array addObject:path];
      [unmountButton setEnabled:YES];
      [pdfList reloadData];
   }
   @catch (NSException *e) {
      [[NSAlert alertWithMessageText:@"PDF mount failed" defaultButton:nil alternateButton:nil otherButton:nil
          informativeTextWithFormat:@"Failed to mount PDF file %@ at %@: %@", path, mountPath, e] runModal];
      [[NSFileManager defaultManager] removeFileAtPath:mountPath handler:nil];
   }
}

-(IBAction)mountPDF:(id)sender {
   printf("mountPDF\n");
   NSOpenPanel *open = [NSOpenPanel openPanel];
   [open setCanChooseFiles:YES];
   [open setCanChooseDirectories:NO];
   [open setAllowsMultipleSelection:NO];
   [open setResolvesAliases:YES];
   if (NSOKButton == [open runModalForTypes:[NSArray arrayWithObject:@"pdf"]]) {
      NSString *path = [open filename];
      [self doMount:path];
   }
}
-(IBAction)unmountPDF:(id)sender {
   printf("unmountPDF\n");
   NSIndexSet *indexSet = [pdfList selectedRowIndexes];
   NSMutableArray *array = [pdfListSource array];
   int i;
   for (i=[array count] - 2; i>=0; i -= 2) {
      if ([indexSet containsIndex:i/2]) {
         NSString *mountPath = [array objectAtIndex:i];
         NSString *path = [array objectAtIndex:i+1];
         @try {
            NSArray *cmd = [NSArray arrayWithObjects: @"/sbin/umount", mountPath, nil];
			BundledTask *t = [[BundledTask alloc] initWithCmd:cmd];
			[t setVerbose:YES];
			[[t autorelease] startAndWait];
         }
         @catch (NSException *e) {
            [[NSAlert alertWithMessageText:@"PDF unmount failed" defaultButton:nil alternateButton:nil otherButton:nil
                 informativeTextWithFormat:@"Failed to unmount PDF file %@ at %@: %@", path, mountPath, e] runModal];
         }
         [[NSFileManager defaultManager] removeFileAtPath:mountPath handler:nil];
         [array removeObjectAtIndex:i+1];
         [array removeObjectAtIndex:i];
      }
   }
   [pdfList reloadData];
   if (0 == [array count])
      [unmountButton setEnabled:NO];
}
-(IBAction)clickLink:(id)sender {
   printf("clickLink\n");
}

@end