// -*- Mode: MooTools Javascript; tab-width: 4; -*-


var TheTool = new Class({
	
	Implements: [Options, Events],
	
	options:{},
	
	initialize: function(options){
		
		this.setOptions(options);
		
		this.setupData();
		
		window.addEvent('domready',this.setupView.bind(this));
		window.addEvent('domready',this.setDefaults.bind(this));
	},
	
	setDefaults: function(){
		this.average_monthly_spend.setValue(1250);
		this.spend_category.setValue('shopping');
	},

	setupCustomPopup: function(){
		this.setupCustomPopup = $empty;
		
		var self = this;
		var V = this.V = this.V || {};
		
		if(isIE){
			var fx = this.popup_fx = new StateToggle('custom-categories').toggleOut();
		} else {
			var fx = this.popup_fx = new Fx.Tween.Toggle('custom-categories',{
				duration: 'short',
				onToggleIn: function(){
					fx.element.setStyle('display','block')
				},
				onComplete: function(){
					if(!fx.toggled) fx.element.setStyle('display','none');
				}
			}).setOut();
		}
		
		$('custom-popup-trigger').addEvent('click',function(){ fx.toggleIn(); });
		$('custom-categories').getElement('span.custom-popup-close').addEvent('click',function(){ fx.toggleOut(); });
		$('spend-types').getElement('label[title=Custom]').addEvent('click',function(){ fx.toggleIn(); });
		
		V.graphInfo = $('graph-info');
		
		if(isIE){
			var info_popup_fx = this.info_popup_fx = new StateToggle(V.graphInfo, {
				to   : function(el){
					el
						.removeClass('hide')
						.addClass('open')
						.addClass('hide-cufon')
					;
					setTimeout(function(){ el.removeClass('hide-cufon'); }, 0);
				},
				from : function(el){
					el
						.removeClass('open')
						.addClass('hide')
						.addClass('hide-cufon')
					;
				}
			}).toggleOut();
		} else {
			var info_popup_fx = this.info_popup_fx = new Fx.Tween.Toggle(V.graphInfo,{
				duration: 'short',
				onToggleIn: function(){
					info_popup_fx.element.removeClass('hide').setStyle('display','block');
				},
				onComplete: function(){
					if (!info_popup_fx.toggled) info_popup_fx.element.setStyle('display','none');
				}
			}).setOut();
		};
		
		V.graphInfoPanels = V.graphInfo.getChildren('div');
		V.graphInfoPanels.addClass('hide').removeClass('show');
		
		$('earn').addEvent('click:relay(label)',function(e,el){
			e.preventDefault();
			info_popup_fx.toggleIn();
			V.graphInfoPanels.addClass('hide').removeClass('show');
			$$('#'+el.get('data-info'))
				.addClass('show')
				.removeClass('hide')
			;
		});
		V.graphInfo.getElement('span.custom-popup-close').addEvent('click',function(){ info_popup_fx.toggleOut(); });
		
		// Keybindings
		document.addEvent('keyup',function(event){
			if (event.key != 'esc') return;
			
			fx.toggleOut();
			info_popup_fx.toggleOut();
		});
	},

	setupCustomSliders: function(){
			
		// custom category sliders
		this.popupSliders = [];
		var customCategories = $('custom-categories');
		customCategories.getElements('label').each(function(element, index){
			// move <i> element out of the label
			var textLabel = element.getElement('i')
				.dispose()
				.inject(customCategories)
				.setStyle('display','block')
				.set('tween',{duration: 'short'})
				.fade('hide')
			;
			// create slider
			var icon = element.getElement('u');
			this.popupSliders[this.popupSliders.length] = new Slider.CustomCategory(element, element.getElement('b'), element.getElement('input'),{
				mode: 'vertical',
				range: [8000, 0],
				onMouseenter: function(){
					textLabel.fade('in');
					icon.addClass('current');
				},
				onMouseleave: function(){
					textLabel.fade('out');
					icon.removeClass('current');
				}
			});
			
		}, this);
		
		// average monthly spending slider
		var averageSliderElement = $('average_monthly_spend_slider');
		var monthly_slider = new Slider.Input(averageSliderElement, averageSliderElement.getElement('b'), 'average_monthly_spend',{
			range: [100, 22000]
		});
		
		monthly_slider.addEvent('complete',function(step){
			// monthly_slider.set(Math.round(step/10)*10);
			monthly_slider.element.fireEvent('change'); // what is this?
			var s = (step / 1.5).floor()
			// setRange on popup sliders
			this.popupSliders.each(function(slider){
				if(!this.spend_category_custom.setting) slider.setRange([s,0])
				slider.adjustFont();
			}, this);
			
		}.bind(this));
		
		return this;
	},
	
	setupData: function(){
		var self = this;
		
		// average_monthly_spend
		this.average_monthly_spend = new Function.Xable.Observable;
		this.average_monthly_spend.defineTransformer('value',function(value){
			var $ = parseFloat(String(value).replace(/[$,]/g,''));
			if ($ !== $) return;
			return $;
		});
		this.average_monthly_spend.defineTransformer('$',function(value){
			return formatCurrency(Math.round( value )).replace('.00','');
		});
		
		
		// spend_category
		this.spend_category        = new Function.Xable.Observable;
		this.spend_category.defineTransformer('value',function(category){
			if (!category) return 'custom';
			if (!(category in DEFAULTS_WHERE_I_SPEND_THE_MOST)) return 'custom';
			return category;
		});
		
		
		// spend_category_custom
		this.spend_category_custom = new Function.Xable.Observable(CUSTOM_WHERE_I_SPEND_THE_MOST);
		this.spend_category_custom.defineTransformer('value',function(rawByCategory, old){
			var byCategory = {};
			for (var category in rawByCategory)
				byCategory[category] = parseFloat(String(rawByCategory[category]).replace(/[$,]/g,'')) || 0;
			return $merge(old.value, byCategory);
		});
		this.spend_category_custom.defineTransformer('total',function($ByCategory){
			var total = 0;
			for (var category in $ByCategory) total += $ByCategory[category];
			return total;
		});
		
		this.spend_category_custom.update = function(){
			if (self.spend_category_custom.setting){
				return;
			}
			
			var $ = self.average_monthly_spend.valueOf();
			var category = self.spend_category.valueOf();
			var M = {};
			
			M.travel        = ( $ * DEFAULTS_WHERE_I_SPEND_THE_MOST[category].travel        );//.fireEvent('change');
			M.gas           = ( $ * DEFAULTS_WHERE_I_SPEND_THE_MOST[category].gas           );//.fireEvent('change');
			M.entertainment = ( $ * DEFAULTS_WHERE_I_SPEND_THE_MOST[category].entertainment );//.fireEvent('change');
			M.shopping      = ( $ * DEFAULTS_WHERE_I_SPEND_THE_MOST[category].shopping      );//.fireEvent('change');
			M.utilities     = ( $ * DEFAULTS_WHERE_I_SPEND_THE_MOST[category].utilities     );//.fireEvent('change');
			M.other         = ( $ * DEFAULTS_WHERE_I_SPEND_THE_MOST[category].other         );//.fireEvent('change');
			
			self.spend_category_custom.setValue(M);
		};
		
		
		// Bind average_monthly_spend
		this.spend_category_custom.addEvent('change:total', function(total){
			self.average_monthly_spend.setValue(total);
		});
		
		// Bind spend_category_custom
		this.average_monthly_spend.addEvent('change', this.spend_category_custom.update);
		this.spend_category.addEvent('change', this.spend_category_custom.update);
	},
	
	setupView: function(){
		var self = this;
		var V = this.V = this.V || {};
		
		// Setup popup
		this.setupCustomPopup();
		
		
		// average_monthly_spend
		V.average_monthly_spend = $('average_monthly_spend');
		// View change set Model
		V.average_monthly_spend.addEvent('change',function(){
			self.average_monthly_spend.setValue(this.get('value'));
		});
		// Model change set View
		this.average_monthly_spend.addEvent('change:$',function($){
			V.average_monthly_spend.set('value', $).fireEvent('change');
		});
		
		
		// spend_category
		// View change set Model
		$$('#spend form').addEvent('submit', function(e){
			e.preventDefault();
			setCategory();
		});

		var lastCategory = '';
		var setCategory = this.setCategory = function(category){
			
			if ($type(category) == 'event')
				category = Element.get(category.target, 'value');
			
			if ($type(category) != 'string')
				category = V.spend_categories.filter(':checked').get('value')[0];
			
			self.popup_fx.toggleIn();
			if (lastCategory != category) self.spend_category.setValue(category);
			lastCategory = category;
		};

		V.spend_types = $('spend-types');
		V.spend_types.addEvent('click:relay(li)', function(event){
			var input = this.getElement('input') || this;
			try {
				V.spend_categories.set('checked', false);
				input.set('checked', true);
				input.blur();
				input.focus();
				input.fireEvent('change');
			} catch(e){}
		});
		
		V.spend_categories = V.spend_types.getElements('input[type=radio]');
		V.spend_categories.addEvents({
			change: setCategory
		});
		
		
		// Model change set View
		V.spendOn = $('spend-on').set('tween',{transition:'elastic:out'}).fade('hide');
		this.spend_category.addEvent('change',function(category){
			
			V.spendOn.fade('show');
			if (category == 'shopping'      ) V.spendOn.tween('left',  -1);
  			if (category == 'entertainment' ) V.spendOn.tween('left',  70);
			if (category == 'travel'        ) V.spendOn.tween('left', 141);
			if (category == 'custom'        ) V.spendOn.tween('left', 212);
			
			V.spend_categories.getParent('li').removeClass('on');
			$$('#spend-'+category).getParent('li').addClass('on');
			
			V.spend_categories.set('checked', false);
			V.spend_categories.filter("[value="+category+"]").set('checked', true);
			
		});
		
		
		// spend_category_custom
		V.customCategories = $('custom-categories');
		// View change set Model
		SPEND_CATEGORIES.each(function(category){
			V[category] = V.customCategories.getElement('input[name='+category+']');
			
			V[category].addEvent('change', function(){
				var data = {};
				data[category] = this.get('value');
				self.spend_category_custom.setValue(data);
			});
		});
		// Model change set View
		self.spend_category_custom.addEvent('change', function($ByCategory){
			for (var category in $ByCategory) 
				V[category].set('value', formatCurrency(Math.round( $ByCategory[category] )).replace('.00','')).fireEvent('change');
		});
		
		
		// graphs
		this.setupGraphs();
		
		
		// Setup Slider UI to update the input values
		this.setupCustomSliders();
	},
	
	setupGraphs: function(){
		var self = this;
		var V = this.V = this.V || {};
		// Bind Model data changes to update the graph bar height
		Hash.each(Cards, function(card, card_id, Cards){
			
			// Cache elements
			V[card_id] = $(card_id);
			V[card_id+'_bar'] = V[card_id].getParent('span').set('tween',{unit:isIE==6?'px':'%'});
			
			// Bind Model data changes to update the graph bar height
			this.spend_category_custom.addEvent('change:'+card_id, function(value,card_id,transformedValues){
				var transformedValues = Hash.getValues(transformedValues).sort(function(a,b){return((a>b)-(a<b))}).reverse();
				var max = transformedValues.max();
				setTimeout(function(){
					V[card_id+'_bar'].tween('height', 0, value / max * 100);
				},0);
			});
			
			// Bind Model data changes to update the graph bar "Miles" text
			this.spend_category_custom.addEvent('change:'+card_id, function(value,card_id){
				V[card_id].set('value', Number.format(value));
			});
			
			// Add a data transformer to the Model for this card
			this.spend_category_custom.defineTransformer(card_id, function(monthlySpend_byCategory){
				return calculatePoints_forCard_fromSpendCategories_andMonths(card_id, monthlySpend_byCategory, 12);
			})
			
		},this);
		
		
		// Special extra rule for the "enjoy rewards worth $X" thing
		// Bind Model data changes to update its "$ worth" input, if there is one
		V.worth_fx = new Fx.Set($('capital_one_venturesm_card_worth'), {
			transition: 'sine:out',
			onComplete: function(){
				$('capital_one_venturesm_card').set('value', Math.round( this.value ).format());
			},
			transformer: function(value){
				return Math.round( value ).format();
			}
		});
		V.worth_fx.set('text', this.spend_category_custom().capital_one_venturesm_card);
		Cufon.CSS.ready(function(){
			V.worth_fx.start('text', 0, self.spend_category_custom().capital_one_venturesm_card);
		})
		self.spend_category_custom.addEvent('change:capital_one_venturesm_card', function(value){
			V.worth_fx.start('text', V.worth_fx.value, value);
		});
	},

	0:0
});


