/*!
 * Piwik - Web Analytics
 *
 * @link http://piwik.org
 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
 */
(function($) {

Date.prototype.getWeek = function() {
	var onejan = new Date(this.getFullYear(),0,1), // needed for getDay()
		
		// use UTC times since getTime() can differ based on user's timezone
		onejan_utc = Date.UTC(this.getFullYear(),0,1),
		this_utc = Date.UTC(this.getFullYear(),this.getMonth(),this.getDate()),
		
		daysSinceYearStart = (this_utc - onejan_utc) / 86400000; // constant is millisecs in one day
	
	return Math.ceil((daysSinceYearStart + onejan.getDay()) / 7);
}

var currentYear, currentMonth, currentDay, currentDate, currentWeek;
function setCurrentDate( dateStr )
{
	var splitDate = dateStr.split("-");
	currentYear = splitDate[0];
	currentMonth = splitDate[1] - 1;
	currentDay = splitDate[2];
	currentDate = new Date(currentYear, currentMonth, currentDay);
	currentWeek = currentDate.getWeek();
}

setCurrentDate(piwik.currentDateString);

var todayDate = new Date;
var todayMonth = todayDate.getMonth();
var todayYear = todayDate.getFullYear();
var todayDay = todayDate.getDate();

// min/max date for picker
var piwikMinDate = new Date(piwik.minDateYear, piwik.minDateMonth - 1, piwik.minDateDay),
	piwikMaxDate = new Date(piwik.maxDateYear, piwik.maxDateMonth - 1, piwik.maxDateDay);

// we start w/ the current period
var selectedPeriod = piwik.period;

function isDateInCurrentPeriod( date )
{
	// if the selected period isn't the current period, don't highlight any dates
	if (selectedPeriod != piwik.period)
	{
		return [true, ''];
	}
	
	var valid = false;

	var dateMonth = date.getMonth();
	var dateYear = date.getFullYear();
	var dateDay = date.getDate();
	var style = '';

	// we don't color dates in the future
	if( dateMonth == todayMonth
		&& dateYear == todayYear
		&& dateDay > todayDay
	)
	{
		return [true, ''];
	}

	// we don't color dates before the minimum date
	if( dateYear < piwik.minDateYear
		|| ( dateYear == piwik.minDateYear
				&&
					(
						(dateMonth == piwik.minDateMonth - 1
						&& dateDay < piwik.minDateDay)
					||  (dateMonth < piwik.minDateMonth - 1)
				)
			)
	)
	{
		return [true, ''];
	}

	// we color all day of the month for the same year for the month period
	if(piwik.period == "month"
		&& dateMonth == currentMonth
		&& dateYear == currentYear
	)
	{
		valid = true;
	}
	// we color all day of the year for the year period
	else if(piwik.period == "year"
			&& dateYear == currentYear
	)
	{
		valid = true;
	}
	else if(piwik.period == "week"
			&& date.getWeek() == currentWeek
			&& dateYear == currentYear
	)
	{
		valid = true;
	}
	else if( piwik.period == "day"
				&& dateDay == currentDay
				&& dateMonth == currentMonth
				&& dateYear == currentYear
		)
	{
		valid = true;
	}

	if(valid)
	{
		return [true, 'ui-datepicker-current-period'];
	}

	return [true, ''];
}

piwik.getBaseDatePickerOptions = function(defaultDate)
{
	return {
		showOtherMonths: false,
		dateFormat: 'yy-mm-dd',
		firstDay: 1,
		minDate: piwikMinDate,
		maxDate: piwikMaxDate,
		prevText: "",
		nextText: "",
		currentText: "",
		defaultDate: defaultDate,
		changeMonth: true,
		changeYear: true,
		stepMonths: 1,
		// jquery-ui-i18n 1.7.2 lacks some translations, so we use our own
		dayNamesMin: [
			_pk_translate('General_DaySu_js'),
			_pk_translate('General_DayMo_js'),
			_pk_translate('General_DayTu_js'),
			_pk_translate('General_DayWe_js'),
			_pk_translate('General_DayTh_js'),
			_pk_translate('General_DayFr_js'),
			_pk_translate('General_DaySa_js')],
		dayNamesShort: [
			_pk_translate('General_ShortDay_1_js'),
			_pk_translate('General_ShortDay_2_js'),
			_pk_translate('General_ShortDay_3_js'),
			_pk_translate('General_ShortDay_4_js'),
			_pk_translate('General_ShortDay_5_js'),
			_pk_translate('General_ShortDay_6_js'),
			_pk_translate('General_ShortDay_7_js')],
		dayNames: [
			_pk_translate('General_LongDay_1_js'),
			_pk_translate('General_LongDay_2_js'),
			_pk_translate('General_LongDay_3_js'),
			_pk_translate('General_LongDay_4_js'),
			_pk_translate('General_LongDay_5_js'),
			_pk_translate('General_LongDay_6_js'),
			_pk_translate('General_LongDay_7_js')],
		monthNamesShort: [
			_pk_translate('General_ShortMonth_1_js'),
			_pk_translate('General_ShortMonth_2_js'),
			_pk_translate('General_ShortMonth_3_js'),
			_pk_translate('General_ShortMonth_4_js'),
			_pk_translate('General_ShortMonth_5_js'),
			_pk_translate('General_ShortMonth_6_js'),
			_pk_translate('General_ShortMonth_7_js'),
			_pk_translate('General_ShortMonth_8_js'),
			_pk_translate('General_ShortMonth_9_js'),
			_pk_translate('General_ShortMonth_10_js'),
			_pk_translate('General_ShortMonth_11_js'),
			_pk_translate('General_ShortMonth_12_js')],
		monthNames: [
			_pk_translate('General_MonthJanuary_js'),
			_pk_translate('General_MonthFebruary_js'),
			_pk_translate('General_MonthMarch_js'),
			_pk_translate('General_MonthApril_js'),
			_pk_translate('General_MonthMay_js'),
			_pk_translate('General_MonthJune_js'),
			_pk_translate('General_MonthJuly_js'),
			_pk_translate('General_MonthAugust_js'),
			_pk_translate('General_MonthSeptember_js'),
			_pk_translate('General_MonthOctober_js'),
			_pk_translate('General_MonthNovember_js'),
			_pk_translate('General_MonthDecember_js')]
	};
};

var updateDate;
function getDatePickerOptions()
{
	var result = piwik.getBaseDatePickerOptions(currentDate);
	result.beforeShowDay = isDateInCurrentPeriod;
	result.stepMonths = selectedPeriod == 'year' ? 12 : 1;
	result.onSelect = function () { updateDate.apply(this, arguments); };
	return result;
};

$(document).ready(function() {
	
	var datepickerElem = $('#datepicker').datepicker(getDatePickerOptions()),
		periodLabels = $('#periodString .period-type label'),
		periodTooltip = $('#periodString .period-click-tooltip').html();
	
	var toggleWhitespaceHighlighting = function (klass, toggleTop, toggleBottom)
	{
		var viewedYear = $('.ui-datepicker-year', datepickerElem).val(),
			viewedMonth = +$('.ui-datepicker-month', datepickerElem).val(), // convert to int w/ '+'
			firstOfViewedMonth = new Date(viewedYear, viewedMonth, 1),
			lastOfViewedMonth = new Date(viewedYear, viewedMonth + 1, 0);
		
		// only highlight dates between piwik.minDate... & piwik.maxDate...
		// we select the cells to highlight by checking whether the first & last of the
		// currently viewed month are within the min/max dates.
		if (firstOfViewedMonth >= piwikMinDate)
		{
			$('tbody>tr:first-child td.ui-datepicker-other-month', datepickerElem).toggleClass(klass, toggleTop);
		}
		if (lastOfViewedMonth < piwikMaxDate)
		{
			$('tbody>tr:last-child td.ui-datepicker-other-month', datepickerElem).toggleClass(klass, toggleBottom);
		}
	};
	
	// 'this' is the table cell
	var highlightCurrentPeriod = function ()
	{
		switch (selectedPeriod)
		{
			case 'day':
				// highlight this link
				$('a', $(this)).addClass('ui-state-hover');
				break;
			case 'week':
				var row = $(this).parent();
				
				// highlight parent row (the week)
				$('a', row).addClass('ui-state-hover');
				
				// toggle whitespace if week goes into previous or next month. we check if week is on
				// top or bottom row.
				var toggleTop = row.is(':first-child'),
					toggleBottom = row.is(':last-child');
				toggleWhitespaceHighlighting('ui-state-hover', toggleTop, toggleBottom);
				break;
			case 'month':
				// highlight all parent rows (the month)
				$('a', $(this).parent().parent()).addClass('ui-state-hover');
				break;
			case 'year':
				// highlight table (month + whitespace)
				$('a', $(this).parent().parent()).addClass('ui-state-hover');
				toggleWhitespaceHighlighting('ui-state-hover', true, true);
				break;
		}
	};
	
	var unhighlightAllDates = function ()
	{
		// make sure nothing is highlighted 
		$('.ui-state-active,.ui-state-hover', datepickerElem).removeClass('ui-state-active ui-state-hover');
		
		// color whitespace
		if (piwik.period == 'year')
		{
			var viewedYear = $('.ui-datepicker-year', datepickerElem).val(),
				toggle = selectedPeriod == 'year' && currentYear == viewedYear;
			toggleWhitespaceHighlighting('ui-datepicker-current-period', toggle, toggle);
		}
		else if (piwik.period == 'week')
		{
			var toggleTop = $('tr:first-child a', datepickerElem).parent().hasClass('ui-datepicker-current-period'),
				toggleBottom = $('tr:last-child a', datepickerElem).parent().hasClass('ui-datepicker-current-period');
			toggleWhitespaceHighlighting('ui-datepicker-current-period', toggleTop, toggleBottom);
		}
	};
	
	updateDate = function (dateText)
	{
		piwikHelper.showAjaxLoading('ajaxLoadingCalendar');
		var date = dateText;
	
		// select new dates in calendar
		setCurrentDate(dateText);
		piwik.period = selectedPeriod;
		
		// make sure it's called after jquery-ui is done, otherwise everything we do will
		// be undone.
		setTimeout(unhighlightAllDates, 1);
		
		datepickerElem.datepicker('refresh');
		
		// Let broadcast do its job:
		// It will replace date value to both search query and hash and load the new page.
		broadcast.propagateNewPage('date=' + date + '&period=' + selectedPeriod);
	};

	var toggleMonthDropdown = function (disable)
	{
		if (typeof disable === 'undefined')
		{
			disable = selectedPeriod == 'year';
		}
		
	    // enable/disable month dropdown based on period == year
	    $('.ui-datepicker-month', datepickerElem).attr('disabled', disable);
	};
	
	var togglePeriodPickers = function (showSingle)
	{
		$('#periodString .period-date').toggle(showSingle);
		$('#periodString .period-range').toggle(!showSingle);
		$('#calendarRangeApply').toggle(!showSingle);
	};
	
	//
	// setup datepicker
	//
	
	unhighlightAllDates();
	
	//
	// hook up event slots
	//
	
	// highlight current period when mouse enters date
	datepickerElem.on('mouseenter', 'tbody td', function() {
		if ($(this).hasClass('ui-state-hover')) // if already highlighted, do nothing
		{
			return;
		}
		
		// unhighlight if cell is disabled/blank, unless the period is year
		if ($(this).hasClass('ui-state-disabled') && selectedPeriod != 'year')
		{
			unhighlightAllDates();
			
			// if period is week, then highlight the current week
			if (selectedPeriod == 'week')
			{
				highlightCurrentPeriod.call(this);
			}
		}
		else
		{
			highlightCurrentPeriod.call(this);
		}
	});
	
	// make sure cell stays highlighted when mouse leaves cell (overrides jquery-ui behavior)
	datepickerElem.on('mouseleave', 'tbody td', function () {
		$('a', this).addClass('ui-state-hover');
	});
	
	// unhighlight everything when mouse leaves table body (can't do event on tbody, for some reason
	// that fails, so we do two events, one on the table & one on thead)
	datepickerElem.on('mouseleave', 'table', unhighlightAllDates)
				  .on('mouseenter', 'thead', unhighlightAllDates);
	
	// make sure whitespace is clickable when the period makes it appropriate
	datepickerElem.on('click', 'tbody td.ui-datepicker-other-month', function () {
		if ($(this).hasClass('ui-state-hover'))
		{
			var row = $(this).parent(), tbody = row.parent();
			
			if (row.is(':first-child'))
			{
				// click on first of the month
				$('a', tbody).first().click();
			}
			else
			{
				// click on last of month
				$('a', tbody).last().click();
			}
		}
	});
	
	// Hack to get around firefox bug. When double clicking a label in firefox, the 'click'
	// event of its associated input will not be fired twice. We want to change the period
	// if clicking the select period's label OR input, so we catch the click event on the
	// label & the input.
	var reloading = false;
	var changePeriodOnClick = function(periodInput)
	{
		if (reloading) // if a click event resulted in reloading, don't reload again
		{
			return;
		}
		
		var url = periodInput.val(),
			period = broadcast.getValueFromUrl('period', url);
		
	    // if clicking on the selected period, change the period but not the date
	    if (selectedPeriod == period && selectedPeriod != 'range')
	    {
	    	// only reload if current period is different from selected
	    	if (piwik.period != selectedPeriod && !reloading)
	    	{
	    		reloading = true;
	    		selectedPeriod = period;
	    		updateDate(piwik.currentDateString);
	    	}
	    	return true;
	    }
	    
	    return false;
	};
	
	$("#otherPeriods label").on('click', function(e) {
		var id = $(e.target).attr('for');
		changePeriodOnClick($('#' + id));
	});
	
	// when non-range period is clicked, change the period & refresh the date picker
	$("#otherPeriods input").on('click', function(e) {
	    var request_URL = $(e.target).val(),
	    	period = broadcast.getValueFromUrl('period', request_URL),
	    	lastPeriod = selectedPeriod;
	    
	    if (changePeriodOnClick($(e.target)))
	    {
	    	return true;
	    }
	    
	    // switch the selected period
		selectedPeriod = period;
		
		// remove tooltips from the period inputs
		periodLabels.each(function() { $(this).attr('title', '').removeClass('selected-period-label'); });
		
		// range periods are handled in an event handler below
	    if (period == 'range')
	    {
	    	return true;
	    }
	    
	    // set the tooltip of the current period
		if (period != piwik.period) // don't add tooltip for current period
		{
			$(this).parent().find('label[for=period_id_'+period+']')
				.attr('title', periodTooltip).addClass('selected-period-label');
		}
	    
	    // toggle the right selector controls (show period selector datepicker & hide 'apply range' button)
	    togglePeriodPickers(true);
		
	    // set months step to 12 for year period (or set back to 1 if leaving year period)
	    if (selectedPeriod == 'year' || lastPeriod == 'year')
	    {
			// setting stepMonths will change the month in view back to the selected date. to avoid
			// we set the selected date to the month in view.
			var currentMonth = $('.ui-datepicker-month', datepickerElem).val(),
				currentYear = $('.ui-datepicker-year', datepickerElem).val();
			
	    	datepickerElem
	    		.datepicker('option', 'stepMonths', selectedPeriod == 'year' ? 12 : 1)
		    	.datepicker('setDate', new Date(currentYear, currentMonth));
	    }
	    
	    datepickerElem.datepicker('refresh'); // must be last datepicker call, otherwise cells get highlighted
	    
	    unhighlightAllDates();
	    toggleMonthDropdown();
	    
		return true;
	});
	
	// clicking left/right re-enables the month dropdown, so we disable it again
	$(datepickerElem).on('click', '.ui-datepicker-next,.ui-datepicker-prev', function() {
		unhighlightAllDates(); // make sure today's date isn't highlighted & toggle extra year highlighting
		toggleMonthDropdown(selectedPeriod == 'year');
	});
	
	// reset date/period when opening calendar
	var firstClick = true;
	$('#periodString #date').click(function() {
		if (!firstClick)
		{
			datepickerElem.datepicker('setDate', currentDate);
			$('#period_id_' + piwik.period).click();
		}
		
		firstClick = false;
	});
	
	function onDateRangeSelect(dateText, inst)
	{
		var toOrFrom = inst.id == 'calendarFrom' ? 'From' : 'To';
		$('#inputCalendar'+toOrFrom).val(dateText);
	}
	
	// this will trigger to change only the period value on search query and hash string.
	$("#period_id_range").on('click', function(e) {
		togglePeriodPickers(false);
		
		var options = getDatePickerOptions();
			 
		// Custom Date range callback
		options.onSelect = onDateRangeSelect;
		// Do not highlight the period
		options.beforeShowDay = '';
		// Create both calendars
		options.defaultDate = piwik.startDateString;
		$('#calendarFrom').datepicker(options).datepicker("setDate", $.datepicker.parseDate('yy-mm-dd', piwik.startDateString));
		
		// Technically we should trigger the onSelect event on the calendar, but I couldn't find how to do that
		// So calling the onSelect bind function manually...
		//$('#calendarFrom').trigger('dateSelected'); // or onSelect
		onDateRangeSelect(piwik.startDateString, { "id": "calendarFrom" } );
		
		// Same code for the other calendar
		options.defaultDate = piwik.endDateString;
		$('#calendarTo').datepicker(options).datepicker("setDate", $.datepicker.parseDate('yy-mm-dd', piwik.endDateString));
		onDateRangeSelect(piwik.endDateString, { "id": "calendarTo" });
		
	
		// If not called, the first date appears light brown instead of dark brown
		$('.ui-state-hover').removeClass('ui-state-hover');
		
		// Apply date range button will reload the page with the selected range
		 	$('#calendarRangeApply')
		 		.on('click', function() {
		 	        var request_URL = $(e.target).val();
		 	        var dateFrom = $('#inputCalendarFrom').val(), 
		 	        	dateTo = $('#inputCalendarTo').val(),
		 	        	oDateFrom = $.datepicker.parseDate('yy-mm-dd', dateFrom),
		 	        	oDateTo = $.datepicker.parseDate('yy-mm-dd', dateTo);
		 	        
		 	        if( !isValidDate(oDateFrom )
		 	        	|| !isValidDate(oDateTo )
		 	        	|| oDateFrom > oDateTo )
		 	        {
		 	        	$('#alert h2').text(_pk_translate('General_InvalidDateRange_js'));
		 	        	piwikHelper.modalConfirm('#alert', {});
		 	        	return false;
		 	        }
		         	piwikHelper.showAjaxLoading('ajaxLoadingCalendar');
		 	        broadcast.propagateNewPage('period=range&date='+dateFrom+','+dateTo);
		 		})
		 		.show();
		
	
		// Bind the input fields to update the calendar's date when date is manually changed
		$('#inputCalendarFrom, #inputCalendarTo')
			.keyup( function (e) {
				var fromOrTo = this.id == 'inputCalendarFrom' ? 'From' : 'To';
				var dateInput = $(this).val();
				try {
				    var newDate = $.datepicker.parseDate('yy-mm-dd', dateInput);
				} catch (e) {
				    return;
				}
				$("#calendar"+fromOrTo).datepicker("setDate", newDate);
				if(e.keyCode == 13) {
					$('#calendarRangeApply').click();
				}
		});
		return true;
	});
	 function isValidDate(d) {
		  if ( Object.prototype.toString.call(d) !== "[object Date]" )
		    return false;
		  return !isNaN(d.getTime());
		}
	
	var period = broadcast.getValueFromUrl('period');
	if (period == 'range')
	{
		$("#period_id_range").click();
	}
});

}(jQuery));
