//
//  MCPGServer.h
//  MCPostgresPersistence
//
//  Created by Michael Clark on 11/09/08.
//  Copyright 2008 Marketcircle Inc.. All rights reserved.
//

#import "MCPGCoreServer.h"

@class MCBackupSchedule;
@class MCPGDatabase;
@class MCMailerSettings;
@class MCDaemonKeeper;

// NSUserDefaults Keys
extern NSString* kMCPGServerNoCleanUpUserDefaultKey;


extern NSString *kMCPGOfflineDatabaseNameSuffix;
extern NSString* kMCPGMirrorDatabaseNameSuffix;


// Database Record Keys
extern NSString* kMCPGServerDatabaseNameKey;
extern NSString* kMCPGServerDatabaseSizeKey;
extern NSString* kMCPGServerDatabaseLastBackupDateKey;

extern NSString* kMCPGServerIsValidFlagKey;
extern NSString* kMCPGServerUUIDKey;
extern NSString* kMCPGServerPublicAddressKey;
extern NSString* kMCPGServerPrivateAddressKey;
extern NSString* kMCPGServerDatabaseUUIDKey;
extern NSString* kMCPGServerDatabaseNumUsersKey;
extern NSString* kMCPGServerDatabaseActiveUsersKey;
extern NSString* kMCPGServerDatabaseUsersStringKey;
extern NSString* kMCPGServerDatabaseTypeKey;
extern NSString* kMCPGServerDatabaseActiveFlagKey;
extern NSString* kMCPGServerDatabaseSchemaKey;
extern NSString* kMCPGServerDatabaseLastSyncDateKey;

extern NSString* kMCPGBackupDatabaseNameKey;
extern NSString* kMCPGBackupDatabaseUUIDKey;
extern NSString* kMCPGBackupDatabaseSchemaKey;
extern NSString* kMCPGBackupDatabaseEncodingKey;
extern NSString* kMCPGBackupDatabaseTypeKey;

//Database Replicant keys
extern NSString* kMCPGServerDatabaseOfflinesArrayKey;
extern NSString* kMCPGServerDatabaseOfflineNameKey;
extern NSString* kMCPGServerDatabaseOfflineLastSyncDateKey;
extern NSString* kMCPGServerDatabaseOfflineUserNameKey;
extern NSString* kMCPGServerDatabaseOfflineIdentifierKey;
extern NSString* kMCPGServerDatabaseOfflineOffsetIDKey;
extern NSString* kMCPGServerDatabaseOfflineStatusCodeKey;
extern NSString* kMCPGServerDatabaseOfflineStatusStringKey;


// Connected Users Record Keys
extern NSString* kMCPGServerConnectedUserUsernameKey;
extern NSString* kMCPGServerConnectedUserDatabaseNameKey;
extern NSString* kMCPGServerConnectedUserProductCodeKey;
extern NSString* kMCPGServerConnectedUserOfflineStatusKey;


#pragma mark -
#pragma mark License Record Keys
extern NSString* kMCPGServerLicenseIDKey;
extern NSString* kMCPGServerLicenseLicenseCodeKey;
extern NSString* kMCPGServerLicenseSerialCodeKey;
extern NSString* kMCPGServerLicenseProductNameKey;
extern NSString* kMCPGServerLicenseSeatsKey;
extern NSString* kMCPGServerLicenseExpiryDateKey;


extern NSDictionary*      kMCPGServerProductCodeMapping;
extern NSDictionary*      kMCPGServerVersionMapping; // Maps product code to version string
extern NSDictionary*      kMCPGServerLicenseBundleMapping; // Maps product code to real product codes - for bundles like DP = DL and DM
extern NSCalendarDate*    kMCPGServerLicenseNoEndDateDate;  // Used to flag what should be interpreted as the product never expiring
extern NSArray*           kMCPGServerInvalidLicenses;
#define kMCPGServerLicenseUpgradeFeature 64


// ServerType type
typedef enum  {
	MCPGSharedServerType   = 1,
	MCPGPersonalServerType,
	MCPGHostedServerType
} MCPGServerType;

typedef enum {
	MCPGFSyncWritethroughStateDisabled = 0,
	MCPGFSyncWritethroughStateEnabled
} MCPGServerFSyncState;


