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

var Alarm = Class.create({
	initialize: function(id) {
		this.onAlarmSet = this.onAlarmSet.bind(this);
		
		this.id = id;
		this.alarmCookieModel = new Mojo.Model.Cookie(Alarm.kAlarmCookie+this.id);
		this.alarmCookie = this.alarmCookieModel.get();
		
		this.alarmSoundFile = Alarm.kAlarmSoundDefaultFile;
		this.alarmSoundTitle = Alarm.kAlarmSoundDefaultTitle;
		this.enabled = false;
		this.enabledTitle = $L("Disabled");
		this.time = new Date();
		
		var minutes = this.time.getMinutes();
		
		if(minutes > 55){
			minutes += 120 - minutes;
		}else{
			minutes += 60 - minutes;
		}
		
		this.time.setMinutes(minutes);
		this.niceTime = this.getNiceTime();
		
		//console.log("new alarm id ="+id);
		this.title = $L("Alarm "); //+ (id !== 0 ? id : ""); // if it's 0, don't append the id
		//console.log("new alarm id ="+this.title);
		this.timezoneOffset = this.time.getTimezoneOffset()
		
		this.occurs = 'daily';
		if(this.alarmCookie){
			this.title = this.alarmCookie.title;
			this.occurs = this.alarmCookie.occurs;
			this.time.setHours(this.alarmCookie.hours);
			this.time.setMinutes(this.alarmCookie.minutes);
			this.timezoneOffset = this.alarmCookie.timezoneOffset;
			this.niceTime = this.getNiceTime();
			this.enabled = this.alarmCookie.enabled;
			this.enabledTitle = this.enabled?$L("Enabled"):$L("Disabled");
			this.alarmSoundFile = this.alarmCookie.alarmSoundFile;
			this.alarmSoundTitle = this.alarmCookie.alarmSoundTitle;
			this.newAlarm = false;
			// if timezone changed, update alarm time in service since service uses UTC
			var newOffset = this.time.getTimezoneOffset();
			if (this.timezoneOffset != newOffset) {
				Mojo.Log.error("CLOCK: rescheduling alarm because UTC offset changed", this.timezoneOffset, newOffset)
				if (this.enabled) {
					this.alarmSet(this.enabled, this.time);
				} else {
					Mojo.Log.error("CLOCK: saving new offset for alarm, but not rescheduling", this.timezoneOffset, newOffset)
				}
				this.timezoneOffset = newOffset;
			}
		}else{
			//use defaults
			this.newAlarm = true;
		}
		
		if (!this.enabled) {
			this.enabled = false;
		}
		
		this.settingsCookieSave();	
	},
	
	getNiceTime: function(){
		return Mojo.Format.formatDate(this.time, {"time":"short"});
	},
	
	// saves current alarm settings to a cookie
	settingsCookieSave: function() {
		if(true){
			var cookie = {
				'id':this.id,
				'alarmSoundFile':this.alarmSoundFile,
				'alarmSoundTitle':this.alarmSoundTitle,
				'title':this.title,
				'enabled':this.enabled,
				'occurs':this.occurs,
				'hours': this.time.getHours(),
				'minutes': this.time.getMinutes(),
				'timezoneOffset': this.timezoneOffset 
			}
			this.alarmCookieModel.put(cookie);
			//console.log("saved cookie for alarm");
		}
	},
	
	destroyMyself: function(){
		Mojo.Log.error("removing alarm", this.id);
		this.alarmRemove();
	},
	
	// sets alarm time
	// if set to enable, enables alarm in scheduler service
	alarmSet: function(enabled, time, callback) {
		Mojo.Log.error("setting alarm", this.id, enabled);
		//console.log("before alarm for" +this.time);
		this.time = this.dateGetNext(time);
		//console.log("after alarm for" +this.time);
		this.niceTime = this.getNiceTime();
		if(this.newAlarm){
			//this.newAlarm = false;
			enabled = true;
		}
		this.newAlarm = false;
		if (enabled) {
			this.alarmEnable(callback);
		} else {
			this.alarmDisable(callback);
		}
		// cancel pending snooze, if there was one
		this.snoozeOff();
	},
	
	saveTitle: function(title){
		this.title = title;
	},
	
	alarmScheduleNext: function(callback) {
		// disable if this only rings once
		//console.log("ENNNNNABLE! " + this.occurs);
		var enable = (this.occurs !== "once");
		this.alarmSet(enable, this.time, callback);
	},
	
	// calls scheduler service to disable alarm.  fires callback(enabled) on success or error 
	alarmRemove: function(callback) {
		this.schedulerSetRequest = new Mojo.Service.Request(Alarm.kAlarmSchedulerUri, {
			method: "clear",
			parameters: {"key": Alarm.kAlarmSchedulerKey+this.id},
			onSuccess: function() {
				this.alarmCookieModel.remove();
				this.schedulerSetRequest.cancel();
				this.schedulerSetRequest = undefined;
			}.bind(this),
				onFailure: function() {
				Mojo.Log.error("Alarm: removeTask couldn't connect to scheduler service");
				this.alarmCookieModel.remove();
				this.schedulerSetRequest.cancel();
				this.schedulerSetRequest = undefined;
			}.bind(this)	
		});
		// cancel pending snooze
		this.snoozeOff();
	},
	
	// calls scheduler service to disable alarm.  fires callback(enabled) on success or error 
	alarmDisable: function(callback) {
		this.schedulerClrRequest = new Mojo.Service.Request(Alarm.kAlarmSchedulerUri, {
			method: "clear",
			parameters: {"key": Alarm.kAlarmSchedulerKey+this.id},
			onSuccess: function() {
				this.onAlarmSet(false, callback);
				this.schedulerClrRequest.cancel();
				this.schedulerClrRequest = undefined;
			}.bind(this),
			onFailure: function() {
				Mojo.Log.error("Alarm: removeTask couldn't connect to scheduler service");
				this.onAlarmSet(this.enabled, callback);
				this.schedulerClrRequest.cancel();
				this.schedulerClrRequest = undefined;
			}.bind(this)	
		});
	},
	
	// calls scheduler service to enable alarm.  fires callback(enabled) on success or error
	alarmEnable: function(callback) {
		//console.log("setting alarm for" +this.time);
		var newParams = Alarm.kAlarmLaunchParams.evalJSON();
		newParams.params.id = this.id;
		var newParamsJSON = Object.toJSON(newParams);
		var at = this.dateFormatForScheduler(this.time);
		this.schedulerSetRequest = new Mojo.Service.Request(Alarm.kAlarmSchedulerUri, {
			method: "set",
			parameters: {
				"wakeup": true,
				"key": Alarm.kAlarmSchedulerKey+this.id,
				"uri": Alarm.kAlarmLaunchUri,
				"params": newParamsJSON,
				"at": at
			},
			onSuccess: function(payload) {
				if (payload) {
					this.onAlarmSet(true, callback);
				} else {
					Mojo.Log.error("Alarm: updateTask failed");
					this.onAlarmSet(this.enabled, callback);
				}
				this.schedulerSetRequest.cancel();
				this.schedulerSetRequest = undefined;
			}.bind(this),
			onFailure: function() {
				Mojo.Log.error("Alarm: updateTask couldn't connect to scheduler service");
				this.enabled = false;
				this.enabledTitle = this.enabled?$L("Enabled"):$L("Disabled");
				this.onAlarmSet(this.enabled, callback);
				this.schedulerSetRequest.cancel();
				this.schedulerSetRequest = undefined;
			}.bind(this)
		});
	},
	
	// called after every call to the scheduler service to save current state
	// into the cookie; then fires callback(enabled)
	onAlarmSet: function(enabled, callback) {
		//console.log("ALARM IS! ENABLED? " + enabled );
		this.enabled = enabled;
		this.enabledTitle = this.enabled?$L("Enabled"):$L("Disabled");
		this.settingsCookieSave();
		if (callback) {
			callback(enabled)
		}
	},
	
	// given a date object whose time is set to when the alarm should fire
	// returns a date object whose day parameters are set to the 
	// correct day the alarm should fire next
	dateGetNext: function(d) {
		var now = new Date();

		switch (this.occurs) {
			case ('daily'):
				now = this.nextDay(d,now);
				break;
			case ('weekdays'):
				now = this.nextWeekday(d,now);
				break;
			case ('weekends'):
				now = this.nextWeekend(d,now);
				break;
			default:
				now = this.nextDay(d,now);
				break;
		}

		return now;
		
	},
	
	nextDay: function(d,now){
		if (now.getHours() > d.getHours() || (now.getHours() == d.getHours() && now.getMinutes() >= d.getMinutes())) {
				now.setDate(now.getDate()+1);
		}
		now.setHours(d.getHours());
		now.setMinutes(d.getMinutes());
		now.setSeconds(0);
		return now;
	},
	
	nextWeekday: function(d,now){
		var timePassed = false;
		if (now.getHours() > d.getHours() || (now.getHours() == d.getHours() && now.getMinutes() >= d.getMinutes())) {
			timePassed = true;
		}
		
		var day = now.getDay();
		if(day == Alarm.kSunday) {
			now.setDate(now.getDate() + 1);
		} else if (day == Alarm.kFriday && timePassed) {
			now.setDate(now.getDate() + 3);
		} else if (day == Alarm.kSaturday) {
			now.setDate(now.getDate() + 2);
		} else if (timePassed) {
			now.setDate(now.getDate() + 1);
		}
		
		now.setHours(d.getHours());
		now.setMinutes(d.getMinutes());
		now.setSeconds(0);
		return now;
	},

	nextWeekend: function(d,now){
		var timePassed = false;
		if (now.getHours() > d.getHours() || (now.getHours() == d.getHours() && now.getMinutes() >= d.getMinutes())) {
			timePassed = true;
		}
		var day = now.getDay();
		
		if (day == Alarm.kSunday){
			if (timePassed) {
				now.setDate(now.getDate() + 6);
			}	
		} else if (day == Alarm.kSaturday && timePassed){
			now.setDate(now.getDate() + 1);
		} else {
			now.setDate(now.getDate() + (6 - day));
		}
		now.setHours(d.getHours());
		now.setMinutes(d.getMinutes());
		now.setSeconds(0);
		
		return now;
	},
	
	// returns date in format suitable for scheduler service
	dateFormatForScheduler: function(d) {
		function twoChars(x) { return ((x>9)?"":"0")+x; }
		
		
		return twoChars(d.getUTCMonth()+1) + "/" + twoChars(d.getUTCDate()) + "/" + twoChars(d.getUTCFullYear()) 
					+ " " + twoChars(d.getUTCHours()) + ":" + twoChars(d.getUTCMinutes()) + ":00" 
	},
	
	// returns number of days until this alarm rings.  returns 0 for today.
	daysUntilAlarm: function() {
		var now = new Date();
		var today = now.getDay()
		
		switch (this.occurs) {
			case 'weekdays':
				if (this.isWeekend()) {
					// it either rings tomorrow or in 2 days if today's saturday
					return 1 + (today == 6);
				} else if (this.isLaterToday()){
					return 0
				} else {
					// if it's friday, then it rings in 3 days (on monday), otherwise tomorrow
					return (today == Alarm.kFriday ? 3 : 1)
				}
			case 'weekends':
				// if it's not the weekend, the first time it rings is saturday
				if (!(this.isWeekend())) {
					return 6 - today;
				} else if (this.isLaterToday()) {
					return 0;
				// if it's sunday, then it rings in 6 days (on saturday), otherwise tomorrow
				} else {
					return (today == Alarm.kSunday ? 6 : 1)
				}
			// if it rings daily or once, then it either rings today or tomorrow
			case 'daily':
			case 'once':
				return (this.isLaterToday() ? 0 : 1);
			
		}
	},
	
	// snooze this alarm.  pass true to indicate that it was snoozed by another popup opening
	snooze: function(alarmInterrupted) {
		var newParams = Alarm.kAlarmLaunchParams.evalJSON();
		newParams.params.id = this.id;
		if (alarmInterrupted) {
			newParams.params.alarmInterrupted = true;
		}
		var newParamsJSON = Object.toJSON(newParams);
		this.schedulerSetRequest = new Mojo.Service.Request(Alarm.kAlarmSchedulerUri, {
			method: "set",
			parameters: {
				"wakeup": true,
				"key": Alarm.kAlarmSchedulerKeySnooze+this.id,
				"uri": Alarm.kAlarmLaunchUri,
				"params": newParamsJSON,
				"in": (alarmInterrupted ? Alarm.kAlarmSnoozeInterruptedDuration : Alarm.kAlarmSnoozeDuration)
			},
			onSuccess: function(payload) {
				// Mojo.Log.info("Alarm: snooze succeeded");
				this.schedulerSetRequest.cancel();
				this.schedulerSetRequest = undefined;
			}.bind(this),
			onFailure: function() {
				Mojo.Log.error("Alarm: snooze couldn't connect to scheduler service");
				this.schedulerSetRequest.cancel();
				this.schedulerSetRequest = undefined;				
			}.bind(this)
		});
	},
	
	// calls scheduler service to cancel snooze alarm 
	snoozeOff: function(callback) {
		this.schedulerSetRequest = new Mojo.Service.Request(Alarm.kAlarmSchedulerUri, {
			method: "clear",
			parameters: {"key": Alarm.kAlarmSchedulerKeySnooze+this.id},
			onSuccess: function(payload) {
				// Mojo.Log.info("Alarm: snooze succeeded");
			},
			onFailure: function() {
				Mojo.Log.error("Alarm: snooze couldn't connect to scheduler service");				
			}	
		});
	},
	
	// saves alarm sound.  if title isn't specified, uses soundfile
	alarmSoundSet: function(soundFile, soundTitle) {
		
		if (!soundTitle) {
			soundTitle = soundFile;
		}

		this.alarmSoundFile = soundFile;
		this.alarmSoundTitle = soundTitle;
		this.settingsCookieSave();
		
	},
	
	saveOccurance: function(occurs){
		this.occurs = occurs;
		this.settingsCookieSave();
	},
	
	nextAlarmDayText: function() {
		var today = new Date().getDay();
		switch (this.occurs) {
			case 'weekdays':
				if (today == Alarm.kSaturday 
					|| (today == Alarm.kFriday && !(this.isLaterToday()))) {
					return $L("Monday");
				} else if (today == Alarm.kSunday || !(this.isLaterToday())) {
					return $L("tomorrow")
				} else {
					return "";
				}
			case 'weekends':
				if ((today >= Alarm.kMonday && today <= Alarm.kThursday)
					|| (today == Alarm.kSunday && !(this.isLaterToday()))) {
					return $L("Saturday");
				} else if (today == Alarm.kFriday || today == Alarm.kSaturday && !(this.isLaterToday())) {
					return $L("tomorrow")
				} else {
					return "";
				}
			case 'daily':
			case 'once':
				if (this.isLaterToday()) {
					return ""
				} else {
					return $L("tomorrow");
				}
		}
	},
	
	isLaterToday: function() {
		var now = new Date();
		return (this.time.getHours() > now.getHours() 
			|| (this.time.getHours() == now.getHours() 
					&& this.time.getMinutes() > now.getMinutes()))
	},
	
	isWeekday: function() {
		var now = new Date();
		var day = now.getDay();
		return (day !== Alarm.kSunday && day !== 6);
	},
	
	isWeekend: function() {
		return !(this.isWeekday());
	}
});

