/******************************************************************************
 * $Id: CreatorWindowController.m 4423 2008-01-02 16:55:05Z livings124 $
 *
 * Copyright (c) 2007-2008 Transmission authors and contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *****************************************************************************/

#import "CreatorWindowController.h"
#import "NSStringAdditions.h"

@interface CreatorWindowController (Private)

+ (NSString *) chooseFile;
- (void) locationSheetClosed: (NSSavePanel *) openPanel returnCode: (int) code contextInfo: (void *) info;
- (void) checkProgress;
- (void) failureSheetClosed: (NSAlert *) alert returnCode: (int) code contextInfo: (void *) info;

@end

@implementation CreatorWindowController

+ (void) createTorrentFile: (tr_handle *) handle
{
    //get file/folder for torrent
    NSString * path;
    if (!(path = [CreatorWindowController chooseFile]))
        return;
    
    CreatorWindowController * creator = [[self alloc] initWithWindowNibName: @"Creator" handle: handle path: path];
    [creator showWindow: nil];
}

+ (void) createTorrentFile: (tr_handle *) handle forFile: (NSString *) file
{
    CreatorWindowController * creator = [[self alloc] initWithWindowNibName: @"Creator" handle: handle path: file];
    [creator showWindow: nil];
}

- (id) initWithWindowNibName: (NSString *) name handle: (tr_handle *) handle path: (NSString *) path
{
    if ((self = [super initWithWindowNibName: name]))
    {
        fStarted = NO;
        
        fPath = [path retain];
        fInfo = tr_metaInfoBuilderCreate(handle, [fPath UTF8String]);
        
        if (fInfo->fileCount == 0)
        {
            NSAlert * alert = [[NSAlert alloc] init];
            [alert addButtonWithTitle: NSLocalizedString(@"OK", "Create torrent -> no files -> button")];
            [alert setMessageText: NSLocalizedString(@"This folder contains no files.",
                                                    "Create torrent -> no files -> title")];
            [alert setInformativeText: NSLocalizedString(@"There must be at least one file in a folder to create a torrent file.",
                                                        "Create torrent -> no files -> warning")];
            [alert setAlertStyle: NSWarningAlertStyle];
            
            [alert runModal];
            [alert release];
            
            [self release];
            return nil;
        }
        if (fInfo->totalSize == 0)
        {
            NSAlert * alert = [[NSAlert alloc] init];
            [alert addButtonWithTitle: NSLocalizedString(@"OK", "Create torrent -> zero size -> button")];
            [alert setMessageText: NSLocalizedString(@"The total file size is zero bytes.",
                                                    "Create torrent -> zero size -> title")];
            [alert setInformativeText: NSLocalizedString(@"A torrent file cannot be created for files with no size.",
                                                        "Create torrent -> zero size -> warning")];
            [alert setAlertStyle: NSWarningAlertStyle];
            
            [alert runModal];
            [alert release];
            
            [self release];
            return nil;
        }
        
        fDefaults = [NSUserDefaults standardUserDefaults];
    }
    return self;
}

- (void) awakeFromNib
{
    NSString * name = [fPath lastPathComponent];
    
    [[self window] setTitle: name];
    
    [fNameField setStringValue: name];
    [fNameField setToolTip: fPath];
    
    BOOL multifile = !fInfo->isSingleFile;
    
    NSImage * icon = [[NSWorkspace sharedWorkspace] iconForFileType: multifile
                        ? NSFileTypeForHFSTypeCode('fldr') : [fPath pathExtension]];
    [icon setSize: [fIconView frame].size];
    [fIconView setImage: icon];
    
    NSString * statusString = [NSString stringForFileSize: fInfo->totalSize];
    if (multifile)
    {
        NSString * fileString;
        int count = fInfo->fileCount;
        if (count != 1)
            fileString = [NSString stringWithFormat: NSLocalizedString(@"%d Files, ", "Create torrent -> info"), count];
        else
            fileString = NSLocalizedString(@"1 File, ", "Create torrent -> info");
        statusString = [fileString stringByAppendingString: statusString];
    }
    [fStatusField setStringValue: statusString];
    
    NSString * piecesCountString;
    int piecesCount = fInfo->pieceCount;
    if (piecesCount == 1)
        piecesCountString = NSLocalizedString(@"1 piece", "Create torrent -> info");
    else
        piecesCountString = [NSString stringWithFormat: NSLocalizedString(@"%d pieces", "Create torrent -> info"),
                                                                piecesCount];
    [fPiecesField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%@, %@ each", "Create torrent -> info"),
                                        piecesCountString, [NSString stringForFileSize: fInfo->pieceSize]]];
    
    fLocation = [[[[fDefaults stringForKey: @"CreatorLocation"] stringByExpandingTildeInPath] stringByAppendingPathComponent:
                    [name stringByAppendingPathExtension: @"torrent"]] retain];
    [fLocationField setStringValue: [fLocation stringByAbbreviatingWithTildeInPath]];
    [fLocationField setToolTip: fLocation];
    
    //set previously saved values
    NSString * tracker;
    if ((tracker = [fDefaults stringForKey: @"CreatorTracker"]))
        [fTrackerField setStringValue: tracker];
    
    if ([fDefaults objectForKey: @"CreatorPrivate"])
        [fPrivateCheck setState: [fDefaults boolForKey: @"CreatorPrivate"] ? NSOnState : NSOffState];
    
    if ([fDefaults objectForKey: @"CreatorOpen"])
        [fOpenCheck setState: [fDefaults boolForKey: @"CreatorOpen"] ? NSOnState : NSOffState];
}

