// DateSelector Class v1
// Author:    Serge I. Zolotukhin ( serge@design.ru, http://serge.design.ru/ )
// Updated:   2003-04-21

/*
 * Constructor
 */
function DateSelector( sName, sValue, sPath )
{
	var oSelf = this

	// Путь к картинкам
	this.sClassPath = sPath

	// Нода из BuildSelector()
	this.oSelector = null

	// Название месяцев
	this.aMonths = new Array( 'Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь');
	this.bMonths = new Array ("января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря");

	// Корневой элемент контрола
	this.oNode = document.createElement('table')
	this.oNode.className = 'DS_Control'

	// input[@type='text'] в документе
	this.oInput = this.oNode.insertRow(-1).insertCell(-1).appendChild( this.CreateElement('input', 'text') )
	this.oInput.parentNode.style.borderRightWidth = '0'
	this.oInput.name = sName + '_INPUT'
	this.oInput.value = sValue
	this.oInput.onblur = function() { oSelf.ParseStrToValue(oSelf.oInput.value) }
	this.oInput.onclick = function() { oSelf.HideSelector() }

	// Кнопка
	this.oButton = this.oNode.rows[this.oNode.rows.length-1].insertCell(-1).appendChild( document.createElement('div') )
	this.oButton.parentNode.style.borderLeftWidth = '0'
	this.oButton.appendChild( document.createElement('img') )
	this.oButton.lastChild.src = this.sClassPath + 'dateselector_ar-d.gif'
	this.oButton.onclick = function(oEvent)
	{
		if( !oSelf.oSelector )
		{
			oSelf.ShowSelector(oSelf.iYear, oSelf.iMonth)
		}
		else
		{
			oSelf.HideSelector()
		}
		try { event.cancelBubble = true } catch (oException) { oEvent.stopPropagation() }
	}

	// input[@type='hidden'] в документе
	this.oHidden = this.oNode.lastChild.lastChild.lastChild.appendChild( this.CreateElement('input', 'hidden') )
	this.oHidden.name = sName

	// Автозакрывание селектора
	document.onclick = function() { oSelf.HideSelector() }

	// Текущее значение даты
	this.ParseStrToValue(this.oInput.value)

	this.sClientName = this.GetClientName()

	return this
}

/*
 * Private
 */

// Установить внутренние значения даты
DateSelector.prototype.SetValue = function( iYear, iMonth, iDay )
{
	if(
		( (iYear > 9 && iYear < 100) || (iYear > 999 && iYear < 10000) ) &&
		( iMonth > 0 && iMonth < 13 ) &&
		( iDay <= this.GetDaysCountByMonth(iYear, iMonth) )
	)
	{
		this.iYear = iYear
		this.iMonth = iMonth
		this.iDay = iDay
		//this.oInput.value = iDay + ' ' + this.bMonths[iMonth-1].toLowerCase() + ' ' + iYear; //substr(0,3)
		this.oInput.value = iDay + '.' + iMonth + '.' + iYear; //substr(0,3)
		this.oHidden.value = iYear + '-' + iMonth + '-' + iDay
	}
	else
	{
		this.oInput.value = this.iDay + '.' + this.iMonth + '.' + this.iYear; //substr(0,3)
		//this.oInput.value = this.iDay + ' ' + this.aMonths[this.iMonth-1].toLowerCase() + ' ' + this.iYear; //substr(0,3)
		this.oHidden.value = this.iYear + '-' + this.iMonth + '-' + this.iDay
	}
}

// Отпарсить строку и попробовать получить три int: iYear, iMonth, iDay
DateSelector.prototype.ParseStrToValue = function( sStr )
{
	var re, aResult

	// '2003-4-16'
	re = /^(\d{2,4})\-(\d{1,2})\-(\d{1,2})$/
	aResult = re.exec(sStr)
	if( aResult )
	{
		this.SetValue( aResult[1], aResult[2], aResult[3] )
		return true
	}

	// '16.4.2003', '16/4/2003', '16 4 2003'
	re = /^(\d{1,2})[\.\/\s](\d{1,2})[\.\/\s](\d{2,4})$/
	aResult = re.exec(sStr)
	if( aResult )
	{
		this.SetValue( aResult[3], aResult[2], aResult[1] )
		return true
	}

	// '16-апр-2003', '16 апр 2003'
	re = /^(\d{1,2})[\s\.\-]([a-я]+)[\s\.\-](\d{2,4})$/i
	aResult = re.exec(sStr)
	if( aResult )
	{
		for( var i=0; i<this.aMonths.length; i++ )
		{
			var sMonthNormalized = this.aMonths[i].toLowerCase()
			if( sMonthNormalized.indexOf(aResult[2].toLowerCase()) == 0 )
			{
				this.SetValue( aResult[3], i+1, aResult[1] )
				return true
			}
		}
	}

	return false
}

