1/******************************************************************************
2 * Copyright (c) 2008-2012 Transmission authors and contributors
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 *****************************************************************************/
22
23#import "FileListNode.h"
24
25@interface FileListNode (Private)
26
27- (id) initWithFolder: (BOOL) isFolder name: (NSString *) name path: (NSString *) path torrent: (Torrent *) torrent;
28
29@end
30
31@implementation FileListNode
32
33#warning remove ivars in header when 64-bit only (or it compiles in 32-bit mode)
34@synthesize name = fName;
35@synthesize path = fPath;
36@synthesize torrent = fTorrent;
37@synthesize size = fSize;
38@synthesize icon = fIcon;
39@synthesize isFolder = fIsFolder;
40@synthesize indexes = fIndexes;
41@synthesize children = fChildren;
42
43- (id) initWithFolderName: (NSString *) name path: (NSString *) path torrent: (Torrent *) torrent
44{
45    if ((self = [self initWithFolder: YES name: name path: path torrent: torrent]))
46    {
47        fChildren = [[NSMutableArray alloc] init];
48        fSize = 0;
49    }
50
51    return self;
52}
53
54- (id) initWithFileName: (NSString *) name path: (NSString *) path size: (uint64_t) size index: (NSUInteger) index torrent: (Torrent *) torrent
55{
56    if ((self = [self initWithFolder: NO name: name path: path torrent: torrent]))
57    {
58        fSize = size;
59        [fIndexes addIndex: index];
60    }
61
62    return self;
63}
64
65- (void) insertChild: (FileListNode *) child
66{
67    NSAssert(fIsFolder, @"method can only be invoked on folders");
68
69    [fChildren addObject: child];
70}
71
72- (void) insertIndex: (NSUInteger) index withSize: (uint64_t) size
73{
74    NSAssert(fIsFolder, @"method can only be invoked on folders");
75
76    [fIndexes addIndex: index];
77    fSize += size;
78}
79
80- (id) copyWithZone: (NSZone *) zone
81{
82    //this object is essentially immutable after initial setup
83    return self;
84}
85
86
87- (NSString *) description
88{
89    if (!fIsFolder)
90        return [NSString stringWithFormat: @"%@ (%ld)", fName, [fIndexes firstIndex]];
91    else
92        return [NSString stringWithFormat: @"%@ (folder: %@)", fName, fIndexes];
93}
94
95- (NSImage *) icon
96{
97    if (!fIcon)
98        fIcon = [[NSWorkspace sharedWorkspace] iconForFileType: fIsFolder ? NSFileTypeForHFSTypeCode(kGenericFolderIcon)
99                                                                            : [fName pathExtension]];
100    return fIcon;
101}
102
103- (NSMutableArray *) children
104{
105    NSAssert(fIsFolder, @"method can only be invoked on folders");
106
107    return fChildren;
108}
109
110- (BOOL) updateFromOldName: (NSString *) oldName toNewName: (NSString *) newName inPath: (NSString *) path
111{
112    NSParameterAssert(oldName != nil);
113    NSParameterAssert(newName != nil);
114    NSParameterAssert(path != nil);
115
116    NSArray * lookupPathComponents = [path pathComponents];
117    NSArray * thesePathComponents = [self.path pathComponents];
118
119    if ([lookupPathComponents isEqualToArray: thesePathComponents]) //this node represents what's being renamed
120    {
121        if ([oldName isEqualToString: self.name])
122        {
123            fName = [newName copy];
124            fIcon = nil;
125            return YES;
126        }
127    }
128    else if ([lookupPathComponents count] < [thesePathComponents count]) //what's being renamed is part of this node's path
129    {
130        lookupPathComponents = [lookupPathComponents arrayByAddingObject: oldName];
131        const BOOL allSame = NSNotFound == [lookupPathComponents indexOfObjectWithOptions: NSEnumerationConcurrent passingTest: ^BOOL(NSString * name, NSUInteger idx, BOOL * stop) {
132            return ![name isEqualToString: thesePathComponents[idx]];
133        }];
134
135        if (allSame)
136        {
137            NSString * oldPathPrefix = [path stringByAppendingPathComponent: oldName];
138            NSString * newPathPrefix = [path stringByAppendingPathComponent: newName];
139
140            fPath = [fPath stringByReplacingCharactersInRange: NSMakeRange(0, [oldPathPrefix length]) withString: newPathPrefix];
141            return YES;
142        }
143    }
144
145    return NO;
146}
147
148@end
149
150@implementation FileListNode (Private)
151
152- (id) initWithFolder: (BOOL) isFolder name: (NSString *) name path: (NSString *) path torrent: (Torrent *) torrent
153{
154    if ((self = [super init]))
155    {
156        fIsFolder = isFolder;
157        fName = [name copy];
158        fPath = [path copy];
159
160        fIndexes = [[NSMutableIndexSet alloc] init];
161
162        fTorrent = torrent;
163    }
164
165    return self;
166}
167
168@end
169