// mootools-rpflo plugins


Slider.Input = new Class({
	
	Extends: Slider,

	initialize: function(element, knob, input, options){
		this.input = document.id(input);
		this.options.initialStep = input.value;
		this.parent(element, knob, options);
		this
			// .cancelInputFocus()
			.addEvent('onChange',this.change.bind(this));
		var self = this;
		this.input.addEvent('change', function(){
			try {
				// Handle infinite loops
				var old = self.noChangeInput;
				self.noChangeInput = true;
				var value = parseFloat( String(this.get('value')).replace(/[$,]/g,'') );
				if (value) self.set(value);
			} catch(e){
				throw e;
			} finally {
				self.noChangeInput = old;
			}
		});
	},
	
	change: function(step){
		if (this.noChangeInput) return this;
		this.input.set('value',step);
		$clear(this.input_change_delay);
		var self = this;
		this.input_change_delay = setTimeout(function(){
			self.input.fireEvent('change');
		}, 300);
		
		
		return this;
	},
	
	cancelInputFocus: function(){
		this.input.addEvent('focus',function(){
			this.input.blur();
		}.bind(this));
		return this;
	}

});


Slider.CustomCategory = new Class({
	
	Extends: Slider.Input,

	options: {
		/*
		onMouseenter: $empty,
		onMouseleave: $empty
		*/
	},

	initialize: function(element,knob,input,options){
		this.parent(element,knob,input,options)
		this.setupTooltips();
		this.addEvent('change', this.adjustFont.bind(this));
	},
	
	adjustFont: function(attribute){
		if(this.input.value.replace('$','').replace(',','') > 9999) {
			this.input.setStyle('font-size','9px');
		} else {
			this.input.setStyle('font-size','12px');
		};
		return this;
	},
	
	setupTooltips: function(){		
		var label = this.input.getParent();
		label.set('tween',{ duration: 'short' }).fade('out');
		var events = {
			mouseenter: function(){
				label.fade('in');
				this.fireEvent('mouseenter');
			}.bind(this),
			mouseleave: function(){
				label.fade('out');
				this.fireEvent('mouseleave');
			}.bind(this)
		};
		events.focus = events.mouseenter;
		events.blur = events.mouseleave;
		this.element.addEvents(events);
		return this;
	}

});


