/* Global Services */

angular.service('Config', function($location){
	return {
		AJAX_REQUEST_EVENT: 'abn.ajax.request',
		AJAX_SUCCESS_EVENT: 'abn.ajax.success',
		AJAX_ERROR_EVENT: 'abn.ajax.error',
		BASE_WIND_SPEED: 1,
		BASE_CLOUD_OPACITY: 0.8,
		BASE_SHADOW_OPACITY: 0.2
	};
}, { $inject: ['$location'] });


/* API Services */

angular.service('Request', function(Config){
	
	// Global JQuery AJAX settings	
	$.ajaxSettings.contentType = 'application/json';
	
	amplify.request.decoders.json = function(data, status, xhr, success, error){
		switch (status) {
			case 'success':
				success(angular.fromJson(data));			
				break;
			case 'error':
				error(xhr);
				break;
		}
	};
		
	amplify.request.decoders.xhr = function(data, status, xhr, success, error){
		switch (xhr.statusText) {
			case 'success':
				success(xhr.responseText);			
				break;
			default:
				error(xhr);
				break;
		}
	};
	

	// MailChimp
	
	amplify.request.define(
		'mailchimp',
		'ajax',
		{
			url: 'http://abundancegeneration.us2.list-manage.com/subscribe/post-json?u=718417ee8aa891a860fe4641b&id=144880714c&c=?',
			dataType: 'json',
			type: 'GET',
			decoder: 'json'
		}
	);
	
	amplify.request.define(
		'twitter',
		'ajax',
		{
			url: 'http://twitter.com/status/user_timeline/{user}.json?count={count}&callback=?',
			dataType: 'json',
			type: 'GET',
			decoder: 'json'
		}
	);	

	return function(request){
		amplify.request({
			resourceId: request.resourceId,
			data: request.data,
			success: function(data, status){
				request.scope.$apply(function(scope){
					scope.$emit(Config.AJAX_SUCCESS_EVENT, data);
					(request.success || angular.noop)(scope, data);
				});
			},
			error: function(xhr, status){
				request.scope.$apply(function(scope){
					scope.$emit(Config.AJAX_ERROR_EVENT, xhr);
					(request.error || angular.noop)(scope, xhr);
				});
			}
		})
	};
	
}, { $inject: ['Config'], $eager: true });

angular.service('FormErrors', function($window){
    return function(formScope, formEl){
		var labels = [],
			labelFadeDuration = 250,
			labelPersistDuration = 2000,
			labelStaggerDelay = 50,
			labelFadeDistance = 100;
	
		$(formEl).css('position', 'relative')
			.children('.errorLabel').remove();

		angular.forEach(formScope.$error, function(collection, key){
			angular.forEach(collection, function(widgetScope){
				var widgetId = widgetScope.$widgetId,
					widget = $(formEl).find('*[name=' + widgetId + ']'),
					type = key.toLowerCase(),
					placeholder = widget.attr('placeholder'),
					labelEl = $('<span class="errorLabel ' + type + ' "/>'),
					labelMaxWidth = 100,
					labelLeftMargin = 5,
					includeMarginHeight = false,
					el = widget,
					text = '';

				switch (key) {
					case 'REQUIRED':
						text = 'Required';
						break;

					case 'NUMBER':
					case 'INTEGER':
						text = 'Must be a valid number';
						break;

					case 'MONEY':
						text = 'Must be a valid amount';
						break;

					case 'MIN':
					case 'MAX':
						var moreLess = key == 'MAX' ? 'more' : 'less';
							limit = widget.attr(key.toLowerCase()),
							prefix = suffix = '';

						if (widget.hasClass('money')) prefix = '£';

						text = 'Must be ' + moreLess + ' than ' + prefix + limit + suffix;
						break;

					case 'MINLENGTH':
					case 'MAXLENGTH':
						var moreLess = key == 'MAXLENGTH' ? 'more' : 'less';
							limit = widget.attr('ng:'+key.toLowerCase());

						text = 'Must not be ' + moreLess + ' than ' + limit + ' characters/digits';
						break;

					case 'EMAIL':
						text = 'Must be a valid email address';
						break;

					case 'POSTCODE':
						text = 'Must be a valid UK postcode';
						break;

					case 'TELEPHONE':
						text = 'Must be a valid UK telephone number';
						break;
						
					case 'DATE':
						text = 'Date must match the example format';
						break;

					case 'PATTERN':
						text = 'Does not match the required format';
						break;
						
					case 'CONFIRM':
						text = 'Please confirm';
						el = widget.parent('label.checkbox');
						labelLeftMargin = 10;
						includeMarginHeight = true;
						break;

					default:
						text = 'Error with field';
						break;
				}
				
				labelEl
					.html('<span>' + text + '</span>')
					.appendTo(formEl)
					.css('position', 'absolute')
					.css('width', Math.min(labelEl.outerWidth(), labelMaxWidth))
					.css({
						left: el.position().left + el.outerWidth() + labelFadeDistance + labelLeftMargin,
						top: el.position().top + (el.outerHeight(includeMarginHeight) - labelEl.outerHeight()) / 2,
						opacity: 0
					});
					
				angular.Array.add(labels, { el: labelEl, index: $(formEl).find('input, select').index(widget) });
			});
		});
		
		labels = angular.Array.orderBy(labels, 'index');
		angular.forEach(labels, function(label, i){
			label.el
				.delay(i * labelStaggerDelay)
				.animate({ left: '-=' + labelFadeDistance, opacity: 1 }, labelFadeDuration)
				.delay(labelPersistDuration + labelFadeDuration)
				.animate({ left: '+=' + labelFadeDistance, opacity: 0 }, labelFadeDuration);
		});

		$($window).scrollTo(labels[0].el, 250);
    };
}, { $inject: ['$window'] });

