function dateRange(startDateObj, endDateObj) {
	this.startDateObj = startDateObj;
	this.endDateObj = endDateObj;
	this.isDateInRange = function(dateToTest) {
	    return (this.startDateObj <= dateToTest && dateToTest <= this.endDateObj);
	};
}

// Trace function
function trace(arg) {
    if (window.console) { console.log(arg); }
}

// Tracking events
/* Dummy defenition - real function should be defined 
and this one commented out/deleted */
function statTrack(what, element, where, data) {
	//alert("STAT TRACK!");
//	alert('statTrack: ' + what + ' | ' + element + ' | ' + where + ' | ' + data);
}


function registerNow() {
    jQuery.facebox($('#overlayHaveToRegister').html());
}

function validationPopup(message) {
    alert(message);
}


// Global vars to overcome scope limits of "this":
var quitRanges = null;
var dailyData = null;
var weeklyData = null;
var monthlyData = null;
var runningDate = new Date();
runningDate.setHours(12, 0, 0);
var validationMessage = '';


function calendarHelper(mode) {
    this.calMode = mode;
    this.currentRange = null;    
    this.util = new util();
    this.blockGetRangeEvents = false;
    this.loggedIn = false;
	
	this.dailyCalendar = new dailyCalendar();
	this.weeklyCalendar = new weeklyCalendar();
	this.monthlyCalendar = new monthlyCalendar();
	this.masterCalendarDateBox = new masterCalendarDateBox();

	this.nowBeginning = runningDate;
	this.nowBeginning = new Date(
	        this.nowBeginning.getFullYear(),
	        this.nowBeginning.getMonth(),
	        this.nowBeginning.getDate()
	);
	// In order to encompass the full starting day of the period:
	this.nowBeginning.setHours(0, 0, 2);
	this.dailyCalendar.currentDate = new Date(this.nowBeginning);
	this.weeklyCalendar.currentDate = new Date(this.nowBeginning);
	this.monthlyCalendar.currentDate = new Date(this.nowBeginning);
	this.masterCalendarDateBox.currentDate = new Date(this.nowBeginning);

	this.Init = function() {

	    switch (this.calMode) {
	        case "day":
	            this.currentRange = this.dailyCalendar.getDateRangeShown();
	            this.dailyCalendar.goToDate(this.currentRange.startDateObj);
	            break;
	        case "week":
	            this.currentRange = this.weeklyCalendar.getDateRangeShown();
	            this.weeklyCalendar.goToDate(this.currentRange.startDateObj);
	            break;
	        case "month":
	            this.currentRange = this.monthlyCalendar.getDateRangeShown();
	            this.monthlyCalendar.goToDate(this.currentRange.startDateObj);
	            break;
	    }
	    document.calendarHelper.monthlyCalendar.LoadQuitDateRanges();
	    this.RefreshCalendarWithNewData(this.calMode);
	    // hide/unhide proper boxes
	    this.VisualSwitchToCal(this.calMode);
	    // display new date range in date box
	    this.masterCalendarDateBox.SetNewDisplayDates(this.calMode, this.currentRange);
	};
	
	
	// Modes are: month, week, day
	this.SwitchMode = function(mode, calendarClick) {
	    // figure out a new date range for data
	    intentString = this.calMode + " to " + mode;
	    var today = new Date();
	    today.setHours(0, 0, 0);
	    isValidModeSwitch = true;
	    switch (intentString) {
	        // taking care of three "error" scenarios           
	        case "day to day":
	        case "week to week":
	        case "month to month":
	            isValidModeSwitch = false;
	            break;
	        // then take care of the easy ones, going out (day -> week -> month)        
	        case "day to week":
	            this.weeklyCalendar.currentDate = this.dailyCalendar.currentDate;
	            this.currentRange = this.weeklyCalendar.getDateRangeShown();
	            this.weeklyCalendar.goToDate(this.currentRange.startDateObj);
	            break;
	        case "day to month":
	            this.monthlyCalendar.currentDate = this.dailyCalendar.currentDate;
	            this.currentRange = this.monthlyCalendar.getDateRangeShown();
	            this.monthlyCalendar.goToDate(this.currentRange.startDateObj);
	            break;
	        case "week to month":
	            this.monthlyCalendar.currentDate = this.weeklyCalendar.currentDate;
	            this.currentRange = this.monthlyCalendar.getDateRangeShown();
	            this.monthlyCalendar.goToDate(this.currentRange.startDateObj);
	            break;
	        // then tougher scenarios TODO: account for current month! All those actions will default to current week/day!        
	        case "week to day":
	            if (this.util.todayIsInRunningWeek(this.weeklyCalendar.currentDate)) {
	                runningDate = today;
	            } else {
	                runningDate = this.weeklyCalendar.currentDate;
	            }
	            this.dailyCalendar.currentDate = new Date(runningDate); //this.weeklyCalendar.currentDate;
	            this.currentRange = this.dailyCalendar.getDateRangeShown();
	            this.dailyCalendar.goToDate(this.currentRange.startDateObj);
	            break;
	        case "month to day":
	            if (calendarClick && (calendarClick == "click")) {
	                runningDate = this.dailyCalendar.currentDate;
	            } else {
	                if (this.util.todayIsInRunningMonth(this.monthlyCalendar.currentDate)) {
	                    runningDate = today;
	                } else {
	                    runningDate = this.monthlyCalendar.currentDate;
	                }
	            }
	            this.dailyCalendar.currentDate = new Date(runningDate); //this.monthlyCalendar.currentDate;
	            this.currentRange = this.dailyCalendar.getDateRangeShown();
	            this.dailyCalendar.goToDate(this.currentRange.startDateObj);
	            break;
	        case "month to week":
	            if (this.util.todayIsInRunningMonth(this.monthlyCalendar.currentDate)) {
	                runningDate = today;
	            } else {
	                runningDate = this.monthlyCalendar.currentDate;
	            }
	            this.weeklyCalendar.currentDate = new Date(runningDate); //this.monthlyCalendar.currentDate;
	            this.currentRange = this.weeklyCalendar.getDateRangeShown();
	            this.weeklyCalendar.goToDate(this.currentRange.startDateObj);
	            break;
	    }
	    if (isValidModeSwitch) {
	    	BEXTracker.CalendarTracker_SwitchMode(intentString);
	        // load data for whatever mode from the server, put that data into the proper calendar
	        this.RefreshCalendarWithNewData(mode);
	        // hide/unhide proper boxes
	        this.VisualSwitchToCal(mode);
	        // display new date range in date box
	        this.masterCalendarDateBox.SetNewDisplayDates(mode, this.currentRange);
	        // finally, set the current mode to what it is
	        this.calMode = mode;
	    }
	};

	this.setNavAbilityDayWeek = function(setOn) {
	    document.calendarHelper.goToQuitMode(!setOn);
	    trace('setNavAbilityDayWeek() called. setOn=' + setOn);
	};

    // "true" sets it to Quit mode, false - regular tracking mode:
	this.goToQuitMode = function(isQuitMode) {		
	    this.calMode = 'month';
	    this.monthlyCalendar.quitMode = isQuitMode;
	    this.Init();
	    var backToTrackerLink = '<a onclick="javascript:document.calendarHelper.goToQuitMode(false);" href="javascript:void(0);">'
	    + $('#' + this.monthlyCalendar.monthMessageTemplateId + ' td[id=trackerReturn]').text() + '</a>';
	    if (isQuitMode) {
	    	BEXTracker.CalendarTracker_EnterQuitDateMode();
	        $('#switch').hide();
	        $('#calNav').hide();
	        $('p#backToTrackerLink').html(backToTrackerLink);
	        $('p#quitDateLink').hide();
	        $('p#backToTrackerLink').show();
	        
	        $('#headerTrackingMode').hide();
	        $('#headerQuitMode').show();	        
	    } else {
	    	BEXTracker.CalendarTracker_LeaveQuitDateMode();	    	
	        $('#switch').show();
	        $('#calNav').show();
	        $('p#backToTrackerLink').hide();
	        $('p#quitDateLink').show();

	        $('#headerTrackingMode').show();
	        $('#headerQuitMode').hide();
	    }
	};
	

	// hide the current, unhide the new
	this.VisualSwitchToCal = function(newMode) {
	    var u = new util();
	    switch (newMode) {
	        case "day": u.toggleDay(); break;
	        case "week": u.toggleWeek(); break;
	        case "month": u.toggleMonth(); break;
	    }
	};
	
	// Triggered when somebody presses the > after the date header
	this.NextDateRange = function() {
	    BEXTracker.CalendarTracker_Navigator('next'+this.calMode);
	    switch (this.calMode) {
	        case "day": this.dailyCalendar.nextDay(); break;
	        case "week": this.weeklyCalendar.nextWeek(); break;
	        case "month": this.monthlyCalendar.nextMonth(); break;
	    }
	    this.RefreshCalendarWithNewData(this.calMode);
	};
	
	// Triggered when somebody presses the < in front of the date header
	this.PrevDateRange = function() {
		BEXTracker.CalendarTracker_Navigator('previous'+this.calMode);
		switch (this.calMode) {
			case "day" :	this.dailyCalendar.prevDay(); break;
			case "week" :	this.weeklyCalendar.prevWeek(); break;
			case "month" :	this.monthlyCalendar.prevMonth(); break;
		}
		this.RefreshCalendarWithNewData(this.calMode);
	};

	// Refresh the appropriate calendar with new data
	this.RefreshCalendarWithNewData = function(calendarModeToFill) {
	switch (calendarModeToFill) {
	        case "day":
	            this.currentRange = this.dailyCalendar.getDateRangeShown();
	            this.LoadDetailedDataForDateRange(this.currentRange, this.dailyCalendar);
	            break;
	        case "week":
	            this.currentRange = this.weeklyCalendar.getDateRangeShown();
	            this.LoadDetailedDataForDateRange(this.currentRange, this.weeklyCalendar);
	            break;
	        case "month":
	            this.currentRange = this.monthlyCalendar.getDateRangeShown();
	            this.LoadDetailedDataForDateRange(this.currentRange, this.monthlyCalendar);
	            break;
	    }
	    this.masterCalendarDateBox.SetNewDisplayDates(this.calMode, this.currentRange);
	};


    // define the callback function for GetRangeEvents
	this.rangeEvents = function(response, userData) {
		
		// if we've blocked out the calendar, unblock it
		$('#CalendarReloading').remove();
		
	    // callback has fired, so it's safe to invoke additional API calls now
	    this.blockGetRangeEvents = false;
	    //trace('rangeEvents() called 1. ' + response.IsSuccess);
	    if (!response.IsSuccess) {
	        if (response.FailureMsg.indexOf('AKBAD') != -1) {
	            document.calendarHelper.loggedIn = false;
	            $('#monthCal').click(registerNow);
	        }
	        return;
	    }
	    document.calendarHelper.loggedIn = true;
	    $('p.registerNow').html('<div style="height: 1.8em; width: 10em"></div>');

	    switch (userData.who.toString()) {
	        case "dailyCalendar":
	            dailyData = response.ResponseData.SmokingEvents;
	            userData.clearDataLines();
	            userData.setData(dailyData);
	            userData.dayReloading=false;
	            break;

	        case "weeklyCalendar":
	            weeklyData = response.ResponseData.SmokingEvents;
	            userData.setData(weeklyData);
	            break;

	        case "monthlyCalendar":
	            monthlyData = response.ResponseData.SmokingEvents;
	            var quitDate = response.ResponseData.QuitDate;
	            var u = new util();
	            if (quitDate != undefined) {
	                document.calendarHelper.monthlyCalendar.quitDate = new Date(u.makeDateFromAPI(quitDate));
	            }
	            userData.setData(monthlyData);
	            break;
	    }

	    var mc = document.calendarHelper.monthlyCalendar;
	    if (mc.quitDate.getFullYear() > 1970) {
	        var yourQuitDateText = $('#messageTemplateGeneral #yourQuitDate').text();
	        quitDate = document.calendarHelper.masterCalendarDateBox.months[mc.quitDate.getMonth()]
	                + ' ' + mc.quitDate.getDate() + ', ' + mc.quitDate.getFullYear();
	        $('p#quitDateLink a').text(yourQuitDateText + ' ' + quitDate);
	    }

	};

	
	// populates appropriate calendar data array with smokingEventObj
	this.LoadDetailedDataForDateRange = function(dateSpan, currentCalendar) {
	    // AJAX call out to server
	    var u = this.util;
	    //trace('LoadDetailedDataForDateRange() called. ' + currentCalendar.who);

	        BEXAPI.GetSmokingEvents(u.makeAPIdate(dateSpan.startDateObj), u.makeAPIdate(dateSpan.endDateObj), this.rangeEvents, currentCalendar); 
	};
}

