#import "PCFileNode.h"
#import "FTPKitConstants.h"
#import <pthread.h>

#define kIconLoadingThreshold 30


// This protocol implements the policy for creating the containers used by a folder and is required.
@protocol PCNodeContainerCreating
@required

+ (NSMutableDictionary*)filenameDictionaryWithCapacity:(NSUInteger)capacity;

@end


// default policies, collect them all!
extern NSMutableDictionary* LiteralFilenameDictionary(NSUInteger capacity);
extern NSMutableDictionary* NonliteralFilenameDictionary(NSUInteger capacity);


@protocol PCFolderNode
@optional

// accessors

- (NSLock*)busyLock;
- (NSSet*)contentsWithHidden:(BOOL)flag;
- (NSSet*)contentsWithHidden:(BOOL)hiddenFlag includeDSStore:(BOOL)DSStoreFlag;
- (NSArray*)contentsWithSortType:(FTPSortType)sortType includeHidden:(BOOL)hidden ascending:(BOOL)ascending;
- (NSArray*)contentsWithSortType:(FTPSortType)sortType includeHidden:(BOOL)hidden includeDSStore:(BOOL)store ascending:(BOOL)ascending;
- (NSDictionary*)contentsDict;
- (NSUInteger)countWithHidden:(BOOL)flag;
- (NSArray*)filenamesOfContents;
- (void)setPath:(NSString*)path;
- (BOOL)isExpired;
- (void)setExpired:(BOOL)flag;

// misc

- (void)addNodes:(NSObject<NSFastEnumeration>*)nodes;
- (void)childNodeWasRenamed:(PCNode*)node oldName:(NSString*)oldName;
- (void)removeAllNodes;
- (void)removeNodes:(NSObject<NSFastEnumeration>*)nodes;

// You must obtain -contentsLock_ when directly accessing -contentsDict_. This lock is locked behind the scenes when inserting or removing a node, or when calling -contentsDict or -countWithHidden:.
- (pthread_rwlock_t*)contentsLock_;
- (NSDictionary*)contentsDict_;

// the arguments will be retained, not copied, and contentsDict should have been created using the PCFolderNodeCreating category above to maintain composition insensitivity
- (void)setContentsDict:(NSMutableDictionary*)contentsDict visibleContents:(NSMutableSet*)visibleContents;

@end


// This is an implementation of a folder's contents. The intended use is for the owning folder to conform to the PCFolderNode protocol and forward any unhandled methods to the contents object. If the owning folder wishes to override any methods it is free to do so, in which case it may manually invoke the corresponding method on the contents object.
@interface PCFolderNodeContents : NSObject <PCFolderNode>
{
@private
	__weak PCNode<PCFolderNode>* iFolder;
	
	pthread_rwlock_t iContentsLock;
	NSMutableDictionary* iContentsDict;
	NSMutableSet* iVisibleContents;
	
	NSLock* iBusyLock;
}

- (id)initWithFolder:(PCNode<PCFolderNode>*)folder;

@end


@interface PCFolderNode : PCFileNode <PCNodeContainerCreating, PCFolderNode>
{
@private
	PCFolderNodeContents* iContents;
	
	BOOL iPackage;
	
	BOOL cancelIconLoading;
	NSLock* iconLock;
	BOOL iExpired;
}

@property (getter=isExpired) BOOL expired;
@property BOOL isPackage;

+ (id)folderNodeWithPath:(NSString*)path;

// accessors

- (PCFileNode*)nodeWithFilename:(NSString*)name;
- (PCFileNode*)nodeWithFilename:(NSString*)name createWithType:(PCFileSystemType)type;

- (PCFileNode*)nodeWithFilename:(NSString*)name useContentsLock:(BOOL)flag; // Only call this method if you have already obtained the contents lock manually.

// redeclared from PCFolderNode protocol for proper argument type specialization and checking

- (void)addNode:(PCFileNode*)node;
- (void)childNodeWasRenamed:(PCFileNode*)node oldName:(NSString*)oldName;
- (void)removeNode:(PCFileNode*)node;

// misc

- (NSSet*)contentsSet; // observable

- (void)cancelIconLoading;

@end


// a PCNodeTransaction is a per-thread construct that defers adding and/or removing nodes until those modifications are committed, either by an explicit call to +commit or when the thread completes
@interface PCNodeTransaction : NSObject
{
@private
	NSMutableSet* iFolders;
	NSMutableDictionary* iAdditions;
	NSMutableDictionary* iDeletions;
}

+ (void)begin;
+ (void)commit;

+ (BOOL)isPending;

@end