angular.service('World', function(Config, $defer){	
	var windSpeed = Config.BASE_WIND_SPEED,
		cloudOpacity = Config.BASE_CLOUD_OPACITY,
		shadowOpacity = Config.BASE_SHADOW_OPACITY;
	
	return {
		getShadowTransform: function(){
			// TODO: dynamic calculation of transform based on time of day
			// var hours = new Date().getHours();
			return {
				scale: 0.33,
				skew: 60
			}
		},
		
		getWindSpeed: function(){
			// TODO: make dynamic
			return windSpeed;
		},
		
		getBaseCloudOpacity: function(){
			// TODO: make dynamic?
			return cloudOpacity;
		},
		
		getShadowOpacity: function(){
			// TODO: make dynamic?
			return shadowOpacity;
		}
	};
}, { $inject: ['Config', '$defer'], $eager: true });

angular.service('Utils', function(){
	return {
		parseISO8601Date: function(str){
			var regexp = /(\d{4})(-)?(\d\d)(-)?(\d\d)(T)?(\d\d)(:)?(\d\d)(:)?(\d\d)(\.\d+)?(Z|([+-])(\d\d)(:)?(\d\d))/,
				date = new Date();
				
		    if (angular.isString(str) && str.match(regexp)) {
		        var parts = str.match(regexp),
					offset = 0;
					
		        date.setGMTDate(1);
		        date.setGMTFullYear(parseInt(parts[1], 10));
		        date.setGMTMonth(parseInt(parts[3], 10) - 1);
		        date.setGMTDate(parseInt(parts[5], 10));
		        date.setGMTHours(parseInt(parts[7], 10));
		        date.setGMTMinutes(parseInt(parts[9], 10));
		        date.setGMTSeconds(parseInt(parts[11], 10));

		        if (parts[12])
		            date.setGMTMilliseconds(parseFloat(parts[12]) * 1000);
		        else
		            date.setGMTMilliseconds(0);

		        if (parts[13] != 'Z') {
		            offset = (parts[15] * 60) + parseInt(parts[17], 10);
		            offset *= ((parts[14] == '-') ? -1 : 1);
		            date.setTime(date.getTime() - offset * 60 * 1000);
		        }
		    } else {
		        date.setTime(Date.parse(str));
				if (!date.getTime()) return null;
		    }
		
		    return date;
		}
	};
});
