//
//  MCPEntity.h
//  MCPersistence
//
//  Created by aj on Fri Dec 21 2001.
//  Copyright (c) 2001 __MyCompanyName__. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "MCPDefines.h"
#import "MCPDefinitionObject.h"



extern NSString*    MCPDefaultJoinEOClassName;


@class MCPModel, MCPFetchSpecification, MCPObject;
@class MCPRelationship;
@class MCPAttribute, MCPRelationship;

@interface MCPEntity : MCPDefinitionObject {

	NSNumber                *_uniqueID;
	NSMutableArray*          _attributes;
	NSMutableDictionary		*_attributesByName;
	NSMutableArray			*_orderedAttributes;
	NSMutableDictionary		*_attributesByColumnName;
	
	NSMutableDictionary*     _columnAttributeLookup;
	NSMutableDictionary*     _columnTypeCoersionLookup;  // Used to pass to database adaptor for ambiguous internal types - an external type can map to several internal types (only object (blob) at the moment which can map to NSData or NSString)

	NSMutableArray*          _relationships;
	NSMutableDictionary		*_relationshipsByName;
	NSMutableDictionary		*_relationshipByDestinationName;
	NSMutableDictionary		*_fetchSpecifications;
	
	NSMutableArray			*_primaryKeyAttributes;
	NSMutableArray			*_nonPrimaryKeyAttributeNames;
	NSMutableArray			*_nonPrimaryKeyNonForeignKeyAttributeNames;
	NSArray					*_foreignKeyAttributes;
	NSMutableArray			*_foreignKeyAttributeNames;
	NSMutableDictionary     *_foreignKeyRelationshipLookUp;
	
	NSMutableArray			*_flattenedToManyRelationships;
	NSMutableArray			*_ownedRelationships;
	NSDictionary            *_inverseOneSidedRelationships;

	NSString				*_var;
	
	MCPModel				*_model;
	
	Class					_InstanceClassToCreate;

    MCPSupportedPlatforms   _supportedPlatforms; // All, Desktop only, Touch only
    NSString*               _supportedProduct;
	
}

// removes obj from objects that point back to it, but does not remove the object objects from obj. Does to-many's and to-one's -- ignoring intermediates. Uses removeObject:fromRelationshipWithKey: so the object context is alerted and it typically sends notifications
+ (void)verboseRemoveObjectFromInverseRelationships:(id)obj;


// The model this entity belongs to
- (void)setModel:(MCPModel *)aModel;
- (MCPModel *)model;

// Should not be mutated!  It is generated automatically by MCModeler on Entity creation
- (NSNumber *)uniqueIdentifier;


- (NSArray *)attributes;
// primary key first, then the rest
- (NSArray *)orderedAttributes; 
- (NSArray *)attributeNames;
- (id)attributeForName:(NSString *)aName;
- (id)attributeForColumnName:(NSString *)aName;

- (NSDictionary*)columnAttributeLookup;
- (NSDictionary*)columnTypeCoersionLookup;

- (NSArray*)columnNames;

- (NSArray *)primaryKeyAttributeNames;
- (void)setPrimaryKeyAttributeNames: (NSArray*)names;
- (NSArray *)primaryKeyAttributes;
- (BOOL)isPrimaryKeyAttributeName:(NSString *)aName;

- (NSArray *)foreignKeyAttributes;
- (NSArray *)foreignKeyAttributeNames;

- (NSArray *)nonPrimaryKeyAttributeNames;
- (NSArray *)nonPrimaryKeyNonForeignKeyAttributeNames;

- (MCPRelationship*)relationshipForForeignKeyAttributeName: (NSString*)aName;

- (NSString *)classname;
- (void) setClassname:(NSString *)class;
- (NSArray *)classProperties;
- (NSString *)externalName;
- (void)setExternalName:(NSString *)external;
- (NSString *)name;
- (void) setName:(NSString *)name;

- (BOOL)isIntermediate;
- (void)setIsIntermediate: (BOOL)flag;

- (MCPSupportedPlatforms)supportedPlatforms;
- (void)setSupportedPlatforms:(MCPSupportedPlatforms)aVal;

- (NSString*)supportedProduct;
- (void)setSupportedProduct: (NSString*)aProduct;

- (void)cacheDerivedValuesForRelationships;

// Returns self if the keyPath is a single key which is an attribute on the receiver
- (MCPEntity*)destinationEntityForKeyPath: (NSString*)keyPath;

