//
//  MCSyncAbstractProcessor.h
//  GWSyncServices
//
//  Created by Michael Clark on 05/03/07.
//  Copyright 2007 Marketcircle Inc. All rights reserved.
//

#import <Foundation/Foundation.h>

#import "MCSyncDefines.h"


@class MCPObjectContext;
@class MCFileLogger;
@class ISyncSession;
@class MCSyncAbstractObjectProcessor;
@class MCSyncChange;

@protocol MCSyncManagerProtocol;

@interface MCSyncAbstractProcessor : NSObject {

	@protected
	
	id <MCSyncManagerProtocol>       __syncManagerProxy;
	ISyncSession*                    __syncSession;
	MCPObjectContext*                __objectContext; // Weak reference
	id                               __user; // Weak reference - gotten from objectContext
	MCFileLogger*                    __logger;
	
	BOOL                             __isCurrentSyncBlocking;

	NSString*                        __clientSyncIdentifier;
	NSDictionary*                    __entityGroupConfig;
	NSArray*                         __entityConfigs;

	NSMutableDictionary*             __pushMemory;
	NSMutableArray*                  __pushOrder;
	NSMutableDictionary*             __pullMemory;
	NSMutableArray*                  __pullOrder;
	
	NSMutableDictionary*             __pulledRecordCache; // Storage for pulled changes
	NSMutableDictionary*             __queuedChangeCache; // Storage for processed changes
	NSMutableDictionary*             __syncManagerHandledChangeCache; // Keeps track of the changes that the sync manager will handle
	
	NSMutableDictionary*             __objectProcessors;
	NSMutableDictionary*             __newObjectCache;
	NSMutableDictionary*             __deletedObjectCache;
	
	NSMutableDictionary*             __applicationIDLookUp;
	
	// Used for full record reconstitution 
	NSMutableDictionary*             __pulledAdditionRecords;
	NSMutableDictionary*             __reconstitutedRecords;
}


- (id)initWithSyncManagerProxy: (id <MCSyncManagerProtocol>)manager objectContext: (MCPObjectContext*)anObjectContext entityGroupConfig: (NSDictionary*)config clientSyncIdentifier: (NSString*)syncIdentifier logger: (MCFileLogger*)logger isBlockingSync: (BOOL)isBlocking;

#pragma mark Setup Methods
- (NSArray*)filters;
	// concrete subclasses can override this method to return ISyncFilters which will be set on the sync client before pushing

#pragma mark Object Processors
- (MCSyncAbstractObjectProcessor*)objectProcessorForClassName: (NSString*)className;

#pragma mark Push Methods
- (BOOL)determinePushableEntitiesForSession: (ISyncSession*)session;
	// Goes through the processors entities checking with the session if they should be pushed
	// If no entities can be pushed this method return NO, otherwise if there are records to push this method returns YES

- (void)pushChangesForSession: (ISyncSession*)session;
	// Goes through the entities to be pushed during this session and pushes out any changes necessary

- (void)calculateChangesToPushForSession: (ISyncSession*)session;
    // The concreate subclass of the processor shoudl implement this method
    // Gives the processor a chance to precalculate what records are going to be fetched - can queue them up in a way that the fetch method can get at them
	// (In Daylite temporary tables are created and populate with the primary keys of all the objects that are to be pushed and fetch grabs records based on the primary keys being in the template for their entity)

- (NSArray*)fetchRecordsForEntityNamed: (NSString*)entityName syncMode: (MCSyncMode)syncMode;
	// The concrete subclass of the processor should implement this method
	// Does whatever makes sense for the application syncing - i.e. could fetch from a DB or from an in memory data store, etc.

- (NSArray*)fetchDeleteRecordsForEntityNamed: (NSString*)entityName;
	// The concrete subclass of the processor should implement this method
	// Returns an array of SyncMaps of deleted records that need to be propagated to Sync Services

- (id)transformRecordToSyncServicesRepresentation: (id)record forEntityNamed: (NSString*)entityName;
	// The concrete subclass of the processor should implement this method to transform the application record into a Sync Services representation

- (BOOL)doesApplicationWantToPushRecordsForEntityName: (NSString*)entityName;
	// Allows subclassers the ability to skip an entity all together
	// Default value is YES

