
Object.extend(Array.prototype, {
	remove: function(element) {
		var el = this.splice(this.indexOf(element), 1)
		return el
	}
});


//	Calendar: Droppable Days

	DroppableDays = []

	Object.extend(DroppableDays, {
		droppableFor: function(date) {
			var element =  $("day_" + date)
			if ((element) && (element.day)) {
				return element.day
			}
		},
    
		clearPredictions: function() {
			this.each(function(day) {
				day.clearPredictions()
			})
		},
		
		predictBleeding: function(day) {
			day = this.droppableFor(day)
			day.predictBleeding()
		},
		
		predictFertility: function(day) {
			day = this.droppableFor(day)
			day.predictFertility()
		},
		
		predictReminder: function(day) {
			day = this.droppableFor(day)
			return day.predictReminder()
		},
		
		predictOvulation: function(day) {
			day = this.droppableFor(day)
			return day.predictOvulation()
		},
		
		predictMoonPhase: function(date, stage) {
			day = this.droppableFor(date) // 2008-04-06
			return day.predictMoonPhase(stage) // 0..3
		}
	})

	DroppableDay = Class.create({
		date: null, //	2007-04-01
		element: null, droppable: null,
		draggables_container: null, notifications_container: null,
		draggables: null, reminders: [], ovulations: [], moonphases: [],
    
		recieve: function(draggable_element) {
			draggable_element.was_recieved = true
      
			if (draggable_element.hasClassName("draggable-creator")) {
				var reference = {
					event_type: draggable_element.creator.event_type,
					strength: draggable_element.creator.strength,
					day: this.day,
					date: this.day.date
				}
				this.day.overwriteRecord({type: reference.event_type})
				var record = new DraggableRecord(reference)
			} else {	// It's a draggable-record
				if (this.day != draggable_element.record.day) {
					this.day.overwriteRecord(draggable_element.record)
				}
        
				this.day.draggables_container.appendChild(draggable_element)
				draggable_element.setStyle({top: 0, left: 0})
        
				if (this.day != draggable_element.record.day) {
					draggable_element.record.changeDay(this.element.day)
				}
			}
		},
    
		addRecord: function(draggable) {
			this.draggables.push(draggable)
			draggable.day = this
			draggable.date = this.date
			this.recountDraggables()
		},
		
		removeRecord: function(draggable) {
			if (this.draggables.indexOf(draggable) != -1) {
				this.draggables.remove(draggable)
				draggable.day = null
				draggable.date = null
				this.recountDraggables()
			}
		},
		
		overwriteRecord: function(other) {
			var record = this.draggables.find(function(draggable){
				return (draggable.type == other.type)
			})
      
			if (record) {
				record.destroy(false, true)
			}
		},

		recountDraggables: function() {
			var element = this.element
			var classNames = ["one", "two", "three", "four", "five", "six"]
			classNames.each(function(className) {
				element.removeClassName(className)
			})
      
			switch (this.draggables.length) {
				case 1 :	this.element.addClassName("one")
					break
				case 2 :	this.element.addClassName("two")
					break
				case 3 :	this.element.addClassName("three")
					break
				case 4 :	this.element.addClassName("four")
					break
				case 5 :	this.element.addClassName("five")
					break
				case 6 :	this.element.addClassName("six")
			}
		},
    
		predictBleeding: function() {
			this.element.addClassName("predicted-bleeding")
		},
		
		predictFertility: function() {
			this.element.addClassName("predicted-fertility")
		},
		
		predictReminder: function() {
			var reminder = document.createElement("SPAN")
			reminder.className = "predicted-reminder icon"
			reminder.id = "reminder-" + this.element.id
			this.notifications_container.appendChild(reminder)
			this.reminders.push(reminder)
			return reminder
		},
		
		predictOvulation: function() {
			var ovulation = document.createElement("SPAN")
			ovulation.className = "predicted-ovulation icon"
			ovulation.id = "ovulation-" + this.element.id
			this.notifications_container.appendChild(ovulation)
			this.ovulations.push(ovulation)
			return ovulation
		},
		
		predictMoonPhase: function(phase) {
			var moonphase = document.createElement("SPAN")
			moonphase.className = "moonphase-" + phase + " icon"
			moonphase.id = "moonphase-" + this.element.id
			this.notifications_container.appendChild(moonphase)
			this.moonphases.push(moonphase)
			return moonphase
		},
		
		clearPredictions: function() {
			var dis = this;
			
			this.element.removeClassName("predicted-fertility")
			this.element.removeClassName("predicted-bleeding")
			
			if (this.reminders.length > 0) {
				this.reminders.each(function(reminder) {
					dis.reminders.remove(reminder)
					dis.notifications_container.removeChild(reminder)
					Tooltip.instance.removeTrigger(reminder)
					delete reminder
				})
			}
			
			if (this.ovulations.length > 0) {
				this.ovulations.each(function(ovulation) {
					dis.ovulations.remove(ovulation)
					dis.notifications_container.removeChild(ovulation)
					Tooltip.instance.removeTrigger(ovulation)
					delete ovulation
				})
			}
			/*
			This will only come in question when months change on the fly
			
			if (this.moonphases.length > 0) {
				this.moonphases.each(function(moonphase) {
					dis.moonphases.remove(moonphase)
					dis.notifications_container.removeChild(moonphase)
					delete moonphase
				})
			}
			*/
		},
    
		initialize: function(element) {
			this.draggables = []
			this.ovulations = []
			this.reminders = []
			this.moonphases = []
      
			this.element = $(element)
			this.element.day = this
			this.draggables_container = $$("#" + this.element.id + " .draggables-container")[0];
			this.notifications_container = $$("#" + this.element.id + " .notifications-container")[0];
      
			Droppables.add(this.element, {accept: 'draggable', hoverclass: 'drophover', onDrop: this.recieve})
      
			var el = this.element
			this.droppable = Droppables.drops.find(function(droppable) { return (droppable.element == el)})
			this.droppable.day = this
			this.date = this.element.id.substr(this.element.id.indexOf("_")+1, this.element.id.length)
      
			DroppableDays.push(this)
		}
	})