- (NSArray *)relationships;
- (id)relationshipForName:(NSString *)aName;
- (NSArray *)relationshipsForDestinationName:(NSString *)aName;

- (NSArray *)flattenedToManyRelationships;
- (NSArray *)ownedRelationships;

- (id)toManyRelationshipForDestinationEntity:(MCPEntity *)ent;
- (id)flattenedToManyRelationshipForDestinationEntity:(MCPEntity *)ent;

- (void)loadFetchSpecificationsInSerializedData:(NSData *)data;

- (MCPFetchSpecification *)fetchSpecificationForName:(NSString *)aName;
- (void)addFetchSpecification:(MCPFetchSpecification *)fetch withName:(NSString *)aName;

- (MCPFetchSpecification *)fetchSpecificationForName:(NSString *)aName bindings:(NSDictionary *)bindings;



// Return YES if the passed in property is a class property for this entity
- (BOOL)isPropertyClassProperty: (NSString *)aProperty;

- (BOOL)isIntermediate;
- (void)setIsIntermediate: (BOOL)flag;


// This is the designated way to create objects for this entity. If the classname is null or if the classname cannot be found in the runtime, an autoreleased MCPGenericObject is created and returned.
// This method should be used for objects that are fetched from the database and for the creation of entirely new object (insert). Only the entity is set. The primary key is not set!
- (id)createBlankInstanceInZone:(NSZone *)zone;


- (NSString *)primaryKeyValuesAsStringForRawRow:(NSDictionary *)raw;
- (NSString *)primaryKeyValuesAsStringForRawRowColumn:(NSDictionary *)raw;
- (NSString *)primaryKeyValuesAsStringForObject:(MCPObject *)obj;
- (NSString *)primaryKeyStringWithValue:(id)val;

/*!
    @method     valueAttributeKeys
    @abstract   returns all of the keys which are directly related to the object and are not associated with a relationship.  The primary key attribute name IS NOT included in this array.
    @discussion (comprehensive description)
    @result     returns a list of keys (strings)
*/
- (NSArray*)valueAttributeKeys;

- (NSArray*)blobColumnKeys;
- (NSArray*)blobAttributeKeys;

/*!
    @method     toOneRelationshipKeys
    @abstract   returns all of the keys which are toOne relationships
    @discussion (comprehensive description)
    @result     returns a list of keys (strings)
*/
- (NSArray*)toOneRelationshipKeys;

/*!
    @method     toManyRelationshipKeys
    @abstract   returns all of the keys which are toMany relationships
    @discussion (comprehensive description)
    @result     returns a list of keys (strings)
*/
- (NSArray*)toManyRelationshipKeys;

- (NSArray*)toOneRelationships;
- (NSArray*)toManyRelationships;

- (MCPRelationship*)relationshipForKey:(NSString*)aKey;

/*!
 @method     inverseOneSidedRelationshipAttributeNames
 @abstract   returns a cached dictionary of arrays of attributes for which we are the destination, but for which we lack a corresponding inverse.
 @discussion lazily scans all relationships in the model looking for references to us, but for which do not have a corresponding inverse relationship.
 @result     a dictionary of arrays of names of attributes, keyed by the name of the entity to whom those attributes belong.
 */
- (NSDictionary *)inverseOneSidedRelationshipAttributeNames;


#pragma mark Localization
- (NSString *)localizedEntityName;
- (NSString *)localizedPluralEntityName;



#pragma mark Entity Editing Support
- (MCPAttribute *)createAndAddAttribute;
- (void)removeAttribute: (MCPAttribute*)attribute;

- (MCPRelationship *)createAndAddRelationship;
- (void)removeRelationship: (MCPRelationship*)relationship;

- (void)addToPrimaryKeyAttributes:(MCPAttribute *)anAttr;
- (void)removeFromPrimaryKeyAttributes:(MCPAttribute *)anAttr;

-(BOOL) writeToFile:(NSString*)path;


#pragma mark MCEOGenerator Support
- (NSArray*)referencedClassNames;
   // Returns the set of referenced class name as an array
- (NSArray*)nonIntermediateToManyRelationships;
   // Goes through the toManyRelationships and removes any that are intermediate
- (NSString*)referenceProtocolOrClassName;
   // Returns type information, ie the class name plus the *, or just id
@end