// Connection Creation
// For the following functions the flag argument is treated as:
//   If flag == YES, then this connection will be an admin connection
//   If flag == NO, then this connection will be a non admin connection (note non admin connections do not work currently)
extern MCPGDatabase*  MCPGDatabaseConnection(NSString* host, NSNumber* port, NSString* databaseName, NSString* databaseSchema, NSString* userName, NSString* password, NSError** error);

// If nil is passed for databaseName and flag == YES then the default admin DB name will be substituted in
@class MCPGServer;
extern MCPGDatabase*  MCPGServerDatabaseConnection(MCPGServer* server, NSString* databaseName, BOOL flag, NSError** error);


// Password Callbacks
//  These callbacks should be implemented by the subclasser of the MCPGServer class and pointers to the callbacks need to be setup in the settings structure
typedef void (*MCPGServerSuperUserCredentialGenerationCallBack) (NSString** full, NSString** publicPiece);
typedef void (*MCPGServerBasicUserCredentialGenerationCallBack) (NSString** full, NSString** publicPiece);
typedef void (*MCPGServerSuperUserPublicPasswordCallBack) (void* sets, NSString** publicPW);
typedef void (*MCPGServerSuperUserPasswordCallBack) (void* sets, NSString** pw);
typedef void (*MCPGServerBasicUserPublicPasswordCallBack) (void* sets, NSString** publicPW);
typedef void (*MCPGServerBasicUserPasswordCallBack) (void* sets, NSString** pw);

typedef struct _MCPGPasswordCallBacks {
	MCPGServerSuperUserCredentialGenerationCallBack     superGeneration;
	MCPGServerBasicUserCredentialGenerationCallBack     basicGeneration;
	
	MCPGServerSuperUserPublicPasswordCallBack           superPublic;
	MCPGServerSuperUserPasswordCallBack                 superPW;
	
	MCPGServerBasicUserPublicPasswordCallBack           basicPublic;
	MCPGServerBasicUserPasswordCallBack                 basicPW;
} MCPGPasswordCallBacks;

typedef struct _MCPGServerLogs {
	NSString*    databaseLogFile;
	
} MCPGServerLogs;

typedef struct _MCPGServerModelSettings {
    NSString*   userTableName;
    NSString*   userNameColumnName;
    
} MCPGServerModelSettings;

typedef struct _MCPGServerSQLScriptSettings {
    NSString*   schemaScriptName;
    NSString*   createChangeLogTriggersScriptName;
    NSString*   dropChangeLogTriggersScriptName;
    NSString*   resetChangeLogTriggersScriptName;
    NSString*   dropCacheValuesChangeLogTriggersScriptName;
} MCPGServerSQLScriptSettings;

typedef struct _MCPGEmailSettings {
	NSString*   fromEmailAddress;
	NSString*   emailSubject;
	NSString*   testEmailSubject;
	NSString*   testEmailBody;
} MCPGEmailSettings;

typedef struct _MCPGDaemonSettings {
	NSDictionary *ports;
	NSString * listenIP;
} MCPGDaemonSettings;



// Structure to hold settings information
// NOTE: If you add additional fields to the settings structures ADD them to the logServerSettings method on MCPGServer
typedef struct _MCPGServerSettings {
	MCPGServerType			serverType;
	NSString*				serverUUID; // Used for the hosted version
	
	NSString*               rootStoragePath;
	NSString*               dataPath;
	NSString*               localHost; // used only for personal to hard wire the PG stuff to use our relocated unix socket file
	MCPGDataPathSettings    dataPathSettings;
	NSString*               supportFilesPath;
	NSString*               defaultBackupPath;
	NSString*               defaultBackupExtension;
	NSString*               logFilesFolder; // Path to where log files are stored
	NSNumber*               logFilesFolderPermissions;
	MCPGServerLogs          logFiles; // Log file names, found in logFilesFolder
	NSString*               adminDatabaseName;
	NSString*				databaseName;
	NSString*               superuserUsername;
	NSString*               basicUsername;
	NSString*               publicPasswordFilename;
	NSString*				basicPublicPassword;
	NSString*				superPublicPassword;
	NSString*               initCompleteFlagPath;
    NSString*               mailerSettingsPath; // Path to archived plist - Only Shared uses this
	NSString*               posixUsername; // the OS account name which tools run as

	// Remote Server
	NSString*				databaseHost;
	NSNumber*				databaseServerPort;
	NSString*				superuserPassword; // Used for hosted server, because there is no need to do all the password callbacks.
	NSString*				basicPassword;
	
	NSString*				databaseSchema;
	
	MCPGPasswordCallBacks   passwordCallBacks;
    
    MCPGServerModelSettings modelSettings;
    MCPGServerSQLScriptSettings  sqlScriptSettings;
    MCPGEmailSettings       emailSettings;
    
} MCPGServerSettings;