// Вернуть количество дней в заданном месяце
DateSelector.prototype.GetDaysCountByMonth = function( iYear, iMonth )
{
	var dDate = new Date(iYear,iMonth,-1)
	return (dDate.getDate() + 1)
}

// Вернуть "правильное" значение месяца, т.е. вместо 13 -- 1 и вместо 0 -- 12
DateSelector.prototype.GetMonthNumber = function( iMonth )
{
	return ( iMonth < 1 || iMonth > 12 ) ? Math.abs( iMonth-12 ) : iMonth
}

// Вернуть "правильное" значение года по месяцу, т.е. вместо 2003(13) -- 2004(1)
DateSelector.prototype.GetYearNumber = function( iYear, iMonth )
{
	if ( iMonth < 1  ) return ( iYear-1 )
	if ( iMonth > 12 ) return ( parseInt(iYear)+1 )
	return iYear
}

// Приделать ноду с Selector к контролу
DateSelector.prototype.ShowSelector = function( iYear, iMonth )
{
	if ( !this.oSelector )
	{
		this.oButton.className = 'Pushed'
		this.oSelector = this.BuildSelector( this.BuildYearMonthSelector(iYear, iMonth), this.BuildDaySelector(iYear, iMonth) )
		this.oNode.parentNode.appendChild( this.oSelector )
	}
}

// Убить ноду с Selector
DateSelector.prototype.HideSelector = function()
{
	if ( this.oSelector && this.oSelector.parentNode )
	{
		this.oButton.className = ''
		this.oSelector.parentNode.removeChild(this.oSelector)
		this.oSelector = null
	}
}

// "Перерисовать" ноду с Selector к контролу
DateSelector.prototype.RedrawSelector = function( iYear, iMonth )
{
	this.HideSelector()
	this.ShowSelector(iYear, iMonth)
}

// Сгенерить ноду с выбором даты
DateSelector.prototype.BuildSelector = function( oYearMonthSelector, oDaySelector )
{
	var oNode = document.createElement('div')

	oNode.appendChild( document.createElement('fieldset') )
	oNode.lastChild.appendChild(oYearMonthSelector)
	oNode.lastChild.appendChild(oDaySelector)

	oNode.className = 'DS_Selector'
	// Эта заплатка сделана потому, что Moz и MSIE по-разному трактуют CSS
	oNode.style.width = ( this.sClientName == 'msie' ) ? '1%' : ''

	return oNode
}

