/**
 * @author rogerstringer
 */


// this section is psuedo constants whose value does not change
var BASE_KEY_NAME = "@BaseConfiguration";
var LIST_KEY_NAME = "@ProfileList";


// functionality to save and restore profiles
var profileStore = {
	
	//////////////////////////////////////////////////////////////////////
	// variables/properties
	//////////////////////////////////////////////////////////////////////

	bOpenStatus: false,
	profileList: null,
	db:          undefined,
	exportList:  null,
	exportCount: 0,
	
	//////////////////////////////////////////////////////////////////////
	// getter/setters
	//////////////////////////////////////////////////////////////////////

	isOpen:            function () {
		Mojo.Log.info("isOpen(): " + this.bOpenStatus + "<br><br> db: " + this.db);
		return this.bOpenStatus;
	},
	baseProfileExists: function () { // assumes if profiles exist, there'll be a base profile
		Mojo.Log.info("baseProfileExists(): " + Object.toJSON(this.profileList));
		return (null == this.profileList || this.profileList.length == 0 ? false : true);
	},
	getProfileListJSON: function  () {
		return (null == this.profileList 
			? "{'errorText':'empty'}" : Object.toJSON(this.profileList) );
	},
	getBaseProfileName: function () {
		return BASE_KEY_NAME;
	},
	
	getProfileCount: function () {
		return (null == this.profileList ? 0 : this.profileList.length);
	},
	
	getProfileList: function (useAll) {
		var tempProfile = [];
		if (useAll == null) useAll = false;
		Mojo.Log.info("getProfileList():  started");
		if (null == this.profileList || this.profileList.length == 0 
				|| (this.profileList.length == 1 && useAll != true) ) {return tempProfile;}
		for (var i = 0 ; i < this.profileList.length ; i++) {
			if (useAll == true || this.profileList[i].name.charAt(0) != '@'
					|| this.profileList[i].name != BASE_KEY_NAME) {
				tempProfile.push(this.profileList[i]);
			}
		}
		return tempProfile; // list is already in reverse chronological sequence
	},
	
	getExportStatus: function () {
		return (null == this.exportList ? false : true );
	},

	//////////////////////////////////////////////////////////////////////
	// Setup
	//////////////////////////////////////////////////////////////////////

	setup: function () {
		var that = this;
		Mojo.Log.info("setup(): profileStore: started");
		var options = {
			name:    "PROFILES",
			version: 1,
		};
		var listSuccess = function (result) {
			Mojo.Log.info("setup(): listSuccess(): succeeded");
			this.profileList = result; // can be null
		}.bind(this);
		var initFailure = function(result){
			Mojo.Log.error("setup(): Failed " + result.errorText);
		}.bind(this);
		var initSuccess = function(result){
			this.bOpenStatus = true;
			this.profileList = null;
			Mojo.Log.info("setup(): database opened");
			if (!this.db){Mojo.Log.error("setup(): Database not initialized");}
			else {this.db.simpleGet(LIST_KEY_NAME, listSuccess, initFailure);}
		}.bind(this);

		Mojo.Log.info("setup(): about to initialize depot");
		this.db = new Mojo.Depot (options, initSuccess, initFailure);
	
	},
	
	//////////////////////////////////////////////////////////////////////
	// Action methods
	//////////////////////////////////////////////////////////////////////

	// returns true/false; false means error; true is not meaningful
	deleteProfile: function (name) {
		if (!name) {
			Mojo.Log.error("deleteProfile(): name missing ");
			return false;
		}
		if (this.bOpenStatus == false || this.db == undefined || this.profileList == null) {
			Mojo.Log.error("deleteProfile(): database is not open or is empty");
			return false;
		}
		var that = this;
		var i = 0;
		while (i < this.profileList.length) {
			if (this.profileList[i].name == name) {break;}
			i++;
		}
		if (i >= this.profileList.length) {
			Mojo.Log.error("deleteProfile(): Name NOT found " + name);
			return false;
		}
		
		Mojo.Log.info("deleteProfile(): delete " + name);
		this.simpleDelete (name,
			function() { // onSuccess
				that.profileList.splice (i, 1); // remove i'th element
				that.db.simpleAdd (LIST_KEY_NAME, that.profileList, 
					function(){ // onSuccess
						Mojo.Log.info("updateProfile(): profileList updated " + name);
					},
					that.profileListUpdateOnFailure.bind(that));
			}, 
			this.genericOnFailure.bind(this));
		return true;// means parameters seem OK
	},
	
	// returns true/false; false means error; true is not meaningful
	updateProfile: function (name, description, details, onSuccess, onFailure) {
		var errMsg = "Error updating/creating profile ";
		if (!name) {
			errMsg += ": name missing";
			Mojo.Log.error("updateProfile(): " + errMsg);
			if (onFailure) {param.onFailure(errMsg);}
			return false;
		}
		errMsg += name + "<br><br>";
		if (this.bOpenStatus == false || this.db == undefined) {
			errMsg += "Database not open";
			Mojo.Log.error("updateProfile(): " + errMsg);
			if (onFailure) {param.onFailure(errMsg);}
			return false;
		}
		if (!details) {
			errMsg += 'details parameter is missing!';
			Mojo.Log.error("updateProfile(): " + errMsg);
			if (onFailure) {param.onFailure(errMsg);}
			return false;
		} 
		var that = this;
		var isNew = true;
		var isProfileChange = false;
		Mojo.Log.info("updateProfile(): find name in profileList: " + name);
		if (this.profileList != null) {
			for (var i = 0 ; i < this.profileList.length ; i++) {
				if (this.profileList[i].name == name) {
					isNew = false;   // found
					if (description != null && this.profileList[i].desc != description) {
						this.profileList[i].desc = description;
						isProfileChange = true;
					}
					break;
				}
			}
			Mojo.Log.info("updateProfile(): name "
				+ (isNew == true ? "missing from" : "found in") 
				+ " profileList; has " + this.profileList.length + " entries.");
		} else {Mojo.Log.info("updateProfile(): profileList is empty");}

		this.db.simpleAdd (name, details,
			function() { // onSuccess
				if (isNew == true) { // found
					Mojo.Log.info("updateProfile(): New entry added for: " + name);
					if (that.profileList == null) {
						that.profileList = [{'name':name, 'desc':description}];
					} else {
						that.profileList.unshift({'name':name, 'desc':description}); // add to front!
					}
					isProfileChange = true;
				} else {
					Mojo.Log.info("updateProfile(): Entry updated for: " + name);
				}
				if (isProfileChange == true) {
					that.db.simpleAdd (LIST_KEY_NAME, that.profileList,
						function(){ // onSuccess
							Mojo.Log.info("updateProfile(): profileList updated " + name);
							if (onSuccess != null) {onSuccess (name, description);}
						},
						that.profileListUpdateOnFailure.bind(that)
					);
				} else if (onSuccess != null) {onSuccess (name, description);}
			}, 
			this.genericOnFailure.bind(this)
		);
			
		return true;// means parameters seem OK
	},
	
	// returns true/false; false means error or 'name' not found; true is not meaningful
	getProfileDetails: function (name, onSuccess, onFailure) {
		if (!name) {
			Mojo.Log.error("getProfileDetails(): name missing ");
			return false;
		}
		if (this.bOpenStatus == false || this.db == undefined) {
			Mojo.Log.error("getProfileDetails(): database is not open");
			return false;
		}
		var that = this;
		var i = 0;
		Mojo.Log.info("getProfileDetails(): find name in profileList: " + name);
		while (this.profileList != null && i < this.profileList.length) {
			if (this.profileList[i].name == name) {
				Mojo.Log.info("getProfileDetails(): profileList name found: " + name);
				this.db.simpleGet (name, onSuccess, onFailure);
				return true;// means parameters seem OK
			}
			i++;
		}
		Mojo.Log.error("getProfileDetails(): profileList name NOT found: " + name);
		return false;
		
	},
 	
	// will return null if error, or name not found, or description is null
	getProfileDescription: function (name) {
		if (!name) {
			Mojo.Log.error("getProfileDescription(): name missing ");
			return null;
		}
		if (this.bOpenStatus == false || this.db == undefined) {
			Mojo.Log.error("getProfileDescription(): database is not open");
			return null;
		}
		var that = this;
		var i = 0;
		Mojo.Log.info("getProfileDescription(): find name in profileList: " + name);
		while (this.profileList != null && i < this.profileList.length) {
			if (this.profileList[i].name == name) {
				Mojo.Log.info("getProfilDescription(): profileList entry found: " + name
					+ "; Desc: " + this.profileList[i].desc);
				return this.profileList[i].desc;
			}
			i++;
		}
		Mojo.Log.error("getProfileDescription(): profileList entry NOT found: " + name);
		return null;
	},
	
	deleteAllProfiles: function (onSuccess, onFailure) {
		if (this.bOpenStatus == false || this.db == undefined) {
			Mojo.Log.error("deleteAllProfiles(): database is not open");
			if (onFailure) {
				onFailure ("{'errorText': 'Database is not open'}");
			}
		} else {
			var that = this;
			this.db.removeAll(
				function() { //onSuccess
					Mojo.Log.info("deleteAllProfiles(): suceeded!");
					that.profileList = null;
					if (onSuccess) {onSuccess ();}
				}, 
				(onFailure ? onFailure : that.genericOnFailure.bind(that))
			);
		}
	},
	
	importProfile: function (param) { // 'param' has fullPath, onSuccess(), onFailure(message)
		var that = this;
		Mojo.Log.info("importProfile(): fullPath: " + param.fullPath
			+ "; function onSuccess() " + (param.onSuccess ? 'present' : 'missing') 
			+ "; function onFailure() " + (param.onFailure ? 'present' : 'missing'));
		var request = new Mojo.Service.Request('palm://com.palm.logctld', {
			method: 'importjsonfile',
			parameters: {filename: param.fullPath},
			onSuccess: function (result) {
				// Quick check on contents
				var obj = undefined;
				Mojo.Log.info("importProfile(): onSuccess - result: " + Object.toJSON(result));
				try {
					obj = (result.text ? result.text.evalJSON(true) : undefined);
					if (obj != undefined) {Mojo.Log.info("importProfile(): obj: " + Object.toJSON(obj));}
				} catch (exception) {
					Mojo.Log.logException(exception);
					Mojo.Log.info("importProfile(): onSuccess - result: " + Object.toJSON(result.text));
					obj = undefined;
				}
				
				if (obj != undefined && obj.filename && obj.description && obj.details && obj.details[0]) {
					that.processImport(param, obj);
				} else {
					Mojo.Log.error("importProfile(): Failed: \'invalid format\' on file: " + param.fullPath);
					if (param.onFailure) {param.onFailure($L("Import failed as file doesn't appear to have valid format."));}
				}
			},
			onFailure: function (result) {
				Mojo.Log.error ("importProfile(): Failed: " + result.errorText + " on file: " + param.filename);
				if (param.onFailure) {param.onFailure($L("Import failed.<br><br> Do you have the latest version of the 'logctld' service?"));}
			},

		});
	},
	
	processImport: function  (param, text) {
		try {
			var name = (text.filename.charAt(0) != '@' ? '@' : '') + text.filename;
			var isFound = (null == this.getProfileDescription(name) ? false : true);
			if (isFound == false && text.filename.charAt(0) != '@') { // perhaps re-import?
				isFound = (null == this.getProfileDescription(text.filename) ? false : true);
				if (isFound == true) {name = text.filename;}
			}
			var details = []; // type, name, level
			Mojo.Log.info("importImport(): " + name + (isFound == true ? " (overwriting)" : " (adding)"));
			
			for (var i = 0 ; i < text.details.length ; i++) { // only extract apparently valid entries
				if (text.details[i].type && text.details[i].name && text.details[i].level) {
					details.push({'type':text.details[i].type, 'name':text.details[i].name, 'level':text.details[i].level});
				}
			}
			if (details.length == 0) {
				Mojo.Log.error ("processImport(): Failed as no valid profile entries found in file: " + param.fullname);
				if (param.onFailure) {param.onFailure($L("Import failed.<br><br>no valid profile entries found in file: ") + param.fullname);}
			} else {
				Mojo.Log.info("processImport(): details: " + Object.toJSON(details));
				//var description = (name.charAt(0) != '@' || text.description.charAt(0) == '|' ? text.description : "| " + text.description);
				this.updateProfile (name, text.description, details, param.onSuccess, param.onFailure);
			}
		}
		catch (exception) {
			Mojo.Log.logException(exception);
			if (param.onFailure) {param.onFailure("Error trying to import file.<br><br>" + exception);}
		}
	},
	
	// returns null for OK, or an error message
	verifyNewDescription: function (desc) {
		if (null == desc || desc.length == 0) {
			return $L("Description is empty");
		} 
	//	if (desc.charAt(0) == '@') {
	//		return $L("Description must start with numeric or alphabetic character");
	//	}
		if (this.profileList == null || this.profileList.length < 2) {return null;}
		for (var i = 0 ; i < this.profileList.length ; i++ ) {
			if (this.profileList[i].desc == desc) {
				return $L("Description duplicates a profile already stored.");
			}
		}
		return null;
	},
 	
	///////////////////////////////////////////////////////////////////////////////////
	// utility functions
	//////////////////////////////////////////////////////////////////////

	simpleDelete: function (key, onSuccess, onFailure) {
		Mojo.Log.info("simpleDelete(): delete from profile bucket: " + key);
		// From reading source code on Depot, the default bucket is 'null'
		this.db.removeSingle (null, key, onSuccess, onFailure);
	},

	genericOnFailure: function (result) {
		var text = (!result ? "Unknown" : ( !result.errorText ? "" : result.errorText));
		var code = (!result || !result.errorCode ? "" : (" #" + result.errorCode));
		Mojo.Log.error ("Database access error: " + text + code);
	},
	
	profileListUpdateOnFailure: function (result) {
		var text = (!result ? "Unknown" : ( !result.errorText ? "" : result.errorText));
		var code = (!result || !result.errorCode ? "" : (" #" + result.errorCode));
		Mojo.Log.error ("Database access error: updating profileList: " + text + code);
	},
	
	formatDateName: function (t, sep) {
		if (t && t.year) {  //{"year": 2009, "month": 4, "day": 22, "hour": 14, "minute": 54, "second": 33},
			return t.year + 
					( (t.month >= 10)  ? "" : "0") + t.month +
					( (t.day >= 10)    ? "" : "0") + t.day + 
					( sep ? sep : 'T') +
					( (t.hour >= 10)   ? "" : "0") + t.hour + 
					( (t.minute >= 10) ? "" : "0") + t.minute + 
					( (t.second >= 10) ? "" : "0") + t.second;
		} else {
			var date = (!t ? new Date () : new Date(t * 1000));
			return date.getFullYear().toString() + 
					( (date.getMonth() >= 9)    ? "" : "0") + (date.getMonth()+1) +
					( (date.getDate() >= 10)    ? "" : "0") + date.getDate() + 
					( sep ? sep : 'T') +
					( (date.getHours() >= 10)   ? "" : "0") + date.getHours() + 
					( (date.getMinutes() >= 10) ? "" : "0") + date.getMinutes() + 
					( (date.getSeconds() >= 10) ? "" : "0") + date.getSeconds();
		}
	},
};