- (void) dealloc
{
    [fPath release];
    [fLocation release];
    
    if (fInfo)
        tr_metaInfoBuilderFree(fInfo);
    
    if (fTimer)
        [fTimer invalidate];
    
    [super dealloc];
}

- (void) setLocation: (id) sender
{
    NSSavePanel * panel = [NSSavePanel savePanel];

    [panel setPrompt: NSLocalizedString(@"Select", "Create torrent -> location sheet -> button")];
    [panel setMessage: NSLocalizedString(@"Select the name and location for the torrent file.",
                                        "Create torrent -> location sheet -> message")]; 
    
    [panel setRequiredFileType: @"torrent"];
    [panel setCanSelectHiddenExtension: YES];
    
    [panel beginSheetForDirectory: [fLocation stringByDeletingLastPathComponent] file: [fLocation lastPathComponent]
            modalForWindow: [self window] modalDelegate: self didEndSelector: @selector(locationSheetClosed:returnCode:contextInfo:)
            contextInfo: nil];
}

- (void) create: (id) sender
{
    //parse tracker string
    NSString * trackerString = [fTrackerField stringValue];
    if ([trackerString rangeOfString: @"://"].location != NSNotFound)
    {
        if (![trackerString hasPrefix: @"http://"])
        {
            NSAlert * alert = [[[NSAlert alloc] init] autorelease];
            [alert addButtonWithTitle: NSLocalizedString(@"OK", "Create torrent -> http warning -> button")];
            [alert setMessageText: NSLocalizedString(@"The tracker address must begin with \"http://\".",
                                                    "Create torrent -> http warning -> title")];
            [alert setInformativeText: NSLocalizedString(@"Change the tracker address to create the torrent.",
                                                        "Create torrent -> http warning -> warning")];
            [alert setAlertStyle: NSWarningAlertStyle];
            
            [alert beginSheetModalForWindow: [self window] modalDelegate: self didEndSelector: nil contextInfo: nil];
            return;
        }
    }
    else
        trackerString = [@"http://" stringByAppendingString: trackerString];
    
    //don't allow blank addresses
    if ([trackerString length] <= 7)
    {
        NSAlert * alert = [[[NSAlert alloc] init] autorelease];
        [alert addButtonWithTitle: NSLocalizedString(@"OK", "Create torrent -> no url warning -> button")];
        [alert setMessageText: NSLocalizedString(@"The tracker address cannot be blank.",
                                                "Create torrent -> no url warning -> title")];
        [alert setInformativeText: NSLocalizedString(@"Change the tracker address to create the torrent.",
                                                    "Create torrent -> no url warning -> warning")];
        [alert setAlertStyle: NSWarningAlertStyle];
        
        [alert beginSheetModalForWindow: [self window] modalDelegate: self didEndSelector: nil contextInfo: nil];
        return;
    }
    
    //check if a file with the same name and location already exists
    if ([[NSFileManager defaultManager] fileExistsAtPath: fLocation])
    {
        NSArray * pathComponents = [fLocation pathComponents];
        int count = [pathComponents count];
        
        NSAlert * alert = [[[NSAlert alloc] init] autorelease];
        [alert addButtonWithTitle: NSLocalizedString(@"OK", "Create torrent -> file already exists warning -> button")];
        [alert setMessageText: NSLocalizedString(@"A torrent file with this name and directory cannot be created.",
                                                "Create torrent -> file already exists warning -> title")];
        [alert setInformativeText: [NSString stringWithFormat:
                NSLocalizedString(@"A file with the name \"%@\" already exists in the directory \"%@\". "
                    "Choose a new name or directory to create the torrent.",
                    "Create torrent -> file already exists warning -> warning"),
                    [pathComponents objectAtIndex: count-1], [pathComponents objectAtIndex: count-2]]];
        [alert setAlertStyle: NSWarningAlertStyle];
        
        [alert beginSheetModalForWindow: [self window] modalDelegate: self didEndSelector: nil contextInfo: nil];
        return;
    }
    
    fOpenTorrent = [fOpenCheck state] == NSOnState;
    
    //store values
    [fDefaults setObject: trackerString forKey: @"CreatorTracker"];
    [fDefaults setBool: [fPrivateCheck state] == NSOnState forKey: @"CreatorPrivate"];
    [fDefaults setBool: fOpenTorrent forKey: @"CreatorOpen"];
    [fDefaults setObject: [fLocation stringByDeletingLastPathComponent] forKey: @"CreatorLocation"];
    
    [[NSNotificationCenter defaultCenter] postNotificationName: @"BeginCreateTorrentFile" object: fLocation userInfo: nil];
    tr_makeMetaInfo(fInfo, [fLocation UTF8String], [trackerString UTF8String], [[fCommentView string] UTF8String],
                    [fPrivateCheck state] == NSOnState);
    
    fTimer = [NSTimer scheduledTimerWithTimeInterval: 0.1 target: self selector: @selector(checkProgress)
                        userInfo: nil repeats: YES];
}