function masterCalendarDateBox(mode) {
	this.calMode = mode;
	this.calDateObj = document.getElementById("currentDateSpan");
	
	if ( document.BEXlanguage == 'es' ) {
		this.months = new Array( "Enero", "Febrero", "Marzo", "Abril", "Mayo",
			 "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre" );
	} else {
		this.months = new Array( "January", "February", "March", "April", "May",
			"June", "July", "August", "September", "October", "November", "December" );
	}
		
	this.SwitchMode = function(mode) {
		this.calMode = mode;
	};

	this.SetNewDisplayDates = function(mode, dateRangeObj) {
		this.SwitchMode(mode);
		this.SetNewDisplayDatesWithoutMode(dateRangeObj.startDateObj, dateRangeObj.endDateObj);
	};

	this.SetNewDisplayDatesWithoutMode = function(startDateObj, endDateObj) {
	    var backText = $('#messageTemplateGeneral #back').text();
	    var fwdText = $('#messageTemplateGeneral #forward').text();
	    var dayText = $('#messageTemplateGeneral #day').text();
	    var weekText = $('#messageTemplateGeneral #week').text();
	    var monthText = $('#messageTemplateGeneral #month').text();
	    switch (this.calMode) {
	        case "day": // display Month D, YYYY
	        	if ( document.BEXlanguage=='es' ) {
	        		$('#currentDateSpan').html( startDateObj.getDate() + ' ' + this.months[startDateObj.getMonth()] + ' ' + startDateObj.getFullYear());
	            } else {
	            	$('#currentDateSpan').html(this.months[startDateObj.getMonth()] + ' ' + startDateObj.getDate() + ', ' + startDateObj.getFullYear());
	            }
	            $('#navHead img:first').attr('alt', backText + ' ' + dayText);
	            $('#navHead img:last').attr('alt', fwdText + ' ' + dayText);
	            
	            break;
	        case "week":
	            var dateSpanTitle = '';
	            var titleStartDate = this.months[startDateObj.getMonth()] + " " + startDateObj.getDate();
	            var titleEndDate = '';

	            // three kinds of display:
	            //	Month D - D, YYYY
	            //  Month D - Month D, YYYY
	            //	Month D, YYYY - Month D, YYYY
	            if (startDateObj.getFullYear() != endDateObj.getFullYear()) {
	                // case # 3
	                titleStartDate += ', ' + startDateObj.getFullYear();
	                titleEndDate = this.months[endDateObj.getMonth()] + " " + endDateObj.getDate();
	                titleEndDate += ', ' + endDateObj.getFullYear();
	            } else
	                if (startDateObj.getMonth() != endDateObj.getMonth()) {
	                // case # 2
	                titleEndDate = this.months[endDateObj.getMonth()] + " " + endDateObj.getDate();
	                titleEndDate += ', ' + endDateObj.getFullYear();
	            } else {
	                // case # 1
	                titleEndDate = endDateObj.getDate() + ', ' + endDateObj.getFullYear();
	            }

	            dateSpanTitle = titleStartDate + ' - ' + titleEndDate;
	            $('#currentDateSpan').html(dateSpanTitle);
	            $('#navHead img:first').attr('alt', backText + ' ' + weekText);
	            $('#navHead img:last').attr('alt', fwdText + ' ' + weekText);
	            break;
	        case "month":
	            // display Month, YYYY
	            $('#currentDateSpan').html(this.months[startDateObj.getMonth()] + ', ' + startDateObj.getFullYear());
	            $('#navHead img:first').attr('alt', backText + ' ' + monthText);
	            $('#navHead img:last').attr('alt', fwdText + ' ' + monthText);
	            break;

	    }
	};
}