Fx.Tween.Toggle = new Class({
	
	Extends: Fx.Tween,
	
		options: {
			/*
			onToggle: $empty,
			onToggleIn: $empty,
			onToggleOut: $empty,
			*/
			property: 'opacity',
			from: 0,
			to: 1
		},
	
	toggle: function(event){
		if(event) event.stop();
		(this.toggled) ? this.toggleOut() : this.toggleIn();
		this.fireEvent('onToggle');
		return this;
	},
	
	toggleIn: function(){
		this.toggled = true;
		this.start(this.options.to);
		this.fireEvent('onToggleIn');
		return this;
	},
	
	toggleOut: function(){
		this.toggled = false;
		this.start(this.options.from);
		this.fireEvent('onToggleOut');
		return this;
	},
	
	setIn: function(){
		this.toggled = true
		this.set(this.options.to);
		return this;
	},
	
	setOut: function(){
		this.toggled = false;
		this.set(this.options.from);
		return this;
	}
	
});


var StateToggle = new Class({
	
	Implements: [Options, Events],
	
		options: {
			/*
			onToggle: $empty,
			onToggleIn: $empty,
			onToggleOut: $empty,
			*/
			to   : function(el){ el.setStyle('display','block'); },
			from : function(el){ el.setStyle('display','none'); }
		},
	
	initialize: function(element, options){
		this.setOptions(options);
		this.element = document.id(element);
	},
	
	toggle: function(event){
		if(event) event.stop();
		(this.toggled) ? this.toggleOut() : this.toggleIn();
		this.fireEvent('onToggle');
		return this;
	},
	
	toggleIn: function(){
		this.toggled = true;
		this.options.to.call(this, this.element);
		this.fireEvent('onToggleIn');
		return this;
	},
	
	toggleOut: function(){
		this.toggled = false;
		this.options.from.call(this, this.element);
		this.fireEvent('onToggleOut');
		return this;
	}
	
});


Array.implement({
	
	sum: function(){
		for(var i=0,sum=0;i<this.length;sum+=this[i++]);
		return sum;
	},
	
	max: function(){
		return Math.max.apply({},this.cleanNumeric());
	},
	
	min: function(){
		return Math.min.apply({},this);
	},
	
	cleanNumeric: function(){
		return this.map(function(item){
			return (isNaN(item)) ? 0 : item;
		});
	}
	
});


