// Copyright 1997-2000 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 <OmniFoundation/OFStaticArray.h>

#import <objc/objc-class.h> // Import this before Foundation/Foundation.h to avoid compiler bug
#import <Foundation/Foundation.h>
#import <OmniBase/OmniBase.h>

RCS_ID("$Header: /Network/Source/CVS/OmniGroup/Frameworks/OmniFoundation/DataStructures.subproj/OFStaticArray.m,v 1.12 2000/01/19 23:35:17 kc Exp $")


@interface OFStaticArray (Private)
- (void)deallocObjectsToCount:(unsigned int)newCount;
@end

@implementation OFStaticArray

static NSZone *OFStaticArrayZone;

+ (void)initialize;
{
    static BOOL initialized = NO;

    [super initialize];
    if (initialized)
        return;
    initialized = YES;

    OFStaticArrayZone = NSCreateZone(0, NSPageSize(), YES);
}

#define DEFAULT_CAPACITY  10
#define DEFAULT_EXTENSION  1

- initWithClass:(Class)aClass capacity:(unsigned int)aCapacity extendBy:(unsigned int)extendBy;
{
    if (![super init])
        return nil;

    objectClass = aClass;
    objectLength = aClass->instance_size;
    count = 0;
    extensionSize = extendBy;
    if (aCapacity < extensionSize)
        capacity = extensionSize;
    else
        capacity = aCapacity;
#ifdef OFStaticArray_USE_NSDATA
    data = [[NSMutableData allocWithZone:OFStaticArrayZone] initWithLength:capacity * objectLength];
    mutableBytes = [data mutableBytes];
#else
    mutableBytes = NSZoneMalloc(OFStaticArrayZone, capacity * objectLength);
#endif
    return self;
}

- initWithClass:(Class)aClass capacity:(unsigned int)aCapacity;
{
    return [self initWithClass:aClass capacity:aCapacity extendBy:DEFAULT_EXTENSION];
}

- initWithClass:(Class)aClass;
{
    return [self initWithClass:aClass capacity:DEFAULT_CAPACITY extendBy:DEFAULT_EXTENSION];
}

- (void)dealloc
{
    [self deallocObjectsToCount:0];
#ifdef OFStaticArray_USE_NSDATA
    [data release];
#else
    NSZoneFree(OFStaticArrayZone, mutableBytes);
#endif
    [super dealloc];
}

- (unsigned int)capacity;
{
    return capacity;
}

- (void)setCapacity:(unsigned int)newCapacity;
{
    if (newCapacity < count)
        [self setCount:newCapacity];
    
    if (newCapacity > capacity) {
        if (!extensionSize)
            newCapacity = MAX(newCapacity, capacity * 2);
        else
            newCapacity = MAX(newCapacity, capacity + extensionSize);
#ifdef OFStaticArray_USE_NSDATA
        [data setLength:newCapacity * objectLength];
        mutableBytes = [data mutableBytes];
#else
        mutableBytes = NSZoneRealloc(OFStaticArrayZone, mutableBytes, newCapacity * objectLength);
        memset(mutableBytes + capacity * objectLength, 0, (newCapacity - capacity) * objectLength);
#endif
        capacity = newCapacity;
    } 
}

- (unsigned int)extensionSize;
{
    return extensionSize;
}

- (void)setExtensionSize:(unsigned int)anAmount;
{
    extensionSize = anAmount;
}

- (unsigned int)count;
{
    return count;
}

- (void)setCount:(unsigned int)number;
{
    void *ptr;

    if (number < count) {
        [self deallocObjectsToCount:number];
    } else {
        if (number > capacity)
            [self setCapacity:number];
        ptr = mutableBytes + count * objectLength;
        while (count < number) {
            *(Class *)ptr = objectClass;
            ptr += objectLength;
            count++;
        }
    }
}

- (void)removeAllObjects;
{
    [self setCount:0];
}

- (id)newObject;
{
    void *ptr;

    if (count == capacity)
        [self setCapacity:capacity+1];

    ptr = mutableBytes + count++ * objectLength;
    *(Class *)ptr = objectClass;
    return (id)ptr;
}

- (id)objectAtIndex:(unsigned int)anIndex;
{
    if (anIndex > count)
        [NSException raise:NSRangeException format:@"index (%d) is beyond count (%d)", anIndex, count];
    return (id)(mutableBytes + objectLength * anIndex);
}

// Debugging

- (NSMutableDictionary *)debugDictionary;
{
    NSMutableDictionary *debugDictionary;
    NSMutableArray *objects;
    unsigned int index;

    objects = [[NSMutableArray alloc] initWithCapacity:count];
    for (index = 0; index < count; index++)
        [objects addObject:[self objectAtIndex:index]];

    debugDictionary = [super debugDictionary];
    [debugDictionary setObject:[NSString stringWithFormat:@"%d", count] forKey:@"count"];
    [debugDictionary setObject:[NSString stringWithFormat:@"%d", capacity] forKey:@"capacity"];
    [debugDictionary setObject:[NSString stringWithFormat:@"%d", extensionSize] forKey:@"extensionSize"];
    [debugDictionary setObject:objects forKey:@"objects"];
    return debugDictionary;
}

@end

@implementation OFStaticArray (Private)

- (void)deallocObjectsToCount:(unsigned int)newCount;
{
    int countDifference;
    void *ptr;

    countDifference = count - newCount;
    if (countDifference <= 0)
        return;
    
    ptr = mutableBytes + (count - 1) * objectLength;
    while (countDifference--) {
        [(id)ptr dealloc];
        ptr -= objectLength;
    }
    memset(mutableBytes + newCount * objectLength, 0, (count - newCount) * objectLength);
    // [data resetBytesInRange:NSMakeRange(newCount * objectLength, (count - newCount) * objectLength)];

    count = newCount;
}

@end
