static void *rcs_id = (rcs_id, "$Header: /LocalDeveloper/Source/CVS/OmniGroup/OmniCVSEOModelerBundle/CVSManager.m,v 1.3 1998/03/25 01:18:32 toon Exp $");

/* CVSManager.m created by andrew on Wed 13-Nov-1996 */


#import <Foundation/Foundation.h>
#import <EOModeler/EOModeler.h>

#import "CVSManager.h"


/* minor extension to NSFileManager to make it more convenient to see if a directory exists */

@interface NSFileManager (CVSBundleExtensions)
- (BOOL)directoryExistsAtPath:(NSString *)path;
@end

@implementation NSFileManager (CVSBundleExtensions)
- (BOOL)directoryExistsAtPath:(NSString *)path;
{
    BOOL isDirectory;

    if (![self fileExistsAtPath: path isDirectory: &isDirectory])
        return NO;
    return isDirectory;
}

@end


/*
   On +load we register for notification when a document is saved. When we get that notification, we try to copy the CVS info from the model's backup to the newly saved model.
*/

@interface CVSManager (Private)
+ (NSString *)restoreCVSInfoToDocumentAt:(NSString *)path;
+ (void)didSaveDocument:(NSNotification *)notification;
@end


@implementation CVSManager

static NSString *versionString = @"version 1.0";

+ (NSString *)versionString;	// in case we ever decide to display this somehow
{
    return versionString;
}

+ (void)load;
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didSaveDocument:) name:EOMDocumentDidSaveNotification object:nil];
}

+ (NSString *)adjustEntriesFile:(NSString *)path forModel:(EOModel *)aModel
{
    NSMutableSet *entityNames, *procedureNames;
    NSMutableString *result;
    NSArray *entriesLines;
    NSEnumerator *enumerator, *remainder = nil;
    NSString *line, *remainderLine = nil;
    NSString *name;

    result = [NSMutableString string];
    entityNames = [NSMutableSet setWithArray:[aModel entityNames]];
    procedureNames = [NSMutableSet setWithArray:[aModel storedProcedureNames]];
    entriesLines = [[NSString stringWithContentsOfFile:path] componentsSeparatedByString:@"\n"];

    /* Find removed entities */
    enumerator = [entriesLines objectEnumerator];
    while((line = [enumerator nextObject])) {
        NSArray *parts = [line componentsSeparatedByString:@"/"];

        if ([parts count] == 6) {
            name = [parts objectAtIndex:1];
            if ([[name pathExtension] isEqualToString:@"plist"]) {
                name = [name stringByDeletingPathExtension];
                if ([entityNames member:name]) {
                    [entityNames removeObject:name];
                } else {
                    NSString *version = [parts objectAtIndex:2];

                    if ([version isEqualToString:@"0"])
                        line = nil;
                    else {
                        NSMutableArray *mutable = [parts mutableCopy];

                        [mutable replaceObjectAtIndex:2 withObject:[@"-" stringByAppendingString:version]];
                        line = [mutable componentsJoinedByString:@"/"];
                        [mutable release];
                    }
                }
            } else if ([[name pathExtension] isEqualToString:@"storedProcedure"]) {
                name = [name stringByDeletingPathExtension];
                if ([procedureNames member:name]) {
                    [procedureNames removeObject:name];
                } else {
                    NSString *version = [parts objectAtIndex:2];

                    if ([version isEqualToString:@"0"])
                        line = nil;
                    else {
                        NSMutableArray *mutable = [parts mutableCopy];

                        [mutable replaceObjectAtIndex:2 withObject:[@"-" stringByAppendingString:version]];
                        line = [mutable componentsJoinedByString:@"/"];
                        [mutable release];
                    }
                }
            }
            if (line) {
                [result appendString:line];
                [result appendString:@"\n"];
            }
        } else {
            remainder = enumerator;
            remainderLine = line;
        }
    }

    /* Find added entities */
    enumerator = [entityNames objectEnumerator];
    while((name = [enumerator nextObject])) {
        [result appendFormat:@"/%@.plist/0/Initial %@.plist//\n", name, name];
    }

    /* Find added procedures */
    enumerator = [procedureNames objectEnumerator];
    while((name = [enumerator nextObject])) {
        [result appendFormat:@"/%@.storedProcedure/0/Initial %@.storedProcedure//\n", name, name];
    }

    /* Append on end */
    if (remainderLine) {
        do {
            [result appendString:remainderLine];
            [result appendString:@"\n"];
        } while((remainderLine = [remainder nextObject]));
    }
    [result writeToFile:path atomically:YES];
    return nil;
}

+ (NSString *)restoreCVSInfoToDocumentAt:(NSString *)path forModel:(EOModel *)aModel;
{
    NSFileManager *manager;
    NSString *cvsPath;
    NSString *oldPath;

    manager = [NSFileManager defaultManager];

    if (![manager directoryExistsAtPath:path])
        return [NSString stringWithFormat:@"Could not find model at %@", path];

    oldPath = [path stringByAppendingString:@"~"];
    if (![manager directoryExistsAtPath:oldPath])
        return nil;	// backup won't exist if model being saved was brand new

    cvsPath = [oldPath stringByAppendingPathComponent:@"CVS"];
    if (![manager directoryExistsAtPath:cvsPath])
        return nil;	// no CVS info to copy - probably never been checked in

    path = [path stringByAppendingPathComponent:@"CVS"];
    if ([manager directoryExistsAtPath:path])
        return [NSString stringWithFormat:@"CVS directory already exists at %@", path];

    if (![manager movePath:cvsPath toPath:path handler:nil])
        return [NSString stringWithFormat:@"Failed to move '%@' to '%@'", cvsPath, path];

    path = [path stringByAppendingPathComponent:@"Entries"];
    return [self adjustEntriesFile:path forModel:aModel];
}

+ (void)didSaveDocument:(NSNotification *)notification;
{
    NSString *errorMsg;
    NSString *path;

    path = [(EOModelerDocument *)[notification object] documentPath];

    errorMsg = [self restoreCVSInfoToDocumentAt:path forModel:[(EOModelerDocument *)[notification object] model]];
    if (errorMsg)
        NSRunAlertPanel (nil, errorMsg, nil, nil, nil);
}

@end
