#import "<%=header%>"
#import <objc/runtime.h>


<%classes.each do |klass|%>
//////////////////////////////////////////////////////////////////////////////
//// <%= klass.objc_class %>
//////////////////////////////////////////////////////////////////////////////
@implementation <%= klass.objc_class %>

+ (RKObjectMapping *) mapperForParsing
{
    return [[RKObjectManager sharedManager].mappingProvider objectMappingForClass:self];
}

+ (RKObjectMapping *) mapperForSerializing
{
    return [[RKObjectManager sharedManager].mappingProvider serializationMappingForClass:self];
}

<%klass.properties.each do |property|%>
@synthesize <%= property.name %>;
<%end%>

+ (void)initialize{
  [self initializeMapping];
<%if klass.resource%>
  [self initializeRouting];
<%end%>
<%if klass.cached?%>
  (void)[self initializeCoreData];
<%end%>
}

- (NSString*)description
{
    RKObjectMapping * mapper = [[RKObjectManager sharedManager].mappingProvider serializationMappingForClass:[self class]];
    RKObjectSerializer * serializer = [RKObjectSerializer serializerWithObject:self mapping:mapper];

    NSError * error;
    NSString * description = (NSString *)[serializer serializedObjectForMIMEType:RKMIMETypeJSON error: &error];
    return [description stringByReplacingOccurrencesOfString:@"\"" withString:@"'"];
}

<%if klass.cached? %>
+ (NSEntityDescription * )initializeCoreData
{
    static NSEntityDescription * entity;
    if(entity){
       return entity;
    }
    entity = [[NSEntityDescription alloc] init];
    entity.name = @"<%=klass.objc_class%>";
    entity.managedObjectClassName = @"<%=klass.objc_class%>";

    // -------------------------------------------
    // Define the properties mappings
    NSMutableArray * properties = [NSMutableArray array];
<%klass.primitive_properties.each do |property|%>
    {
        // <%= property.name %>
        NSAttributeDescription * attrDesc = [[NSAttributeDescription alloc] init];
        attrDesc.name = @"<%= property.name %>";
        [attrDesc setAttributeType:<%= property.ns_attribute_type %>];
        [attrDesc setOptional:NO];
        [properties addObject:attrDesc];
    }
<%end%>

    // ----------------------------------------------
    // Define 'has one' relationships
    // ----------------------------------------------
<%klass.has_one_properties.each do |property|%> 
    { 
      // <%= property.name %>
      NSRelationshipDescription * relDesc = [[NSRelationshipDescription alloc] init];
      [relDesc setDestinationEntity:[<%=property.klass.objc_class%> initializeCoreData]];
      relDesc.name = @"<%= property.name %>";
      relDesc.minCount = 1;
      relDesc.maxCount = 1;
      relDesc.deleteRule = NSCascadeDeleteRule;
      [properties addObject:relDesc];
    }
<%end%>

    // ----------------------------------------------
    // Define 'has many' objects relationships
    // ----------------------------------------------
<%klass.has_many_maps_properties.each do |property|%> 
    { 
      // <%= property.name %>
      NSRelationshipDescription * relDesc = [[NSRelationshipDescription alloc] init];
      relDesc.name = @"<%= property.name %>";
      // Sequence of core data objects
      [relDesc setDestinationEntity:[<%=property.klass.item_class.objc_class%> initializeCoreData]];
      relDesc.deleteRule = NSCascadeDeleteRule;
      [properties addObject:relDesc];
    }
<%end%>

    // ----------------------------------------------
    // Define 'has many' primitves relationships
    // ----------------------------------------------
<%klass.has_many_maps_properties.each do |property|%> 
    { 
      // Sequence of primitives
      // This is really a sequence of primitive
#warning <%= property.name %> is a sequence of primitive
    }
<%end%>

    [entity setProperties:properties];
    return entity;
}
<%end%>


+ (void)initializeMapping{
    RKObjectMapping* mapping = [RKObjectMapping mappingForClass:[<%=klass.objc_class%> class]];

    // -------------------------------------------
    // Define 'primitive' properties mappings
    // ----------------------------------------------
<%klass.primitive_properties.each do |property|%> 
    [mapping mapKeyPath:@"<%=property.name%>" toAttribute:@"<%=property.name%>"];
<%end%>
<%klass.has_many_primitives_properties.each do |property|%> 
    // NSArray of <%= property.klass.item_class.objc_class %>
    [mapping mapKeyPath:@"<%=property.name%>" toAttribute:@"<%=property.name%>"];
<%end%>

    // ----------------------------------------------
    // Define 'has one' relationships
    // ----------------------------------------------
<%klass.has_one_properties.each do |property|%> 
    { 
        // <%= property.name %>
        RKObjectMapping * mapper = [[RKObjectManager sharedManager].mappingProvider 
            objectMappingForClass:[<%=property.klass.objc_class%> class]];
        [mapping hasOne:@"<%=property.name%>" withMapping:mapper];
    }
<%end%>

    // ----------------------------------------------
    // Define 'has many' relationships
    // ----------------------------------------------
<%klass.has_many_maps_properties.each do |property|%> 
    { 
        RKObjectMapping * mapper = [[RKObjectManager sharedManager].mappingProvider 
            objectMappingForClass:[<%=property.klass.item_class.objc_class%> class]];
        [mapping hasMany:@"<%=property.name%>" withMapping:mapper];
    }
<%end%>

    // -------------------------------------------
    // Register the mapper for the class
    [[RKObjectManager sharedManager].mappingProvider addObjectMapping:mapping];

    // -------------------------------------------
    // Register the serializer for the class
    [[RKObjectManager sharedManager].mappingProvider setSerializationMapping:[mapping inverseMapping] forClass:[<%=klass.objc_class%> class] ];
}