// Calendar: Draggable Records

	DraggableRecords = []

	Object.extend(DraggableRecords, {
		find_by: function(date, type) {
			var record = this.find(function(el) {
				return ((el.date == date) && (el.type == type))
			})
			return record
		},
		
		enable: function(date, type, id) {
			var record = this.find_by(date, type)
			record.id = id
			record.enableDragging()
		}
	})

	DraggableRecord = Class.create({
		element: null, draggable: null, day: null,
    
		id: null,	// pk
		date: null, //	"2007-14-03" ?
		type: null, // "bleeding" || "pain" || "visit"
		controller: null,
		strength: null, // "3", "2", "1", "0"
    
		//	Base
		changeDay: function(other) {
			this.disableDragging()
			this.day.removeRecord(this)
			other.addRecord(this)
			this.updateRecord() // & enableDragging
		},
		
		destroy: function(soft, silent) {
			this.disableDragging()
			this.destroyDraggableElement()
      
			this.day.removeRecord(this)
			DraggableRecords.remove(this)
			if(!soft) this.destroyRecord(silent)
      
		  // delete this // Why doesn't IE allow this?
		},
    
		//	Ajax
    
		createRecord: function() {
			var params
			switch (this.type) {
  			case "bleeding"	:	params = {"bleeding[happened_at]"	: this.date, "bleeding[strength]"	: this.strength}
  				break
  			case "pain"		:	params = {"pain[happened_at]"		: this.date, "pain[strength]"		: this.strength}
  				break
  			case "visit"	:	params = {"visit[happened_at]"		: this.date}
			}
        
			new Ajax.Request(this.controller, {method: "post", parameters: params})
		},
		
		destroyRecord: function(silent) {
		  if (!silent) silent = false
			new Ajax.Request(this.controller + "/" + this.id, {method: "delete", parameters: {silent: silent}})
		},
		
		updateRecord: function() {
			var params
			switch (this.type) {
  			case "bleeding"	:	params = {"bleeding[happened_at]"	: this.date}
  				break
  			case "pain"		:	params = {"pain[happened_at]"		: this.date}
  				break
  			case "visit"	:	params = {"visit[happened_at]"		: this.date}
			}
      
			new Ajax.Request(this.controller + "/" + this.id, {method: "put", parameters: params})
		},
    
		//	Dragging
    
		onStart: function(draggable) {
			draggable.element.parentNode.removeChild(draggable.element)
			$("records").appendChild(draggable.element)
			draggable.element.oldIndex = draggable.element.style.zIndex
			draggable.element.style.zIndex = 6000
		},
		
		onEnd: function(draggable) {
			if (!draggable.element.was_recieved) {
				Effect.Fade(draggable.element, {
					afterFinish: function() {
						draggable.record.destroy(false, false)
					}
				})
			}
      
			draggable.element.style.zIndex = draggable.element.oldIndex
			draggable.element.was_recieved = false
		},
    
		enableDragging: function() {
			this.draggable = new Draggable(this.element, {onStart:this.onStart, onEnd:this.onEnd})
			this.element.draggable = this.draggable
			this.draggable.record = this
		},
    
		disableDragging: function() {
			this.draggable.destroy()
			this.element.draggable = null
		},
    
		createDraggableElement: function() {
			this.element = document.createElement("SPAN")
			this.element.record = this
			// Explorer doesnt treat this.element as a Prototype Element, so instance level functions don't work
			Element.addClassName(this.element, "loading")
			Element.addClassName(this.element, "draggable")
			Element.addClassName(this.element, "draggable-record")
			Element.addClassName(this.element, this.type)
			Element.addClassName(this.element, this.type + "-" + this.strength)
		},
		
		destroyDraggableElement: function() {
			this.element.parentNode.removeChild(this.element)
			delete this.element
		},
    
		initialize: function(reference) {
			this.type = reference.event_type
			this.controller = reference.event_type + "s"
      
			this.strength = reference.strength
			this.date = reference.date
      
			if (reference.id) {	//	DraggableRecord
				this.id = reference.id
				this.day = DroppableDays.droppableFor(reference.date)
			} else {	//	DraggableCreator
				this.day = reference.day
			}
      
			this.createDraggableElement()
      
			this.day.draggables_container.appendChild(this.element)
			this.day.addRecord(this)
      
			DraggableRecords.push(this)
      
			if (!reference.id) {
				this.createRecord()
			} else {
				this.enableDragging()
			}
		}
	})