- (BOOL)doesApplicationWantToPushAllRecordsForEntityName: (NSString*)entityName;
	// Allows subclassers the ability to force a slow sync if necessary
	// Default value is NO

- (BOOL)doesApplicationWantToResetEntityNamed: (NSString*)entityName;
	// Allows the subclassers the ability to force a refresh sync (which resets the sync client state with SS)
	// Default value is NO

#pragma mark Pull Methods
- (NSArray*)determinePullableEntitiesForSession: (ISyncSession*)session;
	// Goes through the processors entities checking with the session if they should be pulled
	// Returns the array of entities to be pulled, if none are to be pulled then it returns an empty array

- (void)pullChangesForSession: (ISyncSession*)session;
	// Goes through the entities to pull during this session and pulls in any necessary changes

- (void)processChangesForSession: (ISyncSession*)session;
	// Takes all the records that got pulled from SS and queues them up for committing - communicates with the SyncManager to help process

- (void)resolveRelationshipsInChanges: (NSArray*)change forSyncServicesEntityName: (NSString*)entityName;
	// Goes through all the passed in changes and resolves necessary relationship identifiers - default implementation does nothing, subclassers can override this method to do the resolving using the __applicationIDLookUp

- (void)preprocessChanges: (NSArray*)changes forSyncServicesEntityName: (NSString*)entityName;
	// Called before any processing occurs on the pulled changes.  The default implementation does nothing. Subclassers can override this method to do whatever preprocessing is necessary.
	// They can affect the sync in 2 ways by setting the outcome to the change to either ignore or reject.  If they want to continue processing a change the outcome should be unchanged.

- (void)calculateChangesToPushForEntityNamed: (NSString*)entity_name syncMode: (MCSyncMode)syncMode;

- (void)commitChangesForSession: (ISyncSession*)session;
	// Commits any changes pulled and pre-processed

- (void)committingDeleteChange: (MCSyncChange*)change;
	// Allows subclassers the opportunity to do further processing on deletes

- (id)transformRecordToApplicationRepresentation: (id)record recordIdentifier: (NSString*)ssID recordChanges: (NSArray*)change formattedRecord: (NSDictionary**)formattedRecord forEntityNamed: (NSString*)entityName forAddition: (BOOL)flag;
	// The concrete subclass of the processor should implement this method to transform the sync services record into an application representation

- (id)applicationRecordIdentifierForSyncServicesRecord: (id)record entityName: (NSString*)ssEntityName syncServicesRecordIdentifier: (id)ssIdentifier;
	// Gives the concrete subclass a chance to make an application specific record identifier

- (BOOL)doesApplicationWantToPullRecordsForEntityName: (NSString*)entityName;
	// Allows subclassers the ability to skip an entity all together
	// Default value is YES

- (BOOL)doesApplicationWantToForceFollowUpSync;
	// Allows subclassers the ability to force a follow up sync once the current sync is complete.
	// Default value is NO

- (id)reconstitutedRecordForChange: (MCSyncChange*)change;
	// Subclasses need to implement this method because it needs to know specific details about records, i.e. for a contact it needs to know which relationships to resolve

- (void)willBeginSync;
- (void)didFinishSync;
	// Subclassers can override these to do special logic (i.e. record the last sync date somewhere, etc.)

- (void)willBeginPushingEntityNamed: (NSString*)entityName;
- (void)didFinishPushingEntityNamed: (NSString*)entityName completedSuccessfully: (BOOL)flag;
	// Subclassers can override these to do special logic (i.e. record the last sync date somewhere, etc.)

- (void)willBeginPullingEntityNamed: (NSString*)entityName;
- (void)didFinishPullingEntityNamed: (NSString*)entityName completedSuccessfully: (BOOL)flag;
	// Subclassers can override these to do special logic (i.e. record the last sync date somewhere, etc.)


#pragma mark Accessors
- (NSDictionary*)entityConfigForSyncServicesEntityName: (NSString*)ssEntityName;
- (NSString*)applicationEntityNameForSyncServicesEntityName: (NSString*)ss_entity_name record: (NSDictionary*)record syncServicesRecordIdentifier: (NSString*)identifier;
- (NSArray *)entityConfigs;
- (void)setEntityConfigs:(NSArray *)anEntityConfigs;

- (ISyncSession*)syncSession;
- (void)setSyncSession: (ISyncSession*)aSession;

@end