// Сгенерить ноду с выбором месяца и года. Текущие значения установить в iYear, iMonth
// Такая замороченная нода получилась coz of moz
DateSelector.prototype.BuildYearMonthSelector = function( iYear, iMonth )
{
	var oCurrentRow, oNode
	var oSelf = this

	oNode = document.createElement('div')
	oNode.className = 'DS_YearmonthSelector'
	oNode.appendChild( document.createElement('table') )

	oCurrentRow = oNode.lastChild.insertRow(-1)
	oCurrentRow.insertCell(-1).appendChild( document.createElement('img') )
	oCurrentRow.lastChild.lastChild.src = this.sClassPath + 'dateselector_ar-l.gif'
	oCurrentRow.lastChild.lastChild.alt = this.aMonths[ this.GetMonthNumber(iMonth-1) - 1 ] + ' ' + this.GetYearNumber(iYear, iMonth-1)
	oCurrentRow.lastChild.lastChild.setAttribute('month', this.GetMonthNumber(iMonth-1))
	oCurrentRow.lastChild.lastChild.setAttribute('year', this.GetYearNumber(iYear, iMonth-1))
	oCurrentRow.lastChild.lastChild.onclick = function() { oSelf.RedrawSelector( this.getAttribute('year'), this.getAttribute('month') ) }

	oCurrentRow.insertCell(-1).appendChild( document.createTextNode( this.aMonths[iMonth-1] + ' ' + iYear ) )
	oCurrentRow.lastChild.style.textAlign = 'center'

	oCurrentRow.insertCell(-1).appendChild( document.createElement('img') )
	oCurrentRow.lastChild.style.textAlign = 'right'
	oCurrentRow.lastChild.lastChild.src = this.sClassPath + 'dateselector_ar-r.gif'
	oCurrentRow.lastChild.lastChild.alt = this.aMonths[ this.GetMonthNumber(parseInt(iMonth)+1) - 1 ] + ' ' + this.GetYearNumber(iYear, parseInt(iMonth)+1)
	oCurrentRow.lastChild.lastChild.setAttribute('month', this.GetMonthNumber(parseInt(iMonth)+1))
	oCurrentRow.lastChild.lastChild.setAttribute('year', this.GetYearNumber(iYear, parseInt(iMonth)+1))
	oCurrentRow.lastChild.lastChild.onclick = function() { oSelf.RedrawSelector( this.getAttribute('year'), this.getAttribute('month') ) }

	return oNode
}

// Сгенерить ноду с выбором дня месяца iMonth года iYear
DateSelector.prototype.BuildDaySelector = function( iYear, iMonth )
{
	var oNode, i, j, oCurrentRow
	var oSelf = this
	var aDayOfWeekTitles = new Array('пн','вт','ср','чт','пт','сб','вс')
	var dFirstDay = new Date(iYear,iMonth-1,0)
	var iDaysCount = this.GetDaysCountByMonth(iYear,iMonth)

	oNode = document.createElement('table')
	oNode.className = 'DS_DaySelector'

	// Нужно отбить позицию до требумого дня недели
	oCurrentRow = oNode.insertRow(-1)

	for ( i=0; i<dFirstDay.getDay(); i++ ) oCurrentRow.insertCell(-1)

	// Собственно числа месяца
	for ( i=0; i<iDaysCount; i++ )
	{
		if ( (i+dFirstDay.getDay())%7 == 0 ) oCurrentRow = oNode.insertRow(-1)
		oCurrentRow.insertCell(-1).appendChild( document.createElement('span') ).appendChild( document.createTextNode(i+1) )
		oCurrentRow.lastChild.className = ( this.iYear == iYear && this.iMonth == iMonth && this.iDay == i+1 ) ? 'DS_Selected' : ''
		oCurrentRow.lastChild.onclick = function()
		{
			// Процедура выбора дня
			oSelf.SetValue( iYear, iMonth, this.lastChild.lastChild.nodeValue )
			oSelf.HideSelector()
		}
	}

	// Заголовок с днями недели
	oNode.createTHead().insertRow(0)
	for ( i=0; i<aDayOfWeekTitles.length; i++ )
	{
		oNode.tHead.rows[0].insertCell(i).appendChild( document.createTextNode(aDayOfWeekTitles[i]) )
	}

	return oNode
}

// Определение типа клиекта. Блин, не хотел я этого делать, но пришлось...
// Возвращает: msie|opera|mozilla
DateSelector.prototype.GetClientName = function()
{
	// Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.10 [en] 
	if( navigator.userAgent.indexOf('Opera') != -1 ) return 'opera'

	// Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3) Gecko/20030312
	if( navigator.userAgent.indexOf('Gecko') != -1 ) return 'mozilla'

	// Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705) 
	if( navigator.userAgent.indexOf('MSIE') != -1 ) return 'msie'
}

// Надо бы передеать createElement ...
// TODO: посмотреть такую функциональность на других браузерах
DateSelector.prototype.CreateElement = function( sNodeName, sTypeAttr )
{
	if( this.sClientName == 'msie' )
	{
		return document.createElement('<'+sNodeName+' type="'+sTypeAttr+'"/>')
	}
	else
	{
		var oElement = document.createElement(sNodeName)
		oElement.setAttribute('type', sTypeAttr)
		return oElement
	}
}

