//
//  SFManagedObjectContext.h
//  TimeLog5
//
//  Created by Stefan Fuerst on 07.10.11.
//  Copyright (c) 2011 __MyCompanyName__. All rights reserved.
//

#import <CoreData/CoreData.h>

#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#endif

typedef enum {
    FSManagedObjectContextFailedSyncRepositoriesCantBeMergedReason  = -1,
    FSManagedObjectContextFailedSyncRepositoryModelsDeferReason     = -2,
    FSManagedObjectContextFailedSyncRepositoryResetFailedReason     = -3,
} FSManagedObjectContextFailedSyncReason;

extern NSString* FSManagedObjectContextDidStartSyncingNotification;
extern NSString* FSManagedObjectContextDidEndSyncingNotification;
extern NSString* FSManagedObjectContextDidSaveAfterSyncNotification;
extern NSString* FSManagedObjectContextDidMergeExternalChangesNotification;
extern NSString* FSManagedObjectContextDidFailNotification; // userInfo[reason] == failure reason number

@class FSConnection;

@protocol FSManagedObjectContextDelegate;

@interface FSManagedObjectContext : NSManagedObjectContext

- (id) initWithConcurrencyType:(NSManagedObjectContextConcurrencyType)ct syncIdentifier:(NSString*)syncIdentifier;

@property (weak) id<FSManagedObjectContextDelegate> fsDelegate;
@property (nonatomic, strong) FSConnection* connection;
@property (readonly, strong) NSString* syncIdentifier;
@property (readonly, getter = isSyncing) BOOL syncing;
@property (readonly, getter = isRestoring) BOOL restoring;
@property (nonatomic, readonly) NSDate* lastSyncDate;
@property BOOL loggingDisabled;

- (NSInteger) syncVersion;

- (BOOL) saveAndSync:(BOOL)sync error:(NSError**)error;
- (void) saveAndSync:(BOOL)sync;
- (BOOL) initialSaveError:(NSError**)error;
- (void) sync;

/* Repository Management */
- (void) deleteAllDataCompletion:(void(^)())completion;
- (void) createNewRepositoryCompletion:(void(^)())completion;
- (void) advanceToMostRecentRepositoryCompletion:(void(^)())completion;
- (void) restoreFromRepositoryCompletion:(void(^)())completion;
- (void) restoreFromDate:(NSDate *)theDate completion:(void(^)())completion;
- (NSString *) cacheKeyForEntityName:(NSString *)entityName andUID:(NSString *)theUID;

-(NSArray *)updatesDictionary;
-(NSArray *)deletesDictionary;
-(NSArray *)insertsDictionary;


-(BOOL)insertDictionary:(NSDictionary *)theDictionary inManagedObjectContext:(NSManagedObjectContext *)syncContext create:(BOOL)create;
-(void)linkDictionary:(NSDictionary *)theDictionary inManagedObjectContext:(NSManagedObjectContext *)syncContext;



- (dispatch_queue_t) syncBackgroundQueue;


/* checking device infos */
extern NSString* kDeviceInfoName;
extern NSString* kDeviceInfoSyncVersion;
extern NSString* kDeviceInfoDataVersion;
extern NSString* kDeviceInfoMachine;
extern NSString* kDeviceInfoModel;

- (NSArray*) knownDevices;
- (NSDictionary*) deviceInfoForDevice:(NSString*)device;
@end


@protocol FSManagedObjectContextDelegate <NSObject>
@optional
- (void) managedObjectContext:(FSManagedObjectContext*)context didFailWithReason:(FSManagedObjectContextFailedSyncReason)reason userInfo:(id)userInfo;
- (void) managedObjectContextWillCreateNewRepository:(NSManagedObjectContext*)context;
- (void) managedObjectContextDidCreateNewRepository:(NSManagedObjectContext*)context;
- (void) managedObjectContextWillDeleteAllData:(NSManagedObjectContext*)context;
- (void) managedObjectContextDidDeleteAllData:(NSManagedObjectContext*)context;
- (BOOL) managedObjectContextShouldSyncWithRemote:(NSManagedObjectContext*)context;

// returns on merge thread which is different from the main thread
// make sure you're not using core data objects from the main object context!
- (void) managedObjectContext:(NSManagedObjectContext*)context willMergeObjectWithManagedObject:(NSManagedObject*)object insert:(BOOL)insert changes:(NSDictionary*)changes;
- (void) managedObjectContext:(NSManagedObjectContext*)context didMergeObjectWithManagedObject:(NSManagedObject*)object insert:(BOOL)insert changes:(NSDictionary*)changes;
@end