- (void) cancelCreateWindow: (id) sender
{
    [[self window] close];
}

- (void) windowWillClose: (NSNotification *) notification
{
    [self release];
}

- (void) cancelCreateProgress: (id) sender
{
    fInfo->abortFlag = 1;
    [fTimer fire];
}

@end

@implementation CreatorWindowController (Private)

+ (NSString *) chooseFile
{
    NSOpenPanel * panel = [NSOpenPanel openPanel];
    
    [panel setTitle: NSLocalizedString(@"Create Torrent File", "Create torrent -> select file")];
    [panel setPrompt: NSLocalizedString(@"Select", "Create torrent -> select file")];
    [panel setAllowsMultipleSelection: NO];
    [panel setCanChooseFiles: YES];
    [panel setCanChooseDirectories: YES];
    [panel setCanCreateDirectories: NO];

    [panel setMessage: NSLocalizedString(@"Select a file or folder for the torrent file.", "Create torrent -> select file")];
    
    BOOL success = [panel runModal] == NSOKButton;
    return success ? [[panel filenames] objectAtIndex: 0] : nil;
}

- (void) locationSheetClosed: (NSSavePanel *) panel returnCode: (int) code contextInfo: (void *) info
{
    if (code == NSOKButton)
    {
        [fLocation release];
        fLocation = [[panel filename] retain];
        
        [fLocationField setStringValue: [fLocation stringByAbbreviatingWithTildeInPath]];
        [fLocationField setToolTip: fLocation];
    }
}

- (void) checkProgress
{
    if (fInfo->isDone)
    {
        [fTimer invalidate];
        fTimer = nil;
        
        if (fInfo->failed)
        {
            if (!fInfo->abortFlag)
            {
                NSAlert * alert = [[[NSAlert alloc] init] autorelease];
                [alert addButtonWithTitle: NSLocalizedString(@"OK", "Create torrent -> failed -> button")];
                [alert setMessageText: [NSString stringWithFormat: NSLocalizedString(@"Creation of \"%@\" failed.",
                                                "Create torrent -> failed -> title"), [fLocation lastPathComponent]]];
                [alert setInformativeText: NSLocalizedString(@"There was an error parsing the data file. "
                                            "The torrent file was not created.", "Create torrent -> failed -> warning")];
                [alert setAlertStyle: NSWarningAlertStyle];
                
                [alert beginSheetModalForWindow: [self window] modalDelegate: self
                        didEndSelector: @selector(failureSheetClosed:returnCode:contextInfo:) contextInfo: nil];
                return;
            }
        }
        else
        {
            if (fOpenTorrent)
            {
                NSDictionary * dict = [[NSDictionary alloc] initWithObjectsAndKeys: fLocation, @"File",
                                        [fPath stringByDeletingLastPathComponent], @"Path", nil];
                [[NSNotificationCenter defaultCenter] postNotificationName: @"OpenCreatedTorrentFile" object: self userInfo: dict];
            }
        }
        
        [[self window] close];
    }
    else
    {
        [fProgressIndicator setDoubleValue: (double)fInfo->pieceIndex / fInfo->pieceCount];
        
        if (!fStarted)
        {
            NSWindow * window = [self window];
            
            NSRect windowRect = [window frame];
            float difference = [fProgressView frame].size.height - [[window contentView] frame].size.height;
            windowRect.origin.y -= difference;
            windowRect.size.height += difference;
            
            //don't allow vertical resizing
            float height = windowRect.size.height;
            [window setMinSize: NSMakeSize([window minSize].width, height)];
            [window setMaxSize: NSMakeSize([window maxSize].width, height)];
            
            [window setContentView: fProgressView];
            [window setFrame: windowRect display: YES animate: YES];
            [fProgressView setHidden: NO];
            
            fStarted = YES;
        }
    }
}

- (void) failureSheetClosed: (NSAlert *) alert returnCode: (int) code contextInfo: (void *) info
{
    [[alert window] orderOut: nil];
    [[self window] close];
}

@end
