var CalendarSelections = new Class({
	Implements : [Options, Events],
	
	options :{
		container			: "fullCalendar",
		dayClass			: "day",
		availableClass		: "selectable",
		monthClass			: "month",
		selectedClass		: "selected",
		markedClass			: "marked",
		paddedClass			: "padded",
		timestampAttribute	: "alt",
		
		onCreateRange		: $empty,
		onDaySelectionHover	: $empty,
		onWeekDaySelect		: $empty,
		onWeekDayUnselect	: $empty,
		onInitSelection		: $empty,
		onMouseEnter		: $empty,
		onMouseLeave		: $empty,
		onRangeSeted		: $empty
	},
	
	/*Private*/
	initialDay			: null,
	days				: {},
	selections			: {},
	initialSelected		: false,
	rangesSelected		: [],
	dragging			: false,
	isMouseDown			: false,
	dayCollection		: undefined,
	weekDaysSelected	: [],
	hover				: true,
	
	
	initialize: function(dayCollection, options)
	{
		this.setOptions(options);
		this.dayCollection = dayCollection;
		this.setUp();
	},
	
	setUp: function()
	{
		this.container = $(this.options.container);
		this.container.addEvent("mouseover", function(){this.hover = true}.bind(this));
		this.container.addEvent("mouseleave", function(){this.hover = false}.bind(this));
		
		this.reset();
		document.addEvent("calendarEsc", function(){
			if(this.hover)
			{
				this.resetSelection();
				this.resetWeekDaySelection();
			}
		}.bind(this));
		document.addEvent("leftmouseup",this.documentMouseUpOnDragging.bind(this));
		if($("weekDays"))
		{
			
			$("weekDays").getElements("a").each(function(anchor){
				
				if(!$defined(anchor.selected))
				{
					anchor.selected = false;
				}
				
				anchor.addEvent("click", function(e){e.stop()});
				anchor.addEvent("click", this.weekDayClick.bindWithEvent(this, [anchor]))
				
			}.bind(this));
		}
	},
	
	weekDayClick: function(e, anchor)
	{
		this.resetSelection();
		var dayNum = anchor.get("rel");
		if(anchor.selected)
		{
			this.weekDaysSelected.erase(dayNum);
			this.fireEvent("onWeekDayUnselect", [anchor, this.weekDaysSelected, e]);
			anchor.selected = false;
			this.unSelectSpecificRangeDays(dayNum);
		}
		else
		{
			this.weekDaysSelected.push(dayNum);
			this.fireEvent("onWeekDaySelect", [anchor, this.weekDaysSelected, e]);
			anchor.selected = true;
			this.selectSpecificRangeDays(dayNum);
		}
		
		if(this.weekDaysSelected.length > 0)
		{
			this.initialSelected 			= this.dayCollection.getFirst().getTimestamp();
			this.lastTimestampSelection		= this.dayCollection.getLast().getTimestamp();
			
			this.createRange(e);
			
			this.initialSelected 			= false;
			this.lastTimestampSelection		= false;
		}
		
	},
	
	reset: function()
	{
		this.days = {};
		this.dayCounter = 0;
		this.container.getElements("."+this.options.dayClass+"."+this.options.availableClass).each(this.processDay.bind(this));
	},
	
	selectSpecificRangeDays: function(daysNum)
	{
		if($type(daysNum) != "array")
		{
			daysNum = [daysNum];
		}
		
		daysNum.each(this.dayCollection.highlightSpecificRangeDays.bind(this.dayCollection))
	},
	
	unSelectSpecificRangeDays: function(daysNum)
	{
		if($type(daysNum) != "array")
		{
			daysNum = [daysNum];
		}
		
		daysNum.each(this.dayCollection.unHighlightSpecificRangeDays.bind(this.dayCollection))
	},
	
	processDay: function(dayCell, index)
	{
		
		dayCell.calPosition = index;
		dayCell.addEvent("leftmousedown", 	this.setMouseDown.bind(this, [true]));
		dayCell.addEvent("leftmousedown", 	this.dayClick.bindWithEvent(this, [dayCell, index]));
		
		dayCell.addEvent("mouseenter", 		this.checkDragging.bind(this));
		dayCell.addEvent("mouseenter", 		this.dayMouseEnter.bind(this, [dayCell, index]));

		dayCell.addEvent("mouseenter", 		this.mouseEnter.bindWithEvent(this, [dayCell, index]));
		dayCell.addEvent("mouseleave", 		this.mouseLeave.bindWithEvent(this, [dayCell, index]));
		
		dayCell.addEvent("leftmouseup", 	this.setMouseDown.bind(this, [false]));
		dayCell.addEvent("leftmouseup", 	this.checkMouseUpOnDrag.bindWithEvent(this, [dayCell, index]));
		//dayCell.addEvent("leftmouseup", 	this.checkDragging.bind(this));
		
		
		this.registerDay(dayCell, index);
	},
	
	mouseEnter: function(e, dayCell, index)
	{
		this.fireEvent("onMouseEnter", [e, dayCell, index]);
	},
	
	mouseLeave: function(e, dayCell, index)
	{
		this.fireEvent("onMouseLeave", [e, dayCell, index]);
	},
	
	registerDay: function(dayCell, index)
	{
		var dayTimestamp = dayCell.get(this.options.timestampAttribute);
		
		if(!$defined(this.days[dayTimestamp]))
		{
			this.days[dayTimestamp] = [];
		}
		
		this.days[dayTimestamp].push(dayCell);
	},
	
	selectRange: function(endCell)
	{
		var endTimestamp 		= endCell.get(this.options.timestampAttribute);
		this.fireEvent("onDaySelectionHover", [endTimestamp]);
		this.selectRangeByEndTimestamp(endTimestamp);
	},
	
	selectRangeByEndTimestamp: function(endTimestamp)
	{
		var previousTimestamp 	= this.lastTimestampSelection;
		var isRightSide = (endTimestamp >= this.initialSelected);
		var sideSwitch = ((!isRightSide && this.initialSelected < previousTimestamp) || 
						 (isRightSide && this.initialSelected > previousTimestamp))
		
		if(sideSwitch)
		{
			this.dayCollection.unHighlightRange(previousTimestamp, this.initialSelected);
			previousTimestamp = this.initialSelected;
			this.dayCollection.highlight(previousTimestamp);
		}
		
		if(isRightSide && endTimestamp < previousTimestamp)
		{
			this.dayCollection.unHighlightRange(previousTimestamp, endTimestamp);
			this.dayCollection.highlight(endTimestamp);
		}
		
		
		if(isRightSide && endTimestamp > previousTimestamp)
		{
			this.dayCollection.highlightRange(previousTimestamp, endTimestamp);
		}
		
		if(!isRightSide && endTimestamp > previousTimestamp)
		{
			this.dayCollection.unHighlightRange(previousTimestamp, endTimestamp);
			this.dayCollection.highlight(endTimestamp);
		}
		
		
		if(!isRightSide && endTimestamp < previousTimestamp)
		{
			this.dayCollection.highlightRange(previousTimestamp, endTimestamp);
		}
		
		this.lastTimestampSelection = endTimestamp;
	},
	
	fireRangeCreation: function(e)
	{
		this.fireEvent("onCreateRange", [this.initialSelected, this.lastTimestampSelection, e, this.weekDaysSelected]);
	},
	
	isVisibleDay: function(dayCell)
	{
		return (dayCell.getStyle("display") != "none" && dayCell.getStyle("display") != "hidden");
	},
	
	createRange: function(initTimestamp, endTimestamp)
	{
		this.initialSelected = initTimestamp;
		this.dayCollection.highlight(this.initialSelected);
		this.lastTimestampSelection = this.initialSelected;
		this.selectRangeByEndTimestamp(endTimestamp);
		this.initialSelected = false;
		this.fireEvent("onRangeSeted", [initTimestamp, endTimestamp]);
	},
	
	/*Events*/
	dayClick: function(e, dayCell, index)
	{
		dayCell.addClass(this.options.selectedClass);
		if(!this.initialSelected)
		{
			var timestamp = dayCell.get(this.options.timestampAttribute);
			this.fireEvent("onInitSelection", [timestamp]);
			this.resetWeekDaySelection();
			this.initialSelected = timestamp;
			this.lastTimestampSelection = this.initialSelected
			this.fireEvent("onDaySelectionHover", [this.initialSelected]);
			this.dayCollection.highlight(this.initialSelected);
			return;
		}
		else
		{
			this.fireRangeCreation(e);
			this.initialSelected = false;
			return;
		}
	},
	
	dayMouseEnter: function(dayCell, index)
	{
		if(!this.initialSelected || !this.isVisibleDay(dayCell)) 
		{
			return false;
		}
		
		this.selectRange(dayCell);
	},
	
	setMouseDown: function(status)
	{
		if(!$defined(status)) 
		{
			var status = true;
		}
		
		this.isMouseDown = status;
	},
	
	checkDragging: function()
	{
		var status = false;
		if(this.isMouseDown) 
		{
			var status = true;
		}
		
		this.dragging= status;
	},
	
	preventEvent: function(e)
	{
		if($defined(e))
		{
			e.stop();
		}
	},
	
	checkMouseUpOnDrag: function(e, dayCell, index)
	{
		if(this.dragging)
		{
			this.dayClick(e, dayCell, index);
		}
	},
	
	documentMouseUpOnDragging: function()
	{
		this.dragging = false;
		this.setMouseDown(false);
	},
	
	resetWeekDaySelection: function()
	{
		this.weekDaysSelected.each(this.unSelectSpecificRangeDays.bind(this));
		if($("weekDays"))
		{
			$("weekDays").getElements("a").each(function(anchor){anchor.selected = false});
		}
		this.initialSelected = false;
		this.weekDaysSelected = [];
	},
	
	resetSelection: function()
	{
		if(this.initialSelected)
		{
			this.dayCollection.unHighlightRange(this.initialSelected, this.lastTimestampSelection);
		}
		
		this.setMouseDown(false)
		this.checkDragging();
		this.initialSelected = false;
		this.lastTimestampSelection = false;
		this.currentSelection = [];
	}
});