function weeklyCalendar() {
    this.who = "weeklyCalendar";
	this.currentDate = null; // first day of the week shown
	this.calTableName = "weeklyCalTable";
	this.timesPresent = null;
    this.separator = '|';
	this.util = new util();
	this.weekDays = new Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
	this.esWeekDays = new Array("Dom", "Lun", "Mar", "Mi&eacute;r", "Jue", "Vi&eacute;r", "S&aacute;b");

	
	// start date is Sun, end date is Sat
	this.getDateRangeShown = function() {
	    this.currentDate = this.getCorrectDateToSun(this.currentDate);
	    var endDate = new Date(this.currentDate);
	    endDate.setDate(this.currentDate.getDate() + 6);
	    endDate.setHours(23, 59, 59, 0);
	    return (new dateRange(this.currentDate, endDate));
	};
	
	// give it a date, if it's not sunday, return the sunday previous to it
	this.getCorrectDateToSun = function(dateObj) {
		thisDay = dateObj.getDay();
		if (thisDay != 0) { // not a Sunday? go to Sunday!
			dateObj.setDate(dateObj.getDate()-thisDay);
		}
		return(dateObj);
	};

	this.goToDate = function(dateObj) {
	    this.currentDate = this.getCorrectDateToSun(dateObj);
	    this.clearDataLines();
	    this.setWeekdayTop();
	};

	this.nextWeek = function() {
	    if (!this.util.todayIsInRunningWeek(this.currentDate)) {
	        var newDate = new Date(this.currentDate);
	        newDate.setDate(this.currentDate.getDate() + 7);
	        this.goToDate(newDate);
	        document.calendarHelper.RefreshCalendarWithNewData(document.calendarHelper.calMode);

	    }
	};
	
	this.prevWeek = function() {
	    var newDate = new Date(this.currentDate);
		newDate.setDate(this.currentDate.getDate()-7);
		this.goToDate(newDate);
	};


	this.setEmptyWeeklyCells = function(smokingEventObjArr, startDateObj) {
	    //trace('------setEmptyWeeklyCells----');
	    this.timesPresent = null;
	    this.timesPresent = new Array();
	    for (i = 0; i < smokingEventObjArr.length; i++) {
	        smokingEventObj = smokingEventObjArr[i];
	        var dayNext = new Date(startDateObj);
	        var time = smokingEventObj.DateTime.substr(8, 2) * 1;
	        if (!this.hasTimeLine(time)) {
	            this.addTimeLine(time);
	            $('#' + this.calTableName).append('<tr class="editRow" id="row-' + time + '"></tr>');
	            rowHeader = '<th class="time" scope="row">' + this.util.makeNiceTime(time) + '</th>';
	            var row = $('#row-' + time).append(rowHeader);
	            rowCell = '';
	            for (j = 0; j < 7; j++) {
	                rowCell = '<td id="cell-' + dayNext.getDate() + '-' + time + '"></td>';
	                row = row.append(rowCell);
	                dayNext.setDate(dayNext.getDate() + 1);
	            }
	        }
	        this.timesPresent.sort(function(a, b) { return (a - b); });
	    }
	};
    
	// day, time and numberCigarettes are integers
	// time is expressed in 24 hour format, from 0-23
	this.setDataPoint = function(date, time, numberCigarettes) {
	    if (!this.getDateRangeShown().isDateInRange(date)) {
	        return (false);
	    }
	    this.setTimeCell(date.getDate(), time, numberCigarettes);
	};


	// sets the entire week at once
	this.setData = function(smokingEventObjArr) {
	    smokingEventObjArr.sort(function(a, b) { return (a.DateTime.substr(8, 2) * 1 - b.DateTime.substr(8, 2) * 1) });
	    this.setEmptyWeeklyCells(smokingEventObjArr, this.getDateRangeShown().startDateObj);
	    var totalsDayTime = new Array();
	    var numberCigarettes = 0;
	    var dateTime = '';
	    for (i = 0; i < smokingEventObjArr.length; i++) {
	        smokingEventObj = smokingEventObjArr[i];
	        numberCigarettes = smokingEventObj.Number * 1;
	        dateTime = smokingEventObj.DateTime + '';
	        if (totalsDayTime[dateTime]) {
	            totalsDayTime[dateTime] += numberCigarettes;
	        } else {
	            totalsDayTime[dateTime] = numberCigarettes;
	        }
	    }
	    for (var dataPoint in totalsDayTime) {
	        numberCigarettes = totalsDayTime[dataPoint];
	        this.setDataPoint(this.util.makeDateFromAPI(dataPoint), dataPoint.substr(8, 2) * 1, numberCigarettes);
	    }
	};



	
	///////////////////////////////////////////////////////////////
	// THEN COME THE DISPLAY METHODS, TOUCHING HTML WITHIN DIRECTLY
	///////////////////////////////////////////////////////////////
	// adjust days of week (9th-15th)
	this.setWeekdayTop = function() {
	    var dayNext = new Date(this.currentDate);
	    var suffix = '';
	    var rowHeader = '<tr id="time-header"><th scope="col">Time</th>';
	    for (i = 0, j = 0; i < 7; i++, j++) {
	        switch (dayNext.getDate() % 10) {
	            case 1:
	                suffix = 'st';
	                break;
	            case 2:
	                suffix = 'nd';
	                break;
	            case 3:
	                suffix = 'rd';
	                break;
	            default:
	                suffix = 'th';
	                break;
	        }
	        if ( document.BEXlanguage=='es' ) {
	        	rowHeader += '<th scope="col">' + this.esWeekDays[j] + ' (' + dayNext.getDate() + ')</th>';
	        } else {
	        	rowHeader += '<th scope="col">' + this.weekDays[j] + ' (' + dayNext.getDate() + ')</th>';
	        }
	        dayNext.setDate(dayNext.getDate() + 1);
	    }
	    rowHeader += '</tr>';
	    $('#' + this.calTableName).append(rowHeader);
	};


	// remove all weekly lines
	this.clearDataLines = function() {
	    // actually delete all rows past the first one
	    $('#' + this.calTableName + ' tr').remove();
	    this.timesPresent = new Array();
	};

	// adds a blank line for time
	this.addTimeLine = function(time) {
		if (!this.hasTimeLine(time)) {
		    this.timesPresent.push(time);
		}
	};
	
	// if we get here, we know the cell actually exists!
	this.setTimeCell = function(day, time, numberCigarettes) {
	    //trace('setTimeCell - ' + day + '/' + time + ': ' + numberCigarettes);
	    $('#cell-' + day + '-' + time).html('<span class="cigCount"><span class="count">' + numberCigarettes + '</span></span>');
	};


	this.hasTimeLine = function(time) {
	    var flag = false;
	    for (var i = 0; i < this.timesPresent.length; i++) {
	        if (this.timesPresent[i] == time) {
	            flag = true;
	            break;
	        }
	    }
	    return flag;
	    // if time is in this.timesPresent, then return true, otherwise return false
	};

	this.getRowIdForTime = function(time) {
	    return ('row-' + time);
	};
	
	// initialize calendar right away
	var initDate = new Date();
	this.goToDate(initDate);
}

