//
//  MCChangeSet.h
//  MCServerSupport
//
//  Created by Brent Gulanowski on 03/04/08.
//  Copyright 2008 Marketcircle, Inc. All rights reserved.
//

#import "MCChangeRecord.h"


@class MCSQLiteContext, MCSQLiteResultSet;

@interface MCChangeSet : NSObject {
	
	MCSQLiteContext *db;
	
	NSURL *dbURL;	
	NSString *uuid;
	NSString *parentID;
	NSString *serverID;
	NSString *clientID;
	unsigned version; // I don't really know what this is yet
	
	NSDate *creationDate;
	
	BOOL hasAttachedDB;
}

+ (NSString *)fileExtension;


@property (nonatomic, readonly, retain) MCSQLiteContext *db;
@property (nonatomic, readonly, copy) NSURL *dbURL;
@property (nonatomic, readonly, copy) NSString *uuid;
@property (nonatomic, readonly, copy) NSString *parentID;
@property (nonatomic, readonly, copy) NSString *serverID;
@property (nonatomic, readonly, copy) NSString *clientID;
@property (nonatomic, readonly) unsigned version;
@property (nonatomic, readonly, copy) NSDate *creationDate;

- (NSDate *)lastModifiedDate;
- (BOOL)hasChanges;

// @throws NSInvalidArgumentException if there is no database at the given URL, if the URL is not a file:// type URL,
// or if the database does not have a UUID set
- (id)initWithExistingDatabaseURL:(NSURL *)aURL;
// @throws NSInvalidArgumentException if there is a file in the way, or if the URL is not a file:// type URL,
// or if either serverUUID or clientUUID are nil
// @throws NSInernalInconsistencyException if it cannot create a new database UUID (thrown by +createUUID),
// of if the database cannot be initialized (cannot find the schema script)
- (id)initWithNewDatabaseURL:(NSURL *)aURL
					parentID:(NSString *)parentUUID
					serverID:(NSString *)serverUUID
					clientID:(NSString *)clientUUID
					 version:(unsigned)aVersion;
- (id)initWithNewDatabaseURL:(NSURL *)aURL
					serverID:(NSString *)serverUUID
					clientID:(NSString *)clientUUID
					 version:(unsigned)aVersion;

- (BOOL)isEqualToChangeSet:(MCChangeSet *)otherSet;

// @throws if unabled to generate a new UUID string
+ (NSString *)createUUID;
+ (BOOL)moveChangeSet:(MCChangeSet *)aSet toFolder:(NSString *)folderPath;

// to coalesce means to look for existing changes for the specified table and remove conflicts/redundancies
// @throws NSInvalidArgumentException for an invalid type or if any of aName, aKey or aDate are nil
- (MCChangeRecord *)addChangeWithType:(MCChangeRecordType)aType
							tableName:(NSString *)aName
						   primaryKey:(NSString *)aKey
							timeStamp:(NSDate *)aDate
							   fields:(NSDictionary *)theFields
							 coalesce:(BOOL)coalesce;
- (MCChangeRecord *)addChangeWithType:(MCChangeRecordType)aType
							tableName:(NSString *)aName
						   primaryKey:(NSString *)aKey
							timeStamp:(NSDate *)aDate
							   fields:(NSDictionary *)theFields; // coalesce is YES

- (void)addChangeRecord:(MCChangeRecord *)aChange coalesce:(BOOL)coalesce;
- (void)addChangeRecord:(MCChangeRecord *)aChange; // coalesce = YES

// the change record must already exist in this change set
- (void)removeChangeRecord:(MCChangeRecord *)aChange;

- (void)coalesceRecordsForTableName:(NSString *)tableName primaryKey:(NSString *)primaryKey;
- (void)coalesceAllRecords;

- (NSArray *)namesOfChangedEntities;
- (NSArray *)changeRecords;
- (MCSQLiteResultSet *)changeRecordsResultSet;
- (NSArray *)changeRecordsForTableName:(NSString *)aName; // all of them
- (NSArray *)changeRecordsForTableName:(NSString *)aName
							  fromDate:(NSDate *)firstChange
							 untilDate:(NSDate *)lastChange;

// In the following two methods, "name" and "primaryKey" may be nil
- (NSArray *)changeRecordsForTableName:(NSString *)name
							primaryKey:(NSString *)primaryKey;
- (NSArray *)changeRecordsForTableName:(NSString *)name
							primaryKey:(NSString *)primaryKey
								  type:(MCChangeRecordType)aType;

- (NSArray *)changeRecordsForType:(MCChangeRecordType)aType;

- (long)countOfChangeRecordsForTableName:(NSString *)name
							  primaryKey:(NSString *)primaryKey
									type:(MCChangeRecordType)aType;
- (long)countOfChangeRecords;

- (NSString *)changeDescription:(BOOL)showFields;
- (NSString *)changeDescription;

// @throws MCSqliteErrorException if the attach fails
- (void)appendChangeSet:(MCChangeSet *)newChanges coalesce:(BOOL)flag;
+ (void)logReconcileDetails:(BOOL)flag;
- (void)reconcileWithChangeSet:(MCChangeSet *)otherSet resultSet:(MCChangeSet *)resultSet;

// convenience for transporting extra values (NSNull or nil as a value will clear the entry)
- (BOOL)supportsKeyValuePairs;
- (void)setStringValue:(NSString *)string forKey:(NSString *)key;
- (NSString *)stringValueForKey:(NSString *)key;
- (NSArray *)allStringKeysAndValues;

@end

@interface MCChangeRecord (MCChangeSetAdditions)
// @throws NSInvalidArgumentException if uuid is nil
- (NSDictionary *)dictionaryWithUUID:(NSString *)uuid;

@end