<%if klass.resource%>
+ (NSString *) resourcePath {
  return @"<%= klass.resource.hash[:resource] %>";
}

+ (void)initializeRouting{
    RKObjectRouter * router = [RKObjectManager sharedManager].router;
    
    NSString * collectionResource = [self resourcePath];
<%if klass.resource.singleton?%>
    NSString * objectResource = collectionResource;
<%else%>
    NSString * objectResource = [NSString stringWithFormat:@"%@/:id", collectionResource];
<%end%>

<%if klass.resource.create?%>
    [router routeClass:self toResourcePath:collectionResource forMethod:RKRequestMethodPOST];
<%end%>
<%if klass.resource.read?%>
    [router routeClass:self toResourcePath:objectResource forMethod:RKRequestMethodGET];
<%end%>
<%if klass.resource.update?%>
    [router routeClass:self toResourcePath:objectResource forMethod:RKRequestMethodPUT];
<%end%>
<%if klass.resource.delete?%>
    [router routeClass:self toResourcePath:objectResource forMethod:RKRequestMethodDELETE];
<%end%>

}

- (BOOL)isNew
{
<%if klass.resource.singleton?%>
	return NO;
<%else%>
    return [self valueForKey:@"id"] == NULL;
<%end%>
}

-(void) saveWithDelegate:(id<RKObjectLoaderDelegate>)delegate
{
    RKObjectMapping * mapper = [[RKObjectManager sharedManager].mappingProvider objectMappingForClass:[self class]];

<%if klass.resource.singleton?%>
	[[RKObjectManager sharedManager] putObject:self mapResponseWith:mapper delegate:delegate];
<%else%>
    if ([self isNew])
    {
        [[RKObjectManager sharedManager] postObject:self mapResponseWith:mapper delegate:delegate];
    }else{
        [[RKObjectManager sharedManager] putObject:self mapResponseWith:mapper delegate:delegate];
    }
<%end%>
    
}

- (void)deleteWithDelegate:(id<RKObjectLoaderDelegate>)delegate
{
    RKObjectMapping * mapper = [[RKObjectManager sharedManager].mappingProvider objectMappingForClass:[self class]];
    [[RKObjectManager sharedManager] deleteObject:self mapResponseWith:mapper delegate:delegate];
}

+ (void) loadItem:(NSNumber *)id 
     withDelegate:(id<RKObjectLoaderDelegate>)delegate;
{
    RKObjectMapping * mapper = [[RKObjectManager sharedManager].mappingProvider objectMappingForClass:[self class]];

    <%= klass.objc_class%> * instance = [[self alloc] init];
    [instance setValue:id forKey:@"id"];
    [[RKObjectManager sharedManager] getObject:instance 
                               mapResponseWith:mapper
                                      delegate:delegate];
}

// Load collection
+ (void) loadCollectionWithDelegate:(id<RKObjectLoaderDelegate>)delegate
{
    RKObjectManager * objectManager = [RKObjectManager sharedManager];
    RKObjectMapping * mapping = [objectManager.mappingProvider 
                                 objectMappingForClass:self ];
    
    [objectManager loadObjectsAtResourcePath:[self resourcePath] 
                               objectMapping:mapping 
                                    delegate:delegate];
}


// Load collection with query
+ (void) loadCollectionThroughQuery:(NSObject *)mappableQueryObject 
                       withDelegate:(id<RKObjectLoaderDelegate>)delegate
{
    
    RKObjectManager * objectManager = [RKObjectManager sharedManager];
    RKObjectMapping * mapping = [objectManager.mappingProvider
                                 objectMappingForClass:self ];
    
    
    // Append the dictionary to the resource as query parameters
    NSString * resourcePath = RKPathAppendQueryParams([self resourcePath], convertToDictionary(mappableQueryObject));
    
    // Load the objects at the query
    [objectManager loadObjectsAtResourcePath:resourcePath 
                               objectMapping:mapping 
                                    delegate:delegate];
}
<%end%>

// <%=klass.objc_class%> convenience builder.
// Note that +id+ field if present is not set by this
// builder and so can be used to construct a *new* object
+ (<%=klass.objc_class%> *)buildWith_<%=klass.objc_properites_arg_list_decl%>
{
  <%=klass.objc_class%> * object = [[<%=klass.objc_class%> alloc] init];
<%klass.properties.reject{|p|p.name=='id'}.each do |property|%>
  object.<%=property.name%> = <%=property.name%>;
<%end%>
return object;
}


// Deep Copy
- (id) copyWithZone : (NSZone * ) zone
{
  <%=klass.objc_class%> * object = [[<%=klass.objc_class%> allocWithZone:zone] init];
<%klass.properties.each do |property|%>
  object.<%=property.name%> = [self.<%=property.name%> copy];
<%end%>
  return object;
}


@end

<%end%>




NSMutableArray * entities(){
static NSMutableArray * _entities = nil;
    if(!_entities){
        _entities = [[NSMutableArray alloc] init];
<%classes.each do |klass|%>
<%if klass.cached? %>
        [_entities addObject:[<%=klass.objc_class%> initializeCoreData]];
<%end%>
<%end%>
    }
    return _entities;
}

NSManagedObjectModel * managedObjectModel(){
    static NSManagedObjectModel *mom = nil;
 
    if (mom != nil) {
        return mom;
    }
    
    mom = [[NSManagedObjectModel alloc] init];
    [mom setEntities:entities()];

    return mom;

}