/* GrandPerspective, Version 2.5.4 
 *   A utility for Mac OS X that graphically shows disk usage. 
 * Copyright (C) 2005-2020, Erwin Bonsma 
 * 
 * This program is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU General Public License as published by the Free 
 * Software Foundation; either version 2 of the License, or (at your option) 
 * any later version. 
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
 * more details. 
 * 
 * You should have received a copy of the GNU General Public License along 
 * with this program; if not, write to the Free Software Foundation, Inc., 
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
 */

#import "ProgressTracker.h"

#import "DirectoryItem.h"


NSString  *NumFoldersProcessedKey = @"numFoldersProcessed";
NSString  *NumFoldersSkippedKey = @"numFoldersSkipped";
NSString  *CurrentFolderPathKey = @"currentFolderPath";
NSString  *EstimatedProgressKey = @"estimatedProgress";


@implementation ProgressTracker

- (instancetype) init {
  if (self = [super init]) {
    mutex = [[NSLock alloc] init];
    directoryStack = [[NSMutableArray alloc] initWithCapacity: 16];
  }

  return self;
}

- (void) dealloc {
  [mutex release];
  [directoryStack release];
  
  [super dealloc];

}

- (void) startingTask {
  [mutex lock];
  numFoldersProcessed = 0;
  numFoldersSkipped = 0;
  level = 0;
  [directoryStack removeAllObjects];
  [mutex unlock];
}

- (void) finishedTask {
  [mutex lock];
  [directoryStack removeAllObjects];
  [mutex unlock];
}


- (void) processingFolder:(DirectoryItem *)dirItem {
  [mutex lock];
  [self _processingFolder: dirItem];
  [mutex unlock];
}

- (void) processedFolder:(DirectoryItem *)dirItem {
  [mutex lock];
  [self _processedFolder: dirItem];
  [mutex unlock];
}

- (void) skippedFolder:(DirectoryItem *)dirItem {
  [mutex lock];
  [self _skippedFolder: dirItem];
  [mutex unlock];
}


- (NSDictionary *)progressInfo {
  NSDictionary  *dict;

  [mutex lock];
  dict = @{NumFoldersProcessedKey: @(numFoldersProcessed),
           NumFoldersSkippedKey: @(numFoldersSkipped),
           CurrentFolderPathKey: [directoryStack.lastObject path] ?: @"",
           EstimatedProgressKey: @([self estimatedProgress])};
  [mutex unlock];

  return dict;
}

- (NSUInteger) numFoldersProcessed {
  return numFoldersProcessed;
}

@end // @implementation ProgressTracker


@implementation ProgressTracker (ProtectedMethods)

- (void) _processingFolder:(DirectoryItem *)dirItem {
  if (directoryStack.count == 0) {
    // Find the root of the tree
    DirectoryItem  *root = dirItem;
    DirectoryItem  *parent = nil;
    while ((parent = [root parentDirectory]) != nil) {
      root = parent;
    }

    if (root != dirItem) {
      // Add the root of the tree to the stack. This ensures that -path can be
      // called for any FileItem in the stack, even after the tree has been
      // released externally (e.g. because the task constructing it has been
      // aborted).
      [directoryStack addObject: root];
    }
  }

  [directoryStack addObject: dirItem];
  level++;
}

- (void) _processedFolder:(DirectoryItem *)dirItem {
  NSAssert([directoryStack lastObject] == dirItem, @"Inconsistent stack.");
  [directoryStack removeLastObject];
  numFoldersProcessed++;
  level--;
}

- (void) _skippedFolder:(DirectoryItem *)dirItem {
  numFoldersSkipped++;
}

/* Default implementation, fixed to zero. Without more detailed knowledge about
 * the task, it is not feasible to estimate progress accurately.
 */
- (float) estimatedProgress {
  return 0.0;
}

@end