extern NSString *MCMainWord(MCPGServer *server);



@interface MCPGServer : MCPGCoreServer {
	MCPGServerSettings     settings;
	
	NSString*   value1; // pg_hba md5
	NSString*   value2; // postgresql.conf md5
}

+ (void)setClassForInstances: (Class)serverClass;
+ (MCPGServerSettings)serverSettingsForServerType: (MCPGServerType)type;
+ (MCPGServerSettings)serverSettingsForServerType: (MCPGServerType)type uuid:(NSString *)serverUUID;
+ (id)sharedServer;
+ (id)personalServer;

- (id)initWithSettings: (MCPGServerSettings)settingsParam;

#pragma mark -
#pragma mark Settings
- (MCPGServerSettings)storage;
- (void)logServerSettings;

- (NSString *)dataPath;
- (NSString *)supportFilesPath;
- (NSString *)backupPath;
- (MCPGServerType)serverType;
- (NSString*)localHostPath; // For Personal based server - socket path
- (NSString*)logFilesFolder;
- (NSString*)logFileNamePrefix;

#pragma mark -
#pragma mark Environment Startup
- (BOOL)startEnvironmentAndReturnError: (NSError**)error;
  // This method will auto initialize the environment if necessary

#pragma mark -
#pragma mark Environment Initialization
- (NSString*)basicUsername;
- (NSString*)superuserUsername;
// This method is overridden in subclasses to return data which will be written as files in the config directory
- (BOOL)SSLCertificateData:(NSData **)certData_p privateKeyData:(NSData **)key_p error:(NSError **)error_p;

#pragma mark -
#pragma mark Environment Information
- (NSString*)serverIdentifier; // returns a UUID that uniquely identifies the PG data directory and hence server instance
- (NSString*)resetServerIdentifierAndReturnError: (NSError**)error; // Incase the UUID needs to be reset use this call - it returns the new UUID

- (NSArray*)databases; // returns the list of databases on the server - excluding the postgres, template and app admin dbs
- (BOOL)doesDatabaseExistForName: (NSString*)aName;
- (NSArray*)connectedUsers;
- (NSArray*)connectedUsersForCode: (NSString*)code;

#pragma mark -
#pragma mark ChangeLog Support
- (BOOL)installChangeLogTriggersInDatabase: (id)aDatabase error: (NSError**)error;
- (BOOL)removeChangeLogTriggersFromDatabase: (id)aDatabase error: (NSError**)error;
- (BOOL)resetChangeLogTriggersInDatabase: (id)aDatabase error: (NSError**)error;
// Checks that the right number of change_log triggers are installed (returns NO by default)
- (BOOL)areChangeLogTriggersInstalledInDatabase: (id)aDatabase error: (NSError**)error;
- (BOOL)removeCacheValueTriggersInDatabase:(id)aDatabase error:(NSError **)error;

#pragma mark -
#pragma mark Data Checks
- (BOOL)doesUserExistNamed: (NSString*)aName inDatabaseNamed: (NSString*)aDatabaseName;
// Overriden by subclasses to validate the application specific user credentials
- (BOOL)validateUsername: (NSString*)aUsername password: (NSString*)aPassword inDatabaseNamed: (NSString*)aDatabaseName error: (NSError**)error;

- (BOOL)isSchemaNumber: (NSNumber*)aSchemaNumber validForDatabaseNamed: (NSString*)aDatabaseName databaseSchemaNumber: (NSNumber **)theDatabaseSchemaNumber error: (NSError**)error;

