/*
        Copyright (c) 1996, NeXT Software, Inc.
        All rights reserved.

        You may freely copy, distribute and reuse the code in this example.
        NeXT disclaims any warranty of any kind, expressed or implied,
        as to its fitness for any particular use.
*/
#import <BusinessLogic/Customer.h>
#import <BusinessLogic/Rental.h>
#import <BusinessLogic/Fee.h>
#import <BusinessLogic/Unit.h>
#import <BusinessLogic/NSObjectAdditions.h>

@implementation Customer

- (NSArray *)allRentals
{
    return rentals;
}

- (NSArray *)fees
{
    NSEnumerator *rentalsEnumerator = [[self allRentals] objectEnumerator];
    NSMutableArray *fees;
    Rental *next;

    fees = [NSMutableArray array];
    while(next = [rentalsEnumerator nextObject])
        [fees addObjectsFromArray:[next fees]];

    return fees;
}

- (NSDecimalNumber *)costRestriction;
{
    [NSException raise:NSInvalidArgumentException
                format:@"-%@ cannot be sent to an abstract object of class %@.",
                NSStringFromSelector(_cmd), [[self class] name]];

    return nil; // Just to keep the compiler happy.
}

- (Member *)member
{
    [NSException raise:NSInvalidArgumentException
                format:@"-%@ cannot be sent to an abstract object of class %@.",
                NSStringFromSelector(_cmd), [[self class] name]];

    return nil; // Just to keep the compiler happy.
}

- (void)dealloc
{
    [customerID release];
    [firstName release];
    [lastName release];
    [rentals release];
    [super dealloc];
}


- (NSArray *)unpaidFees
{
    static EOQualifier *qualifier = nil;

    if(!qualifier) {
        qualifier = [[EOKeyValueQualifier alloc] initWithKey:@"datePaid"
                                            operatorSelector:EOQualifierOperatorEqual
                                                       value:[EONull null]];
    }
    return [[self fees] filteredArrayUsingQualifier:qualifier];
}

- (BOOL)hasOverdueProducts
{
    NSEnumerator *rentalsEnumerator = [[self nonReturnedRentals] objectEnumerator];
    Rental *next;

    while(next = [rentalsEnumerator nextObject])
        if([next isOverdue]) return YES;

    return NO;
}

- (NSArray *)nonReturnedRentals
{
    static EOQualifier *qualifier = nil;

    if(!qualifier) {
        qualifier = [[EOKeyValueQualifier alloc] initWithKey:@"isOut"
                                            operatorSelector:EOQualifierOperatorEqual
                                                       value:[NSNumber numberWithBool:YES]];
    }
    return [[self allRentals] filteredArrayUsingQualifier:qualifier];
}

- (NSString *)fullName
{
    return [NSString stringWithFormat:@"%@ %@", firstName, lastName];
}

- (void)rentUnit:(Unit *)unit
{
    Rental *rental;
    Fee *fee;

    // I need to create two objects here.
    rental = [[[Rental alloc] init] autorelease];
    fee = [[[Fee alloc] init] autorelease];

    [rental addObject:fee toBothSidesOfRelationshipWithKey:@"fees"];
    [rental addObject:unit toBothSidesOfRelationshipWithKey:@"unit"];

    [self addObject:rental toBothSidesOfRelationshipWithKey:@"rentals"];

    // Insert the two objects in the editingContext.
    [[self editingContext] insertObject:rental];
    [[self editingContext] insertObject:fee];
}

- (NSException *)validateForSave
{
    // this method will be called before we are inserted or updated in the database
    NSDecimalNumber *currentDeposit = [[self allRentals] sumArrayWithKey:@"unit.product.rentalTerms.depositAmount"];
    NSDecimalNumber *maxDeposit = [self costRestriction];
    
    // sum all the rentals curently out and check that their value is < [self costRestriction]

    if([currentDeposit compare:maxDeposit] == NSOrderedDescending) {
        return [NSException validationExceptionWithFormat:@"The total value of the rented goods (%@) exceed %@ limitations (%@).", currentDeposit, [self fullName], maxDeposit];
    }

    return [super validateForSave];  // pass the check on to the EOClassDesciption
}

- (NSString *)description { return [self eoDescription]; }

@end
