var User;

(function($) {
	User = {
		options: {
			graphBaseURL: '//my.democrats.org/page/graph/',
			checkAuthInterval: 500,
			loginDivId: 'login_lightbox',
			logoutURL: '//my.democrats.org/page/user/logout',
			cookie: {
				guid: 'guid',
				enc: '__u_enc_',
				session: 'PHPSESSID',
				remember: 'remember_me',
				options: {
					domain: '.democrats.org',
					path: '/'
				},
				expiresIn: 24 * 60 * 60 * 1000
			},
			dialog: {
				modal: true,
				width: 550,
				height: 384,
				resizable: false,
				draggable: false
			},
			candidateGroup: {
				formURL: '//my.democrats.org/page/s/candidategroup',
				formField: 'custom-18052',
				cookieSuffix: '_cgrp',
				expiresIn: 100 * 365 * 24 * 60 * 60 * 1000
			},
			platformGroup: {
				cookieSuffix: '_pgrp',
				expiresIn: 100 * 365 * 24 * 60 * 60 * 1000,
				framePrefix: 'my.democrats.org/page/group/',
				frameSuffix: '/join'
			},
			flag: {
				cookieSuffix: '_flag',
				expiresIn: 100 * 365 * 24 * 60 * 60 * 1000
			},
			create: {
				base: {
					firstname: 'Friend',
					lastname: '...'
				},
				genPassOptions: [8, '', false, true, false, false, true, true,
					false, false],
				formURL: '//my.democrats.org/ctl/Constituent/Login',
				defaultRedirect: '/page/dashboard/private'
			}
		},
		data: {},
		loaded: false,
		candidateGroups: [],
		platformGroups: [],
		flags: [],
		
		get: function(callback, reload) {
			if ($.isFunction(callback)) {
				this.callback = callback;
			}
			if (this.loaded && !reload) {
				return this.run();
			} else {
				return this.load(reload);
			}
		},
		
		authenticated: function() {
			if ($.cookie(this.options.cookie.session) &&
			 	$.cookie(this.options.cookie.guid)) {
					return true;
				} else {
					return false;
				}
		},
		
		loggedIn: function() { return this.authenticated(); },
		
		logIn: function(callback) {
			var self = this;
			var dialog = $('#' + this.options.loginDivId).dialog(
				this.options.dialog);
			dialog.bind('dialogclose', function() {
				self.callback = null;
				clearInterval(self.authInterval);
			});
			this.authInterval = setInterval(function() {
				console.log('looking for login...');
				if (self.authenticated()) {
					console.log('got login!');
					clearInterval(self.authInterval);
					dialog.dialog('destroy');
					$(document).trigger('user.login');
					$.cookie('bsduser','1',365);
					callback();
				}
			}, this.options.checkAuthInterval);
			dialog.show();
		},
		
		logOut: function(redirectURL) {
			var self = this;
			var iframe = $('<iframe src="' + this.options.logoutURL + 
				'" style="display: none" />');
			iframe.bind('load', function() {
				/* clear guid cookie (must use same path and domain) */
				$.cookie(self.options.cookie.guid, null,
					self.options.cookie.options);
				window.location = redirectURL || (window.location.href.indexOf('page/dashboard')>-1)?'http://www.democrats.org/':window.location.href;
			});
			iframe.appendTo($('body'));
		},
		
		logout: function(r) {this.logOut(r);},
		
		load: function(reload) {
			var self = this;
			
			if (!this.authenticated()) {
				this.logIn(function() {self.load(reload);});
				return;
			}
			
			/* if authenticated then there is a guid cookie */
			this.data.guid = $.cookie(this.options.cookie.guid);
			
			/* keyHash is a hexadecimal string hash of the guid */
			this.keyHash = sjcl.codec.hex.fromBits(
				sjcl.hash.sha256.hash(this.guid()));
			
			/* now key is available */
			var enc = $.cookie(this.key());
			if (enc && !reload) {
				var str, obj;
				try {
					str = sjcl.decrypt(this.guid(), enc);
					obj = JSON.parse(str);
				} catch(e) {this.loadFromGraph();}
				this.update(obj);
				this.loadGroups();
				this.loaded = true;
				$(document).trigger('user.load');
 				return this.run();
			} else {this.loadFromGraph();}
		},
		
		key: function() {
			if (this.keyHash) {
				return this.options.cookie.enc + this.keyHash;
			}
		},
		
		loadFromGraph: function() {
			var self = this;
			var graphURL = this.options.graphBaseURL + this.guid();
			var dt = (window.location.host == 'my.democrats.org' ?
				'json' : 'jsonp');
			
			console.log('loading user from graph: ' + graphURL + ' (' + dt + ')');
			$.ajax({
				url: graphURL,
				dataType: dt,
				success: function(data) {
					console.log('load from graph success');
					console.log(data);
					self.update(data);
					self.loadGroups();
					self.loaded = true;
					self.save();
					$(document).trigger('user.load');
					self.run();
				},
				error: function(xhr, t, e) {
					console.log('load from graph error');
					console.log(e);
				},
				complete: function() {
					console.log('load from graph complete');
				}
			});
		},
		
		loadGroups: function() {
			var self = this;
			$.each(['candidateGroup', 'platformGroup', 'flag'], function(i, grp) {
				var enc = $.cookie(
					self.key() + self.options[grp].cookieSuffix);
				if (!enc) {return;}
				
				var str, obj;
				try {
					str = sjcl.decrypt(self.guid(), enc);
					obj = JSON.parse(str);
				} catch(e) {}
				if ($.isArray(obj)) {
					self[grp+'s'] = obj;
				}
			});
		},
		
		update: function(data) {
			if (data) {
				$.extend(true, this.data, data);
			}
		},
		
		run: function() {
			var callback = this.callback;
			if ($.isFunction(callback)) { return callback(); }
		},
		
		email: function() {
			if (this.data.userid && this.data.userid.match(/@/)) {
				return this.data.userid;
			} else {
				return primaryOrFirst(this.data.email).email;
			}
		},
		
		firstname: function() {
			return this.data.firstname;
		},
		
		lastname: function() {
			return this.data.lastname;
		},
		
		id: function() {
			return this.data.id;
		},
		
		guid: function() {
			return this.data.guid;
		},
		
		address: function() {
			return primaryOrFirst(this.data.address);
		},
		
		zip: function() {
			return this.address().postal_code;
		},
		
		phone: function() {
			return primaryOrFirst(this.data.phone).phone;
		},
		
		prune: function() {
			return {
				firstname: this.firstname(),
				lastname: this.lastname(),
				id: this.id(),
				guid: this.guid(),
				email: [{email: this.email()}],
				address: [this.address()],
				phone: [{phone: this.phone()}]
			};
		},
		
		save: function() {
			var self = this;
			var obj = this.prune();
			
			var str, enc;
			try {
				str = JSON.stringify(obj);
				enc = sjcl.encrypt(this.guid(), str);
			} catch(e) {
				console.log(e);
				return false;
			}
			
			var date = new Date();
			date.setTime(date.getTime() + this.options.cookie.expiresIn);
			
			var exp = {};
			if (!$.cookie(this.key())) {
				exp = {expires: date};
			}
			
			var options = $.extend(this.options.cookie.options, exp);
			
			console.log('saving user to: ' + this.key());
			console.dir(obj);
			$.cookie(this.key(), enc, options);
			
			return this.saveGroups();
		},
		
		saveGroups: function() {
			var self = this;
			var success = true;
			$.each(['candidateGroup', 'platformGroup', 'flag'], function(i, grp) {
				var date = new Date();
				date.setTime(date.getTime() + self.options[grp].expiresIn);
				
				var obj = self[grp+'s'];
				
				var str, enc;
				try {
					str = JSON.stringify(obj);
					enc = sjcl.encrypt(self.guid(), str);
				} catch(e) {
					console.log(e);
					success = false;
					return;
				}
				
				var key = self.key() + self.options[grp].cookieSuffix;
				
				var options = $.extend(
					{},
					self.options.cookie.options,
					{expires: date});
				
				console.log('saving ' + grp + 's to: ' + key);
				console.log(obj);
				$.cookie(key, enc, options);
			});
			return success;
		},
		
		inCandidateGroup: function(id) {
			return ($.inArray(id, this.candidateGroups) >= 0);
		},
		
		inPlatformGroup: function(id) {
			return ($.inArray(id, this.platformGroups) >= 0);
		},
		
		joinCandidateGroup: function(id, callback) {
			var self = this;
			var iframe = $('<iframe></iframe>');
			iframe.attr('name','target'+id);
			iframe.attr('frameBorder',0);
			var done = false;
			iframe.bind('load', function() {
				if (!done) {
					done = true;
					if ($.inArray(id, self.candidateGroups) == -1) {
						self.candidateGroups.push(id);
						self.save();
					} 
					if ($.isFunction(callback)) {callback();}
				}
			});
			iframe.hide();
			$('body').append(iframe);
			var form = $('<form></form>');
			form.attr('method', 'POST');
			form.attr('target', 'target'+id);
			form.attr('action', this.options.candidateGroup.formURL);
			form.append(generateInput('email', this.email()));
			form.append(generateInput('zip', this.zip()));
			form.append(generateInput(this.options.candidateGroup.formField, id));
			form.hide();
			$('body').append(form);
			form.submit();
		},
		
		joinPlatformGroup: function(id, callback) {
			var self = this;
			var iframe = $('<iframe></iframe>');
			iframe.attr('src', this.options.platformGroup.framePrefix + 
				id + this.options.platformGroup.frameSuffix);
			var done = false;
			iframe.bind('load', function() {
				if (!done) {
					done = true;
					if ($.inArray(id, self.platformGroups) == -1) {
						self.platformGroups.push(id);
						self.save();
					}
					if ($.isFunction(callback)) {callback();}
				}
			});
			iframe.hide();
			$('body').append(iframe);
		},
		
		addFlag: function(id) {
			if ($.inArray(id, this.flags) == -1) {
				this.flags.push(id);
				this.save();
			}
		},
		
		removeFlag: function(id) {
			if ($.inArray(id, this.flags) > -1) {
				this.flags.splice(this.flags.indexOf(id),1);
				this.save();
			}
		},
		
		hasFlag: function(id) {
			return ($.inArray(id, this.flags) >= 0);
		},
		
		genPass: function() {
			return gen_pass.apply({}, this.options.create.genPassOptions);
		},
		
		create: function(data,redirect) {
			var redirectSlug;
			if (redirect) redirectSlug = '?successurl='+encode64(redirect);
			else redirectSlug = '?successurl='+encode64(this.options.create.defaultRedirect);
			var pass = this.genPass();
			var obj = $.extend({}, this.options.create.base, data);
			var form = $('<form></form>');
			form.attr('method', 'POST');
			form.attr('action', this.options.create.formURL + redirectSlug);
			form.append(generateInput('password1', pass));
			form.append(generateInput('password2', pass));
			form.append(generateInput('firstname', obj.firstname));
			form.append(generateInput('lastname', obj.lastname));
			form.append(generateInput('email', obj.email));
			form.append(generateInput('zip', obj.zip));
			form.append(generateInput('signup_submit', 'Signup'));
			$('body').append(form);
			form.submit();
		}
	};
	
	function primaryOrFirst(ary) {
		if (!ary) { return {};}
		for (var i = 0; i < ary.length; i++) {
			if (ary[i].is_primary && ary[i].postal_code != '*') {
				return ary[i];
			}
		}
		if (ary[0]) {
			return ary[0];
		} else {
			return {};}
	}
	
	function generateInput(key, val) {
		var input = $('<input/>');
		input.attr('type', 'hidden');
		input.attr('name', key);
		input.val(val);
		return input;
	}
	
	function encode64(input) {
		var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
		input = escape(input);
		var output = "";
		var chr1, chr2, chr3 = "";
		var enc1, enc2, enc3, enc4 = "";
		var i = 0;
		do {
			chr1 = input.charCodeAt(i++);
			chr2 = input.charCodeAt(i++);
			chr3 = input.charCodeAt(i++);
			enc1 = chr1 >> 2;
			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
			enc4 = chr3 & 63;
			if (isNaN(chr2)) {
				enc3 = enc4 = 64;
			} else if (isNaN(chr3)) {
				enc4 = 64;
			}
			output = output +
				keyStr.charAt(enc1) +
				keyStr.charAt(enc2) +
				keyStr.charAt(enc3) +
				keyStr.charAt(enc4);
			chr1 = chr2 = chr3 = "";
			enc1 = enc2 = enc3 = enc4 = "";
		} while (i < input.length);
		return output;
	}

	
	function gen_numb(min, max){  
		return (Math.floor(Math.random() * (max - min)) + min);  
	}  

	function gen_chr(num, lwr, upr, oth, ext){  
		var num_chr = "0123456789";  
		var lwr_chr = "abcdefghijklmnopqrstuvwxyz";  
		var upr_chr = lwr_chr.toUpperCase();  
		var oth_chr = "`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/? ";  
		var sel_chr = ext;  

		if(num == true)  
		sel_chr += num_chr;  
		if(lwr == true)  
		sel_chr += lwr_chr;  
		if(upr == true)  
		sel_chr += upr_chr;  
		if(oth == true)  
		sel_chr += oth_chr;  
		return sel_chr.charAt(gen_numb(0, sel_chr.length));  
	}  

	function gen_pass(len, ext, bgn_num, bgn_lwr, bgn_upr, bgn_oth,
		flw_num, flw_lwr, flw_upr, flw_oth){  
			var res = "";  

			if(len > 0){  
				res += gen_chr(bgn_num, bgn_lwr, bgn_upr, bgn_oth, ext);  
				for(var i=1;i<len;i++)  
				res += gen_chr(flw_num, flw_lwr, flw_upr, flw_oth, ext);  
				return res;  
			}  
		}
})(jQuery);

(function(b){b(document).ready(function(){b(".inlinejoinLink").each(function(d,a){var a=b(a),c=a.data("groupslug")||"";User&&""!==c&&!User.inPlatformGroup(c)?a.bind("click",function(b){b.preventDefault();User.get(function(){User.joinPlatformGroup(c,function(){a.slideUp().after("<p>Thanks for signing up&mdash;we'll keep you up to date on the issues that matter to you.</p>")})})}):a.hide()})})})(jQuery);