// Dock: Draggable Creators

	DraggableCreators = []

	DraggableCreator = Class.create({
		element: null, draggable: null, event_type: null, strength: null,
    
		teleport: function() {
			this.element.setOpacity(0)
			this.element.was_recieved = false
			this.element.setStyle({top: 0, left: 0})
			new Effect.Opacity(this.element, { to: 1, duration: 1.2, queue: {scope:'_draggable', position:'end' }})
		},
    
		pull: function(top_offset, left_offset) {
			var d = Math.sqrt(Math.abs(top_offset^2) + Math.abs(left_offset^2)) * 0.02
			new Effect.Move(this.element, {	x: -left_offset, y: -top_offset, duration: d, queue: {scope:'_draggable', position:'end' }})
		},
    
		//	Draggable.options.reverteffect
		revert: function(element, top_offset, left_offset) {
			if (element.was_recieved) {
				element.creator.teleport()
			} else {
				element.creator.pull(top_offset, left_offset)
			}
			element.was_recieved = false
		},
    
		createDraggableClass: function() {
			this.draggable = new Draggable(this.element, {revert: true, reverteffect: this.revert, starteffect: null})
			this.element.draggable = this.draggable
			this.draggable.creator = this
		},
    
		initialize: function(element) {
      
			this.element = $(element)
			this.element.creator = this
			this.event_type = this.element.id.substr(0, this.element.id.indexOf("-"))
			this.strength = this.element.id.substr(this.element.id.indexOf("-")+1, this.element.id.length)
      
			this.createDraggableClass()
      
			DraggableCreators.push(this)
		}
	})

// Tooltip

	Tooltip = Class.create({
		element: null, effect: null, triggers: null, tips: null,
		margin_x: 0, margin_y: 31, ie_margin_x: 3, ie_margin_y: 30,
		
		over: function(event) {
			// var element = event.element() // this == element
			this.tooltip.show(this)
		},
		
		out: function(event) {
			this.tooltip.hide()
		},
		
		show: function(trigger) {
			this.element.innerHTML = this.tips[trigger.id]
			var position = Element.cumulativeOffset(trigger)
			var newTop = (position[1] + this.margin_y) + "px"
			var newLeft = (position[0] + this.margin_x) + "px"
			Element.setStyle(this.element, {
				top: newTop,
				left: newLeft
			})
		//	this.show()
			this.effect = Effect.Appear(this.element, {duration: 0.3})
		},
		
		hide: function() {
			if (this.effect) {
				this.effect.cancel()
				delete this.effect
			}
			this.element.hide()
			this.element.innerHTML = ''
		},
    
		addTrigger: function(trigger, content) {
			this.triggers.push(trigger)
			this.tips[trigger.id] = content
			trigger.tooltip = this
			Event.observe(trigger, 'mouseover', this.over)
			Event.observe(trigger, 'mouseout', this.out)
		},
		
		removeTrigger: function(trigger) {
			this.triggers.remove(trigger)
			delete this.tips[trigger.id]
			Event.stopObserving(trigger, 'mouseover', this.over)
			Event.stopObserving(trigger, 'mouseout', this.out)
		},
		
		initialize: function(element) {
			this.element = element
			this.triggers = []
			this.tips = {}
			Element.hide(this.element)
			/*@cc_on
				this.margin_x = this.ie_margin_x
				this.margin_y = this.ie_margin_y
			@*/
		}
	})

// Image slideshow

	Slideshow = []
	Object.extend(Slideshow, {
		interval: 3, images: null, current: 0, executer: null,
		
		cycle: function() {
			new Effect.Fade(Slideshow[Slideshow.current], {
				duration: Slideshow.interval/16,
				afterFinish: function() {
					Slideshow.current++
					if (Slideshow.current >= Slideshow.length) {
						Slideshow.current = 0
					}
					new Effect.Appear(Slideshow[Slideshow.current], {
						duration: Slideshow.interval/8
					})
				}
			})
			
		},
		
		start: function() {
			this.executer = new PeriodicalExecuter(this.cycle, this.interval)
		},
		stop: function() {
			this.executer.stop()
		},
		
		run: function(images) {
			var dis = this
			images.each(function(image) {
				image.onmouseover = function() {
					Slideshow.stop()
				}
				image.onmouseout = function() {
					Slideshow.start()
				}
				dis.push(image)
			})
			
			this.without(this.first()).each(Element.hide)
			
			this.start()
			
			this.first().parentNode.style.height = this.first().offsetHeight + "px"
		}
	})


// UI

function swapLogin(showlogin) {
  if (showlogin == true) {
    $('register').hide()
    $('signin').show()
  } else {
    $('signin').hide()
    $('register').show()
  }
}

function swaps2f() {
  $('s2fbody').toggle();
}
