/* Copyright 2009 Palm, Inc.  All rights reserved. */

var CalendarsManager = Class.create ({
	
	initialize: function() {
		//Mojo.Log.info("CalendarsManager initialize");
		
		this.lastCurrentCal = 'all'	// Do NOT Localize
		this.currentCal = 'all';	// Do NOT Localize
		this.currentCalObservers = new Hash();
		this.calendarIcons = new Hash();
		this.calendarMenuIcons = new Hash();
		
		// Keep this.colorList in sync with the one in the color-picker.js (Is
		// there a better way to do this?)
		this.colorList = ["blue", "green", "yellow", "orange", "pink", "red", "purple", "teal"]; // Do NOT Localize
		this.usedCalendarColors = new Hash();
		this.nextColorIndex = 0;
		
		
		if(Mojo.Host.current === Mojo.Host.mojoHost) {
			this.getCalendarsByAccountCallback.bind(this).defer({"accounts": [{"calendars": [{"readOnly": false, "color": "blue", "syncSource": "Local", "name": "Palm Profile", "id": 40681930227720, "excludeFromAll": false}],
							"userName": "", "icons": '{"32x32":"images/accounts/mypalm-32x32.png", "48x48":"images/accounts/mypalm-48x48.png"}', "name": "Palm Profile", "id": 35184372088835}]});
		
		} else {
			
			// Subscribe to the getCalendarsByAccount service
			this.getCalendarsByAccount();
			
		}
	},
	
	getCalendarsByAccount: function(){		
		this.request = new Mojo.Service.Request(CalendarMojoService.identifier, {
				method: 'getCalendarsByAccount',
				parameters: {subscribe: true},
				onSuccess: this.getCalendarsByAccountCallback.bind(this),
				onFailure: this.getCalendarsByAccountFailed
			});
	},
	
	getCalendarsByAccountFailed: function(response){
		console.error("CalendarsManager: getCalendarsByAccount service call failed: "+Object.toJSON(response));
	},
	
	setup: function() {
	},
	
	cleanup: function() {
		// Unsubscribe from the getCalendars service
		this.request.cancel();
	},
	
	setColorUsed: function(color) {
		this.usedCalendarColors.set(color, true);
	},
	
	findUnusedColor: function() {
		var unusedColor = "";
		
		this.colorList.each(function(color){
			if (this.usedCalendarColors.get(color) == null &&
					unusedColor == "") {
				//Mojo.Log.info("*** calendars-manager: findUnusedColor %s",color);
				unusedColor = color;
			}
		}, this);
		
		if (unusedColor == "") {
			// If all of the colors are used, then cycle through the
			// list of colors
			unusedColor = this.colorList[this.nextColorIndex];
			this.nextColorIndex++;
			if (this.nextColorIndex >= this.colorList.size())
				this.nextColorIndex = 0;
		}
		
		return unusedColor;
	},
	
	setCalendarsCallback: function(response) {
		//Mojo.Log.info("calendars-manager: setCalendarsCallback");
	},
	
	injectColors: function() {
		//Mojo.Log.info("calendars-manager: injectColors %j", this.calendars);
		// Reinit the usedCalendarColors hash, so the colors for any calendars that
		// have been purged, are "released"
		this.usedCalendarColors = new Hash();
		
		// Iterate through the color prefs to figure out which colors have been used
		this.calendars.each(function(calHashEntry){
			// this.calendars is a hash, so calHashEntry[0] represents the key and calHashEntry[1] represents
			// the value of a calendar entry in the hash
			var cal = calHashEntry[1];
			if (cal.color != "none" && cal.color != undefined)		// Do NOT Localize
				this.usedCalendarColors.set(cal.color, true);
		}, this);
		
		var setDefaultColors = false;
		var updatedCalendars = [];
		// Inject the default color settings here!
		this.calendars.each(function(calHashEntry) {
			// this.calendars is a hash, so calHashEntry[0] represents the key and calHashEntry[1] represents
			// the value of a calendar entry in the hash
			var cal = calHashEntry[1];
			var color = cal.color;
			if (cal.id != "all") {
				if (color == "none") {
					// Assign a default color here and save its pref.
					var unusedColor = this.findUnusedColor();
					cal.color = unusedColor;
					cal.colorStyle = 'cal-color-' + unusedColor;
					this.usedCalendarColors.set(unusedColor, true);
					updatedCalendars.push({id: cal.id, color: unusedColor});
					setDefaultColors = true;
				} else {
					if (cal.syncSource == "Local") {	// Do NOT Localize
						this.localCalendarId = cal.id;
					}
					cal.colorStyle = 'cal-color-' + color;
				}
				if (cal.syncSource == "Local" && cal.excludeFromAll) {
					// The Local calendar is NOT allowed to be excluded from the All Calendars
					// view, so we force it to be false
					//Mojo.Log.info("Detected a Local calendar that was excluded from All Calendars view");
					cal.excludeFromAll = false;
					updatedCalendars.push({id: cal.id, excludeFromAll: cal.excludeFromAll});
					setDefaultColors = true;
				}
			}
		}, this);
		
		if (setDefaultColors) {
			getCalendarService().setCalendars(updatedCalendars, this.setCalendarsCallback.bind(this));
		}
		
		return setDefaultColors;
	},
	
	getCalendarsByAccountCallback: function(response){
		//Mojo.Log.info('calendars-manager: getCalendarsByAccountCallback ');
		var calendarsHash = new Hash();
		var foundCurrentCalendar = false;
		
		this.accounts = response.accounts;
		
		// Setup the this.calendars based on the accounts
		
		// Add "All Calendars"
		var allCalendar = {};
		allCalendar.id = 'all'; 									// Do NOT Localize
		allCalendar.name = $L('All calendars');
		allCalendar.readOnly = false;
		allCalendar.syncSource = 'All calendars'; // Do NOT Localize
		calendarsHash.set('all', allCalendar);		// Do NOT Localize
		
		// Add other calendars
		this.accounts.each(function(account){
			account.calendars.each(function(calendar){
				// NOTE: Account names to be localized are located in javascripts/accountLocalizations.js
				calendar.accountName = $L(account.name);
				if (account.icons) {
					calendar.icon = this.parseAcctIconString(account.icons);
				}
				calendarsHash.set("id"+calendar.id, calendar);
				if (calendar.color == "none") {
					// Check to see if we've already injected a color
					// into this calendar
					if (this.calendars) {
						var existingCalEntry = this.calendars.get("id"+calendar.id);
						if (existingCalEntry && existingCalEntry.color != "none") {
							// We already injected a color for this calendar,
							// but our call to setCalendars hasn't been executed yet,
							// so let's re-inject the color so the colors remain
							// consistent
							calendar.color = existingCalEntry.color;
						}
					}
				}
				if (calendar.id == getCurrentCal()) {
					foundCurrentCalendar = true;
				}
				
			}, this);
		}, this);
		
		//Mojo.Log.info('this.calendars EQUALS %j',this.calendars);
		this.calendars = calendarsHash;
		calendarColorsUpdated = this.injectColors();
		this.updateCalendarMenuItems();
		
		// Validate the default calendar preference
		getPrefsManager().validateDefaultCalPref();
		
		// Validate the current calendar.  If that calendar has been removed,
		// set the current calendar back to All
		if (foundCurrentCalendar == false) {
			setCurrentCal('all');
		}
		
		this.notifyObserversCalendarsListChange();
		if (!calendarColorsUpdated)
			this.notifyObserversCalendarSettingsChange();
	},
	
	parseAcctIconString: function(iconsString) {
		if (iconsString) {
			var obj = iconsString.evalJSON(true);
			var iconPath = obj['32x32CALENDAR'];
			if (iconPath == undefined) {
				// If there is no special icon specific to Calendar just use the one for the Account
				iconPath = obj['32x32'];
			} 
			
			if (iconPath) {
				// Check to see if the path is an absolute path... if it is, then we're done.
				if (iconPath[0] == '/' || iconPath.search("file://") == 0) {
				} else {
					// Otherwise, this is a relative path, relative to the framework so we form
					// the absolute path to the image in the framework
					iconPath = Mojo.Config.MOJO_FRAMEWORK_HOME + "/" + iconPath;
				}
			}
			
			return iconPath;
		}
		return undefined;
	},
	
	getCalAccount: function(id) {
		return this.accounts.find(function(acct){
			return acct.id == id;
		});
	},
	
	getCalAccountIcon: function(acctId) {
		var acct = this.getCalAccount(acctId);
		
		if (acct) {
			return this.parseAcctIconString(acct.icons);
		}
		
		return undefined;
	},
	
	getLastCurrentCal: function() {
		return this.lastCurrentCal;
	},
	
	getCurrentCal: function() {
		return this.currentCal;
	},
	
	setCurrentCal: function(newCal) {
		// TODO: Should add some sanity checks here?
		if (this.currentCal != newCal) {
			this.lastCurrentCal = this.currentCal;
		}
		this.currentCal = newCal;
		// Update anyone who is interested in the current calendar
		this.notifyObservers();
	},
	
	getCalColor: function(calId) {
		//Mojo.Log.info('calendars-manager: getCalColor for cal %s ' , calId);
		
		if (calId == 0) {
			//Trying to retrieve the color for the local calendar
			return this.getCal('id'+this.localCalendarId).color;
		}
		
		var cal = this.getCal(calId);
		if (cal == undefined)
			return undefined;
			
		return cal.color;
	},
	
	getCalColorStyle: function(calId) {
		//Mojo.Log.info('calendars-manager: getCalColorStyle for cal %s', calId);
		
		if (calId == 0) {
			//Trying to retrieve the color for the local calendar
			return this.getCal('id'+this.localCalendarId).colorStyle;
		}
		
		var cal = this.getCal(calId);
		if (cal == undefined)
			return undefined;
		
		//Mojo.Log.info('calendars-manager: getCalColorStyle cal %j', cal);
		
		return cal.colorStyle;
	},
	
	getCalName: function(calId) {
		var cal = this.getCal(calId);
		

		if (cal == undefined) {
			return undefined;
		}
		
		return cal.name;
	},
	
	getCalSyncSource: function(calId) {
		var cal = this.getCal(calId);
		

		if (cal == undefined) {
			return undefined;
		}
		
		return cal.syncSource;
	},
	
	getCalIcon: function(calId) {
		
		if (calId == 0) {
			//Trying to retrieve the icon for the local calendar
			return this.getCal('id'+this.localCalendarId).icon;
		}
		
		var cal = this.getCal(calId);

		if (cal == undefined) {
			return undefined;
		}
		
		return cal.icon;
	},
	
	isCalendarReadOnly: function(calId) {
		if (this.calendars) {
			var cal = this.getCal(calId);
		
			//Mojo.Log.info('calendars-manager: isCalendarReadOnly %s %j',calId,cal);
			
			if (cal == undefined) {
				return undefined;
			}
			
			return cal.readOnly;
		}
		
		return undefined;
	},
	
	getCalAccountName: function(calId) {
		var cal = this.getCal(calId);
		
		
		if (cal == undefined) {
			return undefined;
		}
		
		return cal.accountName;
	},
	
	getCal: function(calId) {
		var cal = this.calendars.get(calId);
		
		return cal;
	},
	
	getLocalCalendar: function() {
		return this.getCal('id'+this.localCalendarId);
	},
	
	getLocalCalendarId: function() {
		return this.localCalendarId;
	},
	
	// Returns the id of the "first" non-local calendar.  NOTE: Ordering
	// of the calendars seem to be arbitrary, so essentially this function
	// just retrieves A non-local calendar id.
	getNonLocalCalendarId: function(excludeReadOnly) {
		//Mojo.Log.info("calendars-manager: getNonLocalCalendarId:");
		// By default the list of calendars include All and Local
		if (this.calendars.size() > 2) {
			var firstCal = this.calendars.find(function(cal){
				if (excludeReadOnly && cal[1].readOnly)
					return false;
				else
					return cal[1].id != 0 && cal[1].id != 'all' && cal[1].syncSource != "Local";
			});
			if (firstCal) {
				//Mojo.Log.info("calendars-manager: getNonLocalCalendarId: %j ",firstCal);
				return firstCal[1].id;
			} else {
				return 0;
			}
			
		} else {
			// There are no non-local calendars
			return 0;
		}
	},
	
	buildCalendarsMenu: function(includeAll, includeReadOnly, includeExcludedFromAll) {
		//Mojo.Log.info('calendars-manager: buildCalendarsMenu ');
		var listItems = [];
		
		// All Calendars
		if (includeAll) {
			// Add the All Calendars item
			listItems.push({
	  		label: $L("All calendars"),
	  		command: 'all',	// Do NOT Localize
	  		secondaryIcon: this.calendarMenuIcons.get('all'),
	  	});
		}
		
		// Other calendars
		this.accounts.each(function(account){
			var addThisAccount = true;
			
			if (includeReadOnly == false) {
	  		// Do not add an account to the menu if all of its menus are readonly
				var allCalsAreReadOnly = true;
				account.calendars.each(function(calendar){
					if (calendar.readOnly == false) {
						allCalsAreReadOnly = false;
					}
				});
				
				if (allCalsAreReadOnly) {
					addThisAccount = false;
				}
			} 
			
			if (addThisAccount && includeExcludedFromAll == false) {
				// Do not add an account to the menu if all of its menus are
				// excluded from the "All Calendars" view
				var allCalsAreExcluded = true;
				account.calendars.each(function(calendar){
					if (calendar.excludeFromAll == false) {
						allCalsAreExcluded = false;
					}
				});
				
				if (allCalsAreExcluded) {
					addThisAccount = false;
				}
			}
			
			if (addThisAccount) {
				
				if(account.name == "Palm Profile")
				{
				
					account.name =$L("Palm Profile");
				}
				listItems.push({label: account.name.toUpperCase() /*+ ' - ' + account.userName*/}); //removed username for sake of demo bug #NOV-37729
				
				account.calendars.each(function(cal){
					if(cal.syncSource == "Local")
					{
						
						cal.name =$L("Palm Profile");
					}
					if (includeReadOnly == false && cal.readOnly) {
						// Do NOT include this read only calendar
					} else if (includeExcludedFromAll == false && cal.excludeFromAll) {
						// Do NOT include this calendar that is excluded from the "All Calendars" view
					} else {
						listItems.push({
				  		label: cal.name,
				  		command: cal.id,
				  		secondaryIcon: "calendar-color color-chip " + "cal-color-" + cal.color,
				  	});
				  }
				});
			}
		});
		//finally push the view options item
		if (includeAll) {
			listItems.push({
				label: $L("Calendar View Options..."),
				command: "viewOptions"
			});
		}
		
		return listItems;
	},
	
	updateCalendarMenuItems: function() {
		//Mojo.Log.info('calendars-manager: updateCalendarMenuItems ');
		this.calendarIcons = new Hash();
		this.calendarMenuIcons = new Hash();
		
		this.calendars.values().each(function(cal){
			if (cal.id == "all") {
				this.calendarMenuIcons.set(cal.id, 'menu_all');
			} else if (cal.icon) {
				this.calendarIcons.set(cal.id, cal.icon);
			}
		}, this);
		
		this.notifyObservers();
	},
	
	observeCalendars: function(sceneName, sceneController) {
		//Mojo.Log.info('calendars-manager: observeCalendars ');
		this.currentCalObservers.set(sceneName, sceneController);
		
		// Update the item now
		sceneController.currentCalendarUpdated();
	},
	
	stopObservingCalendars: function(elementName) {
		//Mojo.Log.info('calendars-manager: stopObservingCalendars ');
		this.currentCalObservers.unset(elementName);
	},
	
	notifyObservers: function() {
		//Mojo.Log.info('calendars-manager: notifyObservers ');
		this.currentCalObservers.each(function(elementPair) {
			var sceneController = elementPair.value;
			sceneController.currentCalendarUpdated();
			});
	},
	
	notifyObserversCalendarSettingsChange: function() {
		//Mojo.Log.info('calendars-manager: notifyObserversCalendarSettingsChange ');
		this.currentCalObservers.each(function(elementPair) {
			var sceneController = elementPair.value;
			sceneController.calendarSettingsUpdated();
			});
	},
	
	notifyObserversCalendarsListChange: function() {
		//Mojo.Log.info('calendars-manager: notifyObserversCalendarsListChange ');
		this.currentCalObservers.each(function(elementPair) {
			var sceneController = elementPair.value;
			sceneController.calendarListUpdated();
			});
	}
});