#pragma mark -
#pragma mark Key/Value Accessors
- (NSString*)userDefaultsValueForKey: (NSString*)aKey;
- (void)setUserDefaultsValue: (NSString*)aValue forKey: (NSString*)aKey;

- (NSString*)externalServerAddress;
- (void)setExternalServerAddress: (NSString*)anAddress;

- (NSString*)privateServerAddress;
- (void)setPrivateServerAddress: (NSString*)anAddress;

- (NSString*)oldServerIdentifier;
- (void)setOldServerIdentifier: (NSString*)anAddress;

- (NSString*)machineIdentifier;
- (void)setMachineIdentifier: (NSString*)anIdentifier;

- (NSString*)serverEncodedImage;
- (void)setServerEncodedImage:(NSString*)base64TiffRepresentation;

- (MCBackupSchedule *)backupSchedule;
- (void)setBackupSchedule:(MCBackupSchedule *)newBackupSchedule;
- (MCBackupSchedule *)backupScheduleFallBackToDefault:(BOOL)fallBackToDefaults;
- (MCBackupSchedule *)defaultBackupSchedule;

- (BOOL)revertToAndEnsureDefaultBackupPath;

- (void)setLastBackupFailedFlag:(BOOL)aFlag;
- (BOOL)lastBackupFailedFlag;

- (NSArray*)lastBackupFailedDatabaseNames;
- (void)setLastBackupFailedDatabaseNames: (NSArray*)databaseNames;

- (BOOL)areEmailNotificationsOn;
- (void)setAreEmailNotificationsOn: (BOOL)flag;

- (BOOL)isPortsDeamonActive;
- (void)setPortsDeamonActive: (BOOL)flag;

- (BOOL)isAutoUpdateIPActive;
- (void)setAutoUpdateIPActive: (BOOL)flag;

- (BOOL)isAutoMapPortsActive;
- (void)setAutoMapPortsActive: (BOOL)flag;



- (NSString *)mccloudUsername;
- (void)setMCCloudUsername:(NSString *)newUsername;

//- (NSString *)mccloudPassword;
- (void)setMCCloudPassword:(NSString *)newpassword forUser:(NSString *)newuser;
- (NSString *)getMCCloudPasswordForUsername:(NSString *)username;
- (NSString *)hostIdentifier;

- (NSInteger)portsdOpterationMode;
- (void)setPortsdOperationMode:(NSInteger)_opmode;

- (void)setServerReachabilityState:(NSInteger)reachabilityState;
- (NSInteger)serverReachabilityState;

- (BOOL)portsMappedCorrectly;
- (void)setPortsMappedCorrectly:(BOOL)flag;

- (NSString *)externalIPAddress;
- (void)setExternalIPAddress:(NSString *)anAddress;

- (NSDate *)externalIPCaptureTime;
- (void)setExternalIPCaptureTime:(NSDate *)lastCaptureTime;

- (NSString *)currentCloudIP;
- (void)setCurrentCloudIP:(NSString *)cloudIP;

- (NSDate *)lastMCCloudIPUpdate;
- (void)setLastMCCloudIPUpdate:(NSDate *)lastIPUpdate;

- (BOOL)mccloudIPUpdateHasProblems;
- (void)setMcCloudIPUpdateHasProblem:(BOOL)flag;


- (NSError *)mccloudIPUpdateError;
- (void)setMccloudIPUpdateError:(NSError *)error;

- (BOOL)serverIsHosted;
- (void)setServerIsHosted:(BOOL)flag;

#pragma mark -
#pragma mark Database Creation
// Can only be used be a hosted server.
// Abstract - must be subclassed

- (BOOL)createApplicationDatabaseNamed:(NSString *)aName includeDefaultData:(BOOL)includeData error:(NSError **)error;
- (BOOL)createSuperUserForDatabaseNamed:(NSString *)dbname username:(NSString *)username password:(NSString *)password error:(NSError **)error;