function monthlyCalendar() {
    this.who = "monthlyCalendar";
    this.monthMessageTemplateId = "messageTemplateMonth";
    this.util = new util();
    this.currentDate = null; // first day of the week shown
    this.quitMode = false;
    this.quitDate = null;
    this.quitDay = '32';
    this.event = null;
    this.offsetX = $('div.navHead').offset().left + 10;
    this.offsetY = $('div.navHead').offset().top + 5; 
    this.limitHighX = 1100;
    this.limitLowY = 300;
    
    // define the callback function for getQuitDateRanges
    this.getQuitDateRanges = function(response, userData) {
        // callback has fired, so it's safe to invoke additional API calls now
        this.blockQuitDateRanges = false;

        if (!response.IsSuccess) {
              return;
        }
        
        quitRanges = response.ResponseData;
	document.calendarHelper.RefreshCalendarWithNewData(document.calendarHelper.calMode);        
    };


    this.LoadQuitDateRanges = function() {
        // AJAX call out to server
            var u = this.util;
            var yearMonth = u.makeAPIdate(this.currentDate);
            yearMonth = yearMonth.substr(0, 6);
            // and call the API
            BEXAPI.GetQuitDateRanges(yearMonth, this.getQuitDateRanges);            
    };



    this.getDateRangeShown = function() {
	    var endDate = new Date(this.currentDate);
	    // go up one month, then minus one day
		endDate.setMonth(this.currentDate.getMonth()+1); 
		endDate.setDate(endDate.getDate()-1);
		endDate.setHours(23, 59, 58);
		return (new dateRange(this.currentDate, endDate));
	};
	
	// give it a date, if it's not sunday, return the sunday previous to it
	this.getCorrectDateToBeginningOfMonth = function(dateObj) {
		dateObj.setDate(1);
		return(dateObj);
	};
	
	this.goToDate = function(dateObj) {
	    this.currentDate = this.getCorrectDateToBeginningOfMonth(dateObj);
		// call monthly calendar's next
	};

	this.nextMonth = function() {
	    if (this.quitMode || (!this.quitMode && !this.util.todayIsInRunningMonth(this.currentDate))) {
	        var newDate = new Date(this.currentDate);
	        newDate.setMonth(newDate.getMonth() + 1);
	        BEXTracker.statTrack('event', 'cig tracker', 'month toggle', newDate.getMonth());
	        bex_cal.nextMonth();
	        this.goToDate(newDate);
	        if ( this.quitMode ) {
	        	document.calendarHelper.monthlyCalendar.LoadQuitDateRanges();
	        }        
	    }	    
	};

	this.prevMonth = function() {
	    var newDate = new Date(this.currentDate);
	    newDate.setMonth(newDate.getMonth() - 1);
	    BEXTracker.statTrack('event', 'cig tracker', 'month toggle', newDate.getMonth());
	    bex_cal.prevMonth();  
	    this.goToDate(newDate);
	    if ( this.quitMode ) {
	    	    document.calendarHelper.monthlyCalendar.LoadQuitDateRanges();
	    }
	};

	
	// day, time and numberCigarettes are integers
	// time is expressed in 24 hour format, from 0-23
	this.setDataPoint = function(day, numberCigarettes) {
	    // stick some HTML into calendar here
	    var dateToSet = new Date(this.currentDate);
	    dateToSet.setDate(day);
	    //set the attribute values for date - if you don't set an attribute value, it will simply default to blank.
	    var textToDisplay = numberCigarettes + '';
	    dateToSet.cellHTML = '<span class="cigCount"><span class="count">' + textToDisplay + '</span></span>';
	    dateToSet.title = textToDisplay + '';
	    bex_cal.addDates([dateToSet]);
	};
	
	
	// sets the entire month at once
	this.displayMonthlyData = function(monthlyTotalsArr) {
	    for (var day in monthlyTotalsArr) {
	        // day = extract day from the hash key
	        // numberCigarettes = extract as value from hash
	        this.setDataPoint(day, monthlyTotalsArr[day]);
	    }
	};


	this.clickedBeforeToday = function(dateClicked) {
	    this.takeBaloonAway();
	    calendarSetPickedDate(dateClicked);
	};

	this.clickedNextTwoWeeks = function(dateClicked) {
	    this.takeBaloonAway();
	    calendarSetPickedDate(dateClicked);
	};

    this.clickedAfterTwoWeeks = function(dateClicked) {
        this.takeBaloonAway();
        calendarSetPickedDate(dateClicked);
    };

    this.getXpos = function(e) {
        this.offsetX = $('div.navHead').offset().left + 10;
        this.offsetY = $('div.navHead').offset().top + 5; 
        var posx = 0;
        if (!e) var e = window.event;
        if (e.pageX) {
            posx = e.pageX;
        }
        else if (e.clientX) {
            posx = e.clientX + document.body.scrollLeft
			    + document.documentElement.scrollLeft;
        }
        if (posx > this.limitHighX) posx = this.limitHighX;
        return posx;
    };

    this.getYpos = function(e) {
        var posy = 0;
        if (!e) var e = window.event;
        if (e.pageY) {
            posy = e.pageY;
        }
        else if (e.clientY) {
            posy = e.clientY + document.body.scrollTop
			    + document.documentElement.scrollTop;
        }
        if (posy < this.limitLowY) posy = this.limitLowY;
        return posy;
    };

    this.hoverBeforeToday = function(e) {
        if (this.quitMode) {
            $('#baloon').css('left', this.getXpos(e) - this.offsetX).css('top', this.getYpos(e) - this.offsetY);
            $('#baloon div p').text($('#' + this.monthMessageTemplateId + ' td[id=quitPast]').text());
        } else {
            this.takeBaloonAway();
        }
    };

    this.hoverNextTwoWeeks = function(e) {
        if (this.quitMode) {
            $('#baloon').css('left', this.getXpos(e) - this.offsetX).css('top', this.getYpos(e) - this.offsetY);
            $('#baloon div p').text($('#' + this.monthMessageTemplateId + ' td[id=quitSoon]').text());
        } else {
            this.takeBaloonAway();
        }
    };

    this.hoverAfterTwoWeeks = function(e) {
        if (this.quitMode) {
            $('#baloon').css('left', this.getXpos(e) - this.offsetX).css('top', this.getYpos(e) - this.offsetY);
            $('#baloon div p').text($('#' + this.monthMessageTemplateId + ' td[id=quitOk]').text());
        } else {
            this.takeBaloonAway();
        }
    };

    this.takeBaloonAway = function() {
        $('#baloon').css('top', '-999px').css('left', '-999px');
    };

    this.setURLsForCells = function() {
        var dateParams = '';
        var startDate = new Date();
        var endDate = new Date();
        var todayEnd = new Date();
        startDate.setHours(0, 0, 1);
        endDate.setHours(23, 59, 59);

        var pastRange = null;
        var tooSoonRange = null;
        var okRange = null;
        var tempRange = '';
        
       if (quitRanges) {
            if (quitRanges.PastRange) {
                tempRange = quitRanges.PastRange.split('-');
                pastRange = new dateRange(new Date(startDate), new Date(endDate));
                pastRange.startDateObj.setDate(tempRange[0]);
                pastRange.endDateObj.setDate(tempRange[1]);
            }

            if (quitRanges.TooSoonRange) {
                tempRange = quitRanges.TooSoonRange.split('-');
                tooSoonRange = new dateRange(new Date(startDate), new Date(endDate));
                tooSoonRange.startDateObj.setMonth( this.currentDate.getMonth() );
                tooSoonRange.startDateObj.setDate(tempRange[0]);
                tooSoonRange.endDateObj.setMonth( this.currentDate.getMonth() );
                tooSoonRange.endDateObj.setDate(tempRange[1]);
            }

            if (quitRanges.OKRange) {
                tempRange = quitRanges.OKRange.split('-');
                okRange = new dateRange(new Date(startDate), new Date(endDate));
                okRange.startDateObj.setDate(tempRange[0]);
                okRange.endDateObj.setDate(tempRange[1]);
            }
        }

        for (var i = 0; i < bex_cal.cells.length; i++) {
            bex_cal.cells[i].date.setHours(12, 0, 0);
            if (this.quitDate != null
	                && (bex_cal.cells[i].date.getFullYear() == this.quitDate.getFullYear())
	                && (bex_cal.cells[i].date.getMonth() == this.quitDate.getMonth())
	                && (bex_cal.cells[i].date.getDate() == this.quitDate.getDate())
	                        ) {
                $('#quitText').hide();
                $('#quitText').remove();
                var formerHTML = $(bex_cal.cells[i].tableCell).html();
                $(bex_cal.cells[i].tableCell).html('<span id="quitText"> '
                                        + $('#' + this.monthMessageTemplateId + ' td[id=quit]').text()
                                        + ' </span>');
                $(bex_cal.cells[i].tableCell).children().after(formerHTML);
            }


            if (this.quitMode) {
                // Not going to a day calendar here. Run a function instead with a date clicked passed.
                $(bex_cal.cells[i].tableCell).unbind('mousedown');
                // Past date
                if (quitRanges.PastRange
                //&& (pastRange.startDateObj <= bex_cal.cells[i].date)
                    && (bex_cal.cells[i].date < pastRange.endDateObj)) {
                    $(bex_cal.cells[i].tableCell).addClass('pastdate');
                    $(bex_cal.cells[i].tableCell).mouseout(function() { document.calendarHelper.monthlyCalendar.takeBaloonAway() });
                    $(bex_cal.cells[i].tableCell).mousemove(
                            function(e) { document.calendarHelper.monthlyCalendar.hoverBeforeToday(e); });
                    $(bex_cal.cells[i].tableCell).bind('mousedown',
                            function(d) {
                                return function() {
                                    document.calendarHelper.monthlyCalendar.clickedBeforeToday(d);
                                }
                            } (bex_cal.cells[i].date)
                         );
                }
                else
                    if (quitRanges.TooSoonRange
                        && (tooSoonRange.startDateObj <= bex_cal.cells[i].date)
                        && (bex_cal.cells[i].date <= tooSoonRange.endDateObj)) {
                    // Too Soon
                    $(bex_cal.cells[i].tableCell).attr('style', 'background-color: #DCDCDC; color: #aaa;');
                    $(bex_cal.cells[i].tableCell).mouseout(function() { document.calendarHelper.monthlyCalendar.takeBaloonAway() });
                    $(bex_cal.cells[i].tableCell).mousemove(
                                            function(e) { document.calendarHelper.monthlyCalendar.hoverNextTwoWeeks(e); });
                    $(bex_cal.cells[i].tableCell).bind('mousedown',
                                function(d) {
                                    return function() {
                                        document.calendarHelper.monthlyCalendar.clickedNextTwoWeeks(d);
                                    }
                                } (bex_cal.cells[i].date)
                             );
                }
                else
                // Just Right!
                    if ((quitRanges.OKRange
                        && (okRange.startDateObj <= bex_cal.cells[i].date))
                        ||
                        (quitRanges.TooSoonRange
                        && (bex_cal.cells[i].date > tooSoonRange.endDateObj))) {
                    $(bex_cal.cells[i].tableCell).mouseout(function() { document.calendarHelper.monthlyCalendar.takeBaloonAway() });
                    $(bex_cal.cells[i].tableCell).mousemove(
                                    function(e) { document.calendarHelper.monthlyCalendar.hoverAfterTwoWeeks(e); });
                    $(bex_cal.cells[i].tableCell).bind('mousedown',
                                        function(d) {
                                            return function() {
                                                document.calendarHelper.monthlyCalendar.clickedAfterTwoWeeks(d);
                                            }
                                        } (bex_cal.cells[i].date)
                                     );
                }
            }
            else {
                // Not a Quit Mode:
                $(bex_cal.cells[i].tableCell).unbind('mousedown');
                $(bex_cal.cells[i].tableCell).removeAttr('style');


                if (bex_cal.cells[i].cellClass != 'notmnth' && bex_cal.cells[i].cellClass != 'notmnth curdate') {
                    // Normal monthly calendar browsing - go to day calendar
                    if (bex_cal.cells[i].date <= endDate) {
                        dateParams = bex_cal.cells[i].date.getFullYear() + ','
	                        + bex_cal.cells[i].date.getMonth() + ','
	                        + bex_cal.cells[i].date.getDate() + ','
	                        + bex_cal.cells[i].date.getHours();
                        $(bex_cal.cells[i].tableCell).bind('mousedown',
                            function(dp) {
                                return function() {
                                    window.location.href = 'javascript:document.calendarHelper.dailyCalendar.goToDate(new Date(' + dp + '));'
                                    + 'document.calendarHelper.SwitchMode("day", "click");';
                                }
                            } (dateParams)
                        );
                    }
                }
            } // else
        } // for
    };


    this.setData = function(smokingEventObjArr) {
    //Extract numbers and create a hash to hold totals per day:
        var monthlyTotalsArr = new Array();
        var numberCigarettes = 0;
        var day = 0;
        var month = 0;
        var dayTotal = 0;
        for (var i = 0; i < smokingEventObjArr.length; i++) {
            smokingEventObj = smokingEventObjArr[i];
            day = smokingEventObj.DateTime.substr(6, 2) * 1;
            month = smokingEventObj.DateTime.substr(4, 2) * 1;
            numberCigarettes = smokingEventObj.Number;
            monthlyTotalsArr[day] = ((monthlyTotalsArr[day] == undefined) || (monthlyTotalsArr[day] == NaN)) ? 0 : monthlyTotalsArr[day];
            dayTotal = monthlyTotalsArr[day] + numberCigarettes;
            monthlyTotalsArr[day] = dayTotal;
        }
        this.displayMonthlyData(monthlyTotalsArr);
        this.setURLsForCells();
    };
}

