// Copyright 1999-2002 Omni Development, Inc.  All rights reserved.
//
// This software may only be used and reproduced according to the
// terms in the file OmniSourceLicense.html, which should be
// distributed with this project and can also be found at
// http://www.omnigroup.com/DeveloperResources/OmniSourceLicense.html.

#import <OWF/OWMacOSPeterLewisFTPProcessor.h>

#import <Foundation/Foundation.h>
#import <OmniBase/OmniBase.h>
#import <OmniFoundation/OmniFoundation.h>

#import <OWF/OWAddress.h>
#import <OWF/OWContentCache.h>
#import <OWF/OWDataStreamCharacterCursor.h>
#import <OWF/OWFileInfo.h>
#import <OWF/OWObjectStream.h>
#import <OWF/OWPipeline.h>
#import <OWF/OWURL.h>

RCS_ID("$Header: /Network/Source/CVS/OmniGroup/Frameworks/OWF/Processors.subproj/Protocols.subproj/FTP.subproj/OWMacOSPeterLewisFTPProcessor.m,v 1.9 2002/03/09 01:53:52 kc Exp $")

@interface OWMacOSPeterLewisFTPProcessor (Private)
+ (void)registerForContentTypeString:(NSString *)sourceType cost:(int)cost;
@end

@implementation OWMacOSPeterLewisFTPProcessor

+ (void)didLoad;
{
    [self registerForContentTypeString:@"OWFTPDirectory/MacOS-PeterLewis" cost:1.0];
}

+ (void)registerForContentTypeString:(NSString *)sourceType cost:(int)cost;
{
    [self registerProcessorClass:self fromContentTypeString:sourceType toContentTypeString:@"ObjectStream/OWFileInfoList" cost:cost];
}

- initWithPipeline:(OWPipeline *)aPipeline;
{
    if (![super initWithPipeline:aPipeline])
        return nil;

    baseAddress = [(OWAddress *)[pipeline lastAddress] retain];

    objectStream = [[OWObjectStream alloc] init];
    [objectStream setContentTypeString:@"ObjectStream/OWFileInfoList"];
    [pipeline addContent:objectStream];
    [pipeline cacheContent];
    [pipeline startProcessingContent];
    return self;
}

- (void)dealloc;
{
    [objectStream release];
    [baseAddress release];
    [super dealloc];
}

- (void)addFileForLine:(NSString *)line;
{
    OWFileInfo *fileInfo;
    NSScanner *lineScanner;
    NSString *directoryFlag, *permissions = nil;
    unsigned long long int resourceForkSize = 0, dataForkSize = 0, size = 0;
    NSString *month = nil, *day = nil, *timeOrYear = nil;
    NSString *dateString, *name = nil;
    NSCharacterSet *whitespace;
    NSCalendarDate *changeDate;
    NSRange timeSeparatorRange;
    OWAddress *fileAddress;
    BOOL isFolder;
    NSAutoreleasePool *pool;

    pool = [[NSAutoreleasePool alloc] init];
    whitespace = [NSCharacterSet whitespaceCharacterSet];
    lineScanner = [NSScanner scannerWithString:line];
    [lineScanner scanUpToCharactersFromSet:whitespace intoString:&permissions];
    directoryFlag = [permissions substringToIndex:1];
    permissions = [permissions substringFromIndex:1];

    if ([lineScanner scanString:@"folder" intoString:NULL]) {
        isFolder = YES;
        resourceForkSize = dataForkSize = 0;
        // NB: If isFolder is true, then the "size" field holds the count of items in the folder, not the size of the folder in bytes. We currently have no way of making use of this information. 
    } else {
        isFolder = NO;
        [lineScanner scanLongLong:&resourceForkSize];
        [lineScanner scanLongLong:&dataForkSize];
    }
    
    [lineScanner scanLongLong:&size];
    [lineScanner scanUpToCharactersFromSet:whitespace intoString:&month];
    [lineScanner scanUpToCharactersFromSet:whitespace intoString:&day];
    [lineScanner scanUpToCharactersFromSet:whitespace intoString:&timeOrYear];
    timeSeparatorRange = [timeOrYear rangeOfString:@":"];
    if (timeSeparatorRange.length) {
        NSCalendarDate *now = (NSCalendarDate *)[NSCalendarDate date];
	dateString = [NSString stringWithFormat:@"%@ %@ %@ %d", month, day, timeOrYear, [now yearOfCommonEra]];
	changeDate = [NSCalendarDate dateWithString:dateString calendarFormat:@"%b %d %H:%M %Y"];
        
        // deal with year boundaries
        if ([changeDate monthOfYear] > [now monthOfYear])
            changeDate = [changeDate dateByAddingYears:-1 months:0 days:0 hours:0 minutes:0 seconds:0];
    } else {
	dateString = [NSString stringWithFormat:@"%@ %@ %@", month, day, timeOrYear];
	changeDate = [NSCalendarDate dateWithString:dateString calendarFormat:@"%b %d %Y"];
    }
    [lineScanner setCharactersToBeSkipped:nil];
    [lineScanner scanCharactersFromSet:whitespace intoString:NULL];
    [lineScanner scanUpToString:@" -> " intoString:&name];

    if ([name isEqualToString:@"."] || [name isEqualToString:@".."]) {
        [pool release];
	return;
    }

    fileAddress = [baseAddress addressForRelativeString:[NSString encodeURLString:name asQuery:NO leaveSlashes:NO leaveColons:NO]];
    fileInfo = [[OWFileInfo alloc] initWithAddress:fileAddress
                                              size:isFolder ? nil : [NSNumber numberWithUnsignedLong:size]
                                       isDirectory:(isFolder || [directoryFlag isEqualToString:@"d"])
                                        isShortcut:[directoryFlag isEqualToString:@"l"]
                                    lastChangeDate:changeDate];
    [objectStream writeObject:fileInfo];
    [[OWContentCache contentCacheForAddress:fileAddress] addContent:fileInfo];
    [fileInfo release];
    [pool release];
}

- (void)process;
{
    BOOL firstLine = YES;
    NSString *line;

    while ((line = [characterCursor readLine])) {
        if (firstLine && [line hasPrefix:@"total "]) {
            // On some servers, the first line gives the total size, so we just skip it.
        } else {
            [self addFileForLine:line];
        }
        firstLine = NO;
    }
    [objectStream dataEnd];
}

- (void)processAbort;
{
    [objectStream dataAbort];
    [super processAbort];
}

@end