Alarm.kAlarmCookie = "alarmcookie";

Alarm.kSunday = 0;
Alarm.kMonday = 1;
Alarm.kTuesday = 2;
Alarm.kWednesday = 3;
Alarm.kThursday = 4;
Alarm.kFriday = 5;
Alarm.kSaturday = 6;

Alarm.kAlarmSchedulerKey = "timequake"; // "You were sick, but now you're well again, and there's work to do"
Alarm.kAlarmSchedulerKeySnooze = "timequakeSnooze";
Alarm.kAlarmCookieTime = "alarmTime";
Alarm.kAlarmCookieEnabled = "alarmEnabled";
Alarm.kAlarmSchedulerUri = "luna://com.palm.power/timeout/";
Alarm.kAlarmLaunchUri = "luna://com.palm.applicationManager/launch";
Alarm.kAlarmLaunchParams = '{"id":"com.palm.app.clock","params":{"action":"ring"}}';
Alarm.kAlarmSnoozeDuration = "00:10:00";
// Alarm.kAlarmSnoozeInterruptedDuration = "00:00:45"; service does not allow alarms less than 5 min.
Alarm.kAlarmSnoozeInterruptedDuration = "00:05:00";
Alarm.kCookieAlarmSoundFile = "alarmsoundfile";
Alarm.kCookieAlarmSoundTitle = "alarmsoundtitle";
// TODO ALWAYS MAKE SURE THIS IS VALID
Alarm.kAlarmSoundDefaultFile = "/media/internal/ringtones/Flurry.mp3";
Alarm.kAlarmSoundDefaultTitle = "Flurry";