function dailyCalendar() {
    this.who = "dailyCalendar";
    this.calTableId = "dailyCalTable";
    this.calTableTemplateId = "dailyCalTableTemplate";
    this.dayMessageTemplateId = "messageTemplateDay";
    this.calHeaderRowName = "dailyHeaders";
    this.calHeaderRowTemplateName = "dailyHeadersTemplate";
    this.calRowName = "timeEntry";
    this.calRowTemplateName = "newRowTemplate";
    this.separator = '|';
    this.util = new util();
    this.timesPresent = new Array();
    this.timesPresentIDs = new Array();
    this.currentDate = null; // first day of the week shown
    this.dailyCalendarObj = document.getElementById("dailyCalTable");
    this.validationHash = new Array();
    this.dayReloading = false;


	this.getDateRangeShown = function() {
	    return (new dateRange(this.currentDate, this.currentDate));
	};


	this.goToDate = function(dateObj) {
	    this.currentDate = dateObj;
	    this.clearDataLines();
	    this.setDailyTop();
	    runningDate = new Date(dateObj);
	};

	this.markInvalid = function(elem, rowNum, colName) {
	trace('markInvalid() called');
	trace('rowNum ' + rowNum);
	trace('colName: ' + colName);
	var dc = document.calendarHelper.dailyCalendar;
	    var vh = dc.validationHash;
	    var itemIsPresent = false;
	    for (var item in vh) {
	        if ((vh[item]).toString() == (rowNum + dc.separator + colName)) {
	            itemIsPresent = true;
	            break;
	        }
	    }
	    if (!itemIsPresent) {
	        vh.push(rowNum + this.separator + colName);
	    }
	    $(elem).addClass('error');
	    trace('Validation hash: ' + vh);
	};


	this.removeInvalid = function(elem, rowNum, colName) {
	    var dc = document.calendarHelper.dailyCalendar;
	    var vh = dc.validationHash;
	    var itemIsPresent = false;
	    if (vh.length > 0) {
	        for (var item in vh) {
	            if ((vh[item]).toString() == (rowNum + dc.separator + colName)) {
	                delete vh[item];
	                break;
	            }
	        }
	    }
	    $(elem).removeClass('error');

	    trace('Validation hash: ' + vh);
	};


	this.validationPassed = function() {
	    var dc = document.calendarHelper.dailyCalendar;
	    var vh = dc.validationHash;
	    var passed = true;

	    /*
	    // This is to disregard any empty rows in validation hash
	    var emptyRows = new Array();
	    var oneRow = null;
	    for (var item in vh) {
	    oneRow = vh[item].split(dc.separator);
	    if (oneRow[1] == 'time' || oneRow[1] == 'trigger' || oneRow[1] == 'urge') {
	    if (emptyRows[oneRow[0]]) {
	    emptyRows[oneRow[0]]++;
	    } else {
	    emptyRows[oneRow[0]] = 1;
	    }
	    }
	    }
	    trace('emptyRows: ' + emptyRows);
	    for (var row in emptyRows) {
	    if (emptyRows[row] < 3) {
	    passed = false;
	    break;
	    }
	    }
	    
	    */
	    for (var item in vh) {
	        if (vh[item]) {
	            passed = false;
	        }
	    }

	    return passed;
	};

	this.addValidation = function() {
	    var rowNumber = -1;
	    var $time = $('#' + this.calTableId + ' div[name="timeEntry"] select[name="time"]');
	    for (var i = 0; i < $time.length; i++) {
	        $($time[i]).unbind('blur');
	        $($time[i]).blur(
	            function(rowNum) {
	                return function() {
	                    if ($(this).val() == '') {
	                        document.calendarHelper.dailyCalendar.markInvalid(this, rowNum, 'time');
	                    } else {
	                        document.calendarHelper.dailyCalendar.removeInvalid(this, rowNum, 'time');
	                    }
	                    $(this).parent().parent().attr('submit', 'yes');
	                }
	            } (i)
	        );
	    }
	    var $trigger = $('#' + this.calTableId + ' div[name="timeEntry"] select[name="trigger"]');
	    for (var i = 0; i < $trigger.length; i++) {
	        $($trigger[i]).unbind('blur');
	        $($trigger[i]).blur(
	            function(rowNum) {
	                return function() {
	                    if ($(this).val() == '') {
	                        document.calendarHelper.dailyCalendar.markInvalid(this, rowNum, 'trigger');
	                    } else {
	                        document.calendarHelper.dailyCalendar.removeInvalid(this, rowNum, 'trigger');
	                    }
	                    $(this).parent().parent().attr('submit', 'yes');
	                }
	            } (i)
	        );
	    }
	    var $cigNum = $('#' + this.calTableId + ' div[name="timeEntry"] input[name="cig"]');
	    for (var i = 0; i < $cigNum.length; i++) {
	        $($cigNum[i]).unbind('blur');
	        $($cigNum[i]).blur(
	            function(rowNum) {
	                return function() {
	                    var reDigits = /^\d+$/;
	                    if ($(this).val().search(reDigits) == -1 || $(this).val() == 0) {
	                        document.calendarHelper.dailyCalendar.markInvalid(this, rowNum, 'cig');
	                    } else {
	                        document.calendarHelper.dailyCalendar.removeInvalid(this, rowNum, 'cig');
	                    }
	                    $(this).parent().parent().attr('submit', 'yes');
	                }
	            } (i)
	        );
	    }
	    var $urge = $('#' + this.calTableId + ' div[name="timeEntry"] select[name="urge"]');
	    for (var i = 0; i < $urge.length; i++) {
	        $($urge[i]).unbind('blur');
	        $($urge[i]).blur(
	            function(rowNum) {
	                return function() {
	                    if ($(this).val() == '') {
	                        document.calendarHelper.dailyCalendar.markInvalid(this, rowNum, 'urge');
	                    } else {
	                        document.calendarHelper.dailyCalendar.removeInvalid(this, rowNum, 'urge');
	                    }
	                    $(this).parent().parent().attr('submit', 'yes');
	                }
	            } (i)
	        );
	    }
	};


	this.nextDay = function() {
	    var tomorrow = new Date();
	    tomorrow.setHours(0, 0, 0);
	    tomorrow.setDate(tomorrow.getDate() + 1);
        var newDate = new Date(this.currentDate);
	    newDate.setDate(this.currentDate.getDate() + 1);
	    if (newDate < tomorrow) {
	        this.goToDate(newDate);
	    } else {
	    	this.clearDataLines();
	    }
	};

	this.prevDay = function() {
	    var newDate = new Date(this.currentDate);
	    newDate.setDate(this.currentDate.getDate() - 1);
	    this.goToDate(newDate);
	};




	///////////////////////////////////////////////////////////////
	// THEN COME THE DISPLAY METHODS, TOUCHING HTML WITHIN DIRECTLY
	///////////////////////////////////////////////////////////////

	// remove all time lines
	this.clearDataLines = function() {
	    this.timesPresent = new Array();
	    this.timesPresentIDs = new Array();		
	    $('.rowTd').remove();
	    $('div[name="timeEntry"]').remove();
	};


	this.makeReadOnly = function(lineId) {
	    // switch row to non-editable state
	    $('#' + lineId).hide();
	    var time = $('#' + lineId + ' select[name = "time"] option:selected').attr('value');
	    time = this.util.makeNiceTime(time);
	    var trigger = $('#' + lineId + ' select[name = "trigger"] option:selected').text();
	    var cigNum = $('#' + lineId + ' input[name = "cig"]').val();
	    var urge = $('#' + lineId + ' select[name = "urge"] option:selected').text();
	    var notes = $('#' + lineId + ' textarea[name = "notes"]').val();
	    var readOnlyHTML = '<div class="rowTd" id="' + lineId + '-r" title="' + $('#' + this.dayMessageTemplateId + ' div[id=edit]').text() + '">'
            + '<div class="timeTd">' + time + '</div>'
            + '<div class="triggerTd">' + trigger + '</div>'
            + '<div class="numberTd">' + cigNum + '</div>'
            + '<div class="urgeTd">' + urge + '</div>'
            + '<div class="notesTd">' + notes + '</div>'
            + '</div>';
	    $('#' + lineId).before(readOnlyHTML);
	    var $newRow = $('#' + lineId + '-r');
	    $newRow.click(function(lineID) {
	        return function() {
	            BEXTracker.CalendarTracker_EditEventRow();
	            $(this).hide();
	            $('#' + lineID).attr('submit', 'yes');
	            $('#' + lineID).show();
	            $newRow.remove();
	        }
	    } (lineId)
	    );
	};


	this.addNewLineInsertSort = function(day, time, eventID, newLineHTML) {
	    if (this.timesPresent.length == 0) {
	        // no data rows yet
	        $('#' + this.calTableId ).append(newLineHTML);
	        return;
	    }
	    if (time == undefined) {
	        // just a new empty row
	        $('#' + this.calTableId ).append(newLineHTML);
	        return;
	    }
	    time = time * 1;
	    for (var i = 0; i < this.timesPresent.length; i++) {
	        var runningTime = this.timesPresent[i] * 1;
	        if (time < runningTime) {
	            runningTime = runningTime + '';
	            var eventsForTime = this.timesPresentIDs[runningTime].split(this.separator);
	            var firstEventForTime = eventsForTime[0];
	            $('#row-' + firstEventForTime + '-r').before(newLineHTML);
	            return;
	        }
	    }
	    // Incoming data time is after the last data available
	    $('#' + this.calTableId ).append(newLineHTML);
	    return;
	};

	this.addNewLineManual = function() {
		BEXTracker.CalendarTracker_AddEventRows();
		this.addNewLine();
	};

	this.addNewLine = function(day, time, eventID) {
	    if (!day) {
	        day = this.currentDate.getDate();
	        day = (day < 10) ? ('0' + day.toString()) : day.toString();
	    }
	    var newLineHTML = '<div name="' + this.calRowName + '">'
	        + $('#' + this.calTableTemplateId + ' ' + 'div[name=' + this.calRowTemplateName + ']').html()
	        + '</div>';
	    if (time) {
	        var newId = 'row-' + eventID;
	        newLineHTML = $(newLineHTML).attr('id',newId);
	    }
	    this.addNewLineInsertSort(day, time, eventID, newLineHTML);
	    if (!time) {
	        $('#' + this.calTableId + ' div:last').attr('submit', 'yes');
	    }
	    this.addValidation();

	    return 'row-' + eventID;
	};


	this.setDailyTop = function() {
	    $('#' + this.calTableId).append('<div name="' + this.calHeaderRowName + '"></div>');
	    $('#' + this.calTableId + ' div:first')
	        .html($('#' + this.calTableTemplateId + ' ' + 'div[name=' + this.calHeaderRowTemplateName + ']').html());
	};


	this.setDataTime = function(time, eventID) {
		$('#row-' + eventID + ' select[name="time"] option[value="' + time + '"]').attr('selected', 'selected');
	};

	this.setDataTrigger = function(eventID, triggerId) {
		$('#row-' + eventID + ' select[name="trigger"] option[value=' + triggerId + ']').attr('selected', 'selected');
    };

    this.setDataCigarettes = function(eventID, cigNum) {
    	$('#row-' + eventID + ' input[name="cig"]').val(cigNum);
    };

    this.setDataUrge = function(eventID, urgeId) {
    	$('#row-' + eventID + ' select[name="urge"] option[value=' + urgeId + ']').attr('selected', 'selected');
    };

    this.setDataNotes = function(eventID, comment) {
    	$('#row-' + eventID + ' textarea[name="notes"]').val(comment);
    };

    // will require methods to deal with an extra row addition, data submission, etc
    this.timeIsPresent = function(time) {
        var flag = false;
        for (var i = 0; i < this.timesPresent.length; i++) {
            if (this.timesPresent[i] == time) {
                flag = true;
                break;
            }
        }
        return flag;
    };

    this.setDataPoint = function(smokingEventObj) {
        var day = smokingEventObj.DateTime.substr(6, 2);
        var time = smokingEventObj.DateTime.substr(8, 2);
        var numTime = time * 1 + '';
        var eventID = smokingEventObj.SmokingEventID;
        var numberCigarettes = smokingEventObj.Number;
        var comment = (smokingEventObj.Comment != 'null') ? smokingEventObj.Comment : '';
        var newLineId = this.addNewLine(day, time, eventID);
        if (!this.timeIsPresent(numTime)) {
            this.timesPresent.push(numTime);
        }
        if (this.timesPresentIDs[numTime]) {
            if (this.timesPresentIDs[numTime].indexOf(smokingEventObj.SmokingEventID) == -1) {
                this.timesPresentIDs[numTime] += this.separator + smokingEventObj.SmokingEventID;
            }
        } else {
            this.timesPresentIDs[numTime] = smokingEventObj.SmokingEventID + '';
        }
        this.timesPresent.sort(function(a, b) { return (a - b) });

        this.setDataTime(time, eventID);
        this.setDataTrigger(eventID, smokingEventObj.TriggerId);
        this.setDataCigarettes(eventID, numberCigarettes);
        this.setDataUrge(eventID, smokingEventObj.UrgeId);
        this.setDataNotes(eventID, comment);
        this.makeReadOnly(newLineId);
    };

	// sets the day data
    this.setData = function(smokingEventObjArr) {
        if (smokingEventObjArr.length == 0) {
            this.addNewLine(null, null);
            this.addNewLine(null, null);
            this.addNewLine(null, null);
        }
        for (i = 0; i < smokingEventObjArr.length; i++) {
            this.setDataPoint(smokingEventObjArr[i]);
        }

        this.addValidation();
    };

    this.cleanupEventTime = function(newTime, eventID) {
        //        newId is already present? (loop through all times and all event IDs)
        //        If yes, find the time it linked to and remove the eventID if it is not the same time.
        //        If no more eventIDs per time left, remove the time.

        var eventsInTime = null;
        var newEventsForTime = '';
        for (var t in this.timesPresent) {
            eventsInTime = this.timesPresentIDs[this.timesPresent[t]].split(this.separator);
            if (this.timesPresent[t] != newTime) {
                if (eventsInTime.length == 1 && eventsInTime[0] == eventID) {
                    //trace('Deleting: ' + this.timesPresentIDs[this.timesPresent[t]] + ' at ' + this.timesPresent[t]);
                    delete this.timesPresentIDs[this.timesPresent[t]];
                    delete this.timesPresent[t];
                    break;
                } else if (eventsInTime.length > 1) {
                    for (var i = 0; i < eventsInTime.length; i++) {
                        if (eventsInTime[i] != eventID) {
                            newEventsForTime = newEventsForTime + '' + eventsInTime[i] + this.separator;
                        }
                    }
                    newEventsForTime = newEventsForTime.substring(0, newEventsForTime.lastIndexOf(this.separator));
                    this.timesPresentIDs[this.timesPresent[t]] = newEventsForTime;
                }
            }
        }

    };

    this.updateDailyCalendar = function(response, eventData) {
        if (response.IsSuccess) {
        	
            // this is the callback for editing/creating a cigarette tracker event
            BEXTracker.trackOmnitureEvent('event7');
        	
            var dc = document.calendarHelper.dailyCalendar;
            if ( !dc.dayReloading ) {
            	dc.dayReloading = true;
            	document.calendarHelper.RefreshCalendarWithNewData('day');
            }
            
            /*
            var dc = document.calendarHelper.dailyCalendar;
            var newId = response.ResponseData.SmokingEventID;
            var numTime = eventData.time * 1 + '';

            var newLineHTML = '<div class="editRow" id="row-' + newId + '" name="timeEntry">'
                + $(eventData.row).html() + '</div>';
            // In case brand new line leftover:
            //$('#' + dc.calTableId + ' div[submit="yes"]').remove();
            //$('#row-' + newId).remove();

            //dc.cleanupEventTime(numTime, newId);
            dc.addNewLineInsertSort(eventData.day, numTime, newId, newLineHTML);
            $('#row-' + newId).hide();
            dc.setDataTime(eventData.time, newId);
            dc.setDataTrigger(newId, eventData.trigger);
            dc.setDataCigarettes(newId, eventData.cig);
            dc.setDataUrge(newId, eventData.urge);
            dc.setDataNotes(newId, eventData.notes);
            dc.makeReadOnly('row-' + newId);
            var presentIDs = dc.timesPresentIDs;
            if (!dc.timeIsPresent(numTime)) {
                dc.timesPresent.push(numTime);
            }
            if (presentIDs[numTime]) {
                if (presentIDs[numTime].indexOf(newId) == -1) {
                    presentIDs[numTime] += dc.separator + newId;
                }
            } else {
                presentIDs[numTime] = newId + '';
            }
            dc.timesPresent.sort(function(a, b) { return (a - b) });
            */
        }
    };

    // writes daily data back to DB
    this.submitLines = function() {
        if (!document.calendarHelper.loggedIn) {
            registerNow();
            return;
        }
        if (!this.validationPassed()) {
            validationPopup($('#' + this.dayMessageTemplateId + ' td[id=validation]').text());
            return;
        }
        
        BEXTracker.CalendarTracker_SaveData();
                
        //var $dataRows = $('#' + this.calTableId + ' tr[submit="yes"]');
        var $dataRows = $('#' + this.calTableId + ' div[name="timeEntry"]');
        
        var rowID = null;
        var eventDate = this.util.makeAPIdate(this.currentDate);
        for (var i = 0; i < $dataRows.length; i++) {
        	
            if ( $dataRows[i].getAttribute('submit') !== 'yes' ) {
                continue;
            }
        	
            var day = '';
            var eventID = '';
            var newTime = $('select[name="time"]', $dataRows)[i].value;
            var newTrigger = $('select[name="trigger"]', $dataRows)[i].value;
            var newCigNum = $('input[name="cig"]', $dataRows)[i].value;
            var newUrge = $('select[name="urge"]', $dataRows)[i].value;
            var newNotes = $('textarea[name="notes"]', $dataRows)[i].value;
            rowID = $dataRows[i].id;
            if (rowID) {
                eventID = rowID.substr(4);
            }
            if (newTime && newTrigger && newCigNum && newUrge) {
            	
            	// block out the calendar while it's saving/updating here
            	$('#CalendarReloading').remove();
            	$('#dayCal').prepend('<div id="CalendarReloading"></div>');
            	$('#CalendarReloading').css({
            			'opacity' : .5,
            			'background' : '#fff',
            			'position' : 'absolute',
            			'top' : $('#CalendarReloading').position().top,
            			'left' : 0,
            			'width' : '100%',
            			'bottom' : 0,
            			'z-index' : 5000
            	});
            	
                BEXAPI.WriteSmokingEvent(
                	eventID,
                    eventDate + '' + newTime,
                    newCigNum,
                    newTrigger,
                    newUrge,
                    newNotes,
                    this.updateDailyCalendar,
                    { 'day': day, 'time': newTime, 'trigger': newTrigger, 'cig': newCigNum,
                        'urge': newUrge, 'notes': newNotes, 'row': $dataRows[i]
                    });
            }
            else if (newTime == '' && newTrigger == ''
                && newCigNum == 1
                && newUrge == '' && newNotes == '') {
                    $($dataRows[i]).remove();
            } else {
                var newTime = $('select[name="time"]', $dataRows)[i].value;
                if (newTime == '') this.markInvalid($('select[name="time"]', $dataRows)[i], i, 'time');
                var newTrigger = $('select[name="trigger"]', $dataRows)[i].value;
                if (newTrigger == '') this.markInvalid($('select[name="trigger"]', $dataRows)[i], i, 'trigger');
                var newUrge = $('select[name="urge"]', $dataRows)[i].value;
                if (newUrge == '') this.markInvalid($('select[name="urge"]', $dataRows)[i], i, 'urge');
                validationPopup($('#' + this.dayMessageTemplateId + ' td[id=validation]').text());
            }
        }
        document.calendarHelper.calMode = 'day';
        //document.calendarHelper.Init();
    };
}