#pragma mark -
#pragma mark Backing Up
// aPath does not include the filename - we should standardize on a naming scheme
- (BOOL)backupDBNamed: (NSString*)aName toPath: (NSString*)aPath withInfoDictionary:(NSDictionary *)infoDictionary returnedBackupFilePath:(NSString **)aFilePath error: (NSError**)error;
- (BOOL)restoreDBNamed: (NSString*)aName fromBackupAtPath: (NSString*)aPath autoBackupExisting: (BOOL)flag error: (NSError**)error;
- (NSDictionary *)infoDictionaryFromBackupAtPath:(NSString *)archivePath error:(NSError **)error;
- (BOOL)backupPathValid;
- (NSString *)defaultBackupPath;
- (BOOL)ensureDefaultBackupPath;
- (void)updateLastAutomaticBackupDate;
- (NSCalendarDate *)lastAutomaticBackupDate;
- (NSCalendarDate *)nextAutomaticBackupDate;

- (NSCalendarDate *)lastBackupDateForDBNamed:(NSString *)dbName;




#pragma mark -
#pragma mark Environment Maintenance
- (BOOL)createApplicationDatabaseNamed: (NSString*)aName schemaCommands: (NSArray*)commands dataCommands: (NSArray*)dataCommands error: (NSError**)error;
- (BOOL)removeDatabaseNamed: (NSString*)aName error: (NSError**)error;
- (BOOL)renameDatabaseNamed: (NSString*)aName toName: (NSString*)aNewName error: (NSError**)error;

-(BOOL)setFSync_writethroughState:(MCPGServerFSyncState)state error:(NSError**)error;


#pragma mark -
#pragma mark Offline/Mirror Support
// These methods are used for creating offlines and mirrors from a master.
//  The main distinction is that in the personal case it is an offline in the shared case it is a mirror.  Thus the logic for differentiating is done in the offlineNameForDatabaseName: and masterNameFromOfflineName: methods.  The createOffline... method gets the name for the resulting database using the offlineNameForDatabaseName: method.
//  Other logic elsewhere deals with other differences, like setting the database type appropriately on the DatabaseConfiguration table
- (BOOL)createOfflineFromMaster: (MCPGDatabase*)aMaster progressDelegate: (id)progressDelegate error: (NSError**)error;

- (NSString *)offlineNameForDatabaseName:(NSString *)name;
- (NSString *)masterNameFromOfflineName:(NSString *)name;
// returns array of names of offline databases
- (NSArray *)offlineDatabaseNames;


#pragma mark -
#pragma mark Subclassers
- (BOOL)shouldExcludeDatabaseNamed: (NSString*)aName withConnection: (MCPGDatabase*)database;
- (void)addDetailsForDatabase: (MCPGDatabase*)database toDictionary: (NSMutableDictionary*)Dictionary;

#pragma mark -
#pragma mark Email Notification Support
- (MCMailerSettings*)mailerSettings;
- (void)setMailerSettings: (MCMailerSettings*)mailSettings;
- (BOOL)sendTestEmail;
- (BOOL)emailErrorString: (NSString*)error_str;
- (BOOL)emailError: (NSError*)error;


#pragma mark -
#pragma mark Licensing
- (NSArray*)licenses;
- (BOOL)addLicenseWithLicenseCode: (NSString*)license_code serialCode: (NSString*)serial_code checkedUpgradeLicense: (BOOL)checkedUpgrade error: (NSError**)error;
- (BOOL)removeLicense: (NSDictionary*)license error: (NSError**)error;
//- (int)daysLeftTillExpiryDate;
//- (NSArray *)validateAllLicenses; // Checks all licenses against the blacklist. Returns NO if any were invalid so the caller can handle it as they see fit
+ (NSURL *)blacklistURLForApplicationString:(NSString *)appName typeString:(NSString *)typeStr serialString:(NSString *)aSerial licenseString:(NSString *)aLicense;


#pragma mark -
#pragma mark Accessors
- (NSString *)value1;
- (void)setValue1:(NSString *)aValue1;
- (NSString *)value2;
- (void)setValue2:(NSString *)aValue2;

#pragma mark -
#pragma mark DaemonKeeper
@property (retain, nonatomic, readonly) MCDaemonKeeper * daemonKeeper;
- (MCDaemonKeeper *)daemonKeeper;
@end