// Utitlity functions
function util() {

    this.toggleDay = function() {
        $("#dayCal").show();
        $(".dayNav").addClass("on");
        $("#weekCal").hide();
        $(".weekNav").removeClass("on");
        $("#monthCal").hide();
        $(".monthNav").removeClass("on");
    };

    this.toggleWeek = function() {
        $("#dayCal").hide();
        $(".dayNav").removeClass("on");
        $("#weekCal").show();
        $(".weekNav").addClass("on");
        $("#monthCal").hide();
        $(".monthNav").removeClass("on");
    };

    this.toggleMonth = function() {
        $("#dayCal").hide();
        $(".dayNav").removeClass("on");
        $("#weekCal").hide();
        $(".weekNav").removeClass("on");
        $("#monthCal").show();
        $(".monthNav").addClass("on");
        $('#bex_cal_calendar tr:first').hide();
        $('#bex_cal_calendar tr:last').hide();

    };


    this.makeDateFromAPI = function(dateAPI) {
        // yyyymmddtt
        var newDate = new Date(dateAPI.substr(0, 4), dateAPI.substr(4, 2) - 1, dateAPI.substr(6, 2), dateAPI.substr(8, 2));
        return newDate;
    };


    this.makeAPIdate = function(date) {
        var strDate = date.getFullYear() + '';
        var month = date.getMonth() + 1;
        strDate += (month < 10) ? ('0' + month) : (month + '')
        strDate += (date.getDate() < 10) ? ('0' + date.getDate()) : (date.getDate() + '');
        return strDate;
    };


    this.makeNiceTime = function(time) {
        var newTime = '';
        var hour = time % 12;
        hour = (time == 12) ? 12 : hour;
        hour = (hour == 0) ? 12 : hour;
        var dayPart = (time - 12 >= 0) ? 'pm' : 'am';
        newTime = hour + ':00 ' + dayPart;
        return newTime;
    };


    this.todayIsInRunningMonth = function(dateToTest) {
        var today = new Date();
        today.setHours(12, 0, 0);
        return (today.getFullYear() == dateToTest.getFullYear()
                && today.getMonth() == dateToTest.getMonth());
    };


    this.todayIsInRunningWeek = function(dateToTest) {
        var today = new Date();
        today.setHours(12, 0, 0);        
        var weekBeginDate = new Date(dateToTest);
        var weekBeginningDay = dateToTest.getDay();
        if (weekBeginningDay != 0) { // not a Sunday? go to Sunday!
            weekBeginDate.setDate(weekBeginDate.getDate() - thisDay);
        }
        weekBeginDate.setHours(0, 0, 0, 1);
        var weekEndDate = new Date(weekBeginDate);
        weekEndDate.setDate(weekBeginDate.getDate() + 6);
        weekEndDate.setHours(23, 59, 59, 0);

        return (weekBeginDate <= today && today <= weekEndDate);
    };
}
