/*
	Test approach:
	Build reproducible data structures synchronously and asynchronously,
	then compare the results.

*/
var testClumpy = {

	testFor: function (self) {
		var clumpy = new Clumpy(),
			i,
			a = [],
			b = [],
			bound = 10000;
		
		// control
		for (i = 0; i < bound; i++) {
			a.push(i);
		}

		// test
		return clumpy.
		for_loop(
			function(){i = 0;},
			function(){return i < bound;},
			function(){i++;},
			function(){
				b.push(i);
			}
		).
		once(function () {
			self.assertEq(a, b);
			self.next();
		});
	},
	
	testForIn: function (self) {
		var clumpy = new Clumpy(),
			i,
			a = {},
			b = {},
			people = {
				'Thomas': 31,
				'Lisa': 28,
				'Roseann': 25,
				'Libby': 26,
				'Drew': 28,
				'Dave': 40
			};
		
		// control
		for (i in people) {
			a[i] = people[i];
		}

		// test
		return clumpy.
		for_in_loop(
			people,
			function(i){
				b[i] = people[i];
			}
		).
		once(function () {
			self.assertEq(a, b);
			self.assertEq(b, people);
			self.next();
		});
	},
	
	testWhile: function (self) {
		var clumpy = new Clumpy(),
			i,
			a = [],
			b = [],
			bound = 10000;
		
		// control
		i = 0;
		while (i < bound) {
			a.push(i);
			i++;
		}

		// test
		return clumpy.
		once(function () {
			i = 0;
		}).
		while_loop(
			function(){return i < bound;},
			function(){
				b.push(i);
				i++;
			}
		).
		once(function () {
			self.assertEq(a, b);
			self.next();
		});
	},
	
	testDoWhile: function (self) {
		var clumpy = new Clumpy(),
			i,
			a = [],
			b = [],
			bound = 10000;
		
		// control
		i = 0;
		do {
			a.push(i);
			i++;
		} while (i < bound);

		// test
		return clumpy.
		once(function () {
			i = 0;
		}).
		do_while_loop(
			function(){
				b.push(i);
				i++;
			},
			function(){return i < bound;}
		).
		once(function () {
			self.assertEq(a, b);
			self.next();
		});
	},
	
	testContinueUnnested: function (self) {
		var clumpy = new Clumpy(),
			i,
			a = [],
			b = [],
			bound = 10000;
		
		// control
		for (i = 0; i < bound; i++) {
			if (10 < i && i < 100) {
				continue;
			}
			a.push(i);
		}

		// test
		return clumpy.
		for_loop(
			function(){i = 0;},
			function(){return i < bound;},
			function(){i++;},
			function(){
				if (10 < i && i < 100) {
					return clumpy.
					continue_loop();
				}
				b.push(i);
			}
		).
		once(function () {
			self.assertEq(a, b);
			self.next();
		});
	},
	
	testBreakUnnested: function (self) {
		var clumpy = new Clumpy(),
			i,
			a = [],
			b = [],
			bound = 25000;
		
		// control
		for (i = 0; i < bound; i++) {
			if (i > bound / 2) {
				break;
			}
			a.push(i);
		}
		
		// test
		return clumpy.
		for_loop(
			function(){i = 0;},
			function(){return i < bound;},
			function(){i++;},
			function(){
				if (i > bound / 2) {
					return clumpy.
					break_loop();
				}
				b.push(i);
			}
		).
		once(function () {
			self.assertEq(a, b);
			self.next();
		});
	},
	
	testContinueNested: function (self) {
		var clumpy = new Clumpy(),
			i, j,
			a = [],
			b = [],
			iBound = 100,
			jBound = 100;
		
		// control
		for (i = 0; i < iBound; i++) {
			a.push([]);
			if (i === 3) {
				continue;
			}
			for (j = 0; j < jBound; j++) {
				if (j === 2) {
					continue;
				}
				a[i].push([i,j]);
			}
		}
		
		// test
		return clumpy.
		for_loop(
			function(){i = 0;},
			function(){return i < iBound;},
			function(){i++;},
			function(){
				return clumpy.
				once(function () {
					b.push([]);
					if (i === 3) {
						return clumpy.
						continue_loop();
					}
				}).
				for_loop(
					function(){j = 0;},
					function(){return j < jBound;},
					function(){j++;},
					function(){
						if (j === 2) {
							return clumpy.
							continue_loop();
						}
						b[i].push([i,j]);
					}
				);
			}
		).
		once(function () {
			self.assertEq(a, b);
			self.next();
		});
	},
	
	testBreakNested: function (self) {
		var clumpy = new Clumpy(),
			i, j,
			a = [],
			b = [],
			iBound = 100,
			jBound = 100;
		
		// control
		for (i = 0; i < iBound; i++) {
			if (i > iBound / 2) {
				break;
			}
			a.push([]);
			for (j = 0; j < jBound; j++) {
				if (j > jBound / 2) {
					break;
				}
				a[i].push([i,j]);
			}
		}
		
		// test
		return clumpy.
		for_loop(
			function(){i = 0;},
			function(){return i < iBound;},
			function(){i++;},
			function(){
				return clumpy.
				once(function () {
					if (i > iBound / 2) {
						return clumpy.
						break_loop();
					}
					b.push([]);
				}).
				for_loop(
					function(){j = 0;},
					function(){return j < jBound;},
					function(){j++;},
					function(){
						if (j > jBound / 2) {
							return clumpy.
							break_loop();
						}
						b[i].push([i,j]);
					}
				);
			}
		).
		once(function () {
			self.assertEq(a, b);
			self.next();
		});
	},
	
	testContinueLabelUnnested: function (self) {
		var clumpy = new Clumpy(),
			i,
			a = [],
			b = [],
			bound = 10000;
		
		// control
		myLabel:
		for (i = 0; i < bound; i++) {
			if (10 < i && i < 100) {
				continue myLabel;
			}
			a.push(i);
		}

		// test
		return clumpy.
		label('myLabel').
		for_loop(
			function(){i = 0;},
			function(){return i < bound;},
			function(){i++;},
			function(){
				if (10 < i && i < 100) {
					return clumpy.
					continue_loop('myLabel');
				}
				b.push(i);
			}
		).
		once(function () {
			self.assertEq(a, b);
			self.next();
		});
	},

	testBreakLabelUnnested: function (self) {
		var clumpy = new Clumpy(),
			i,
			a = [],
			b = [],
			bound = 25000;
		
		// control
		myLabel:
		for (i = 0; i < bound; i++) {
			if (i > bound / 2) {
				break myLabel;
			}
			a.push(i);
		}
		
		// test
		return clumpy.
		label('myLabel').
		for_loop(
			function(){i = 0;},
			function(){return i < bound;},
			function(){i++;},
			function(){
				if (i > bound / 2) {
					return clumpy.
					break_loop('myLabel');
				}
				b.push(i);
			}
		).
		once(function () {
			self.assertEq(a, b);
			self.next();
		});
	},
	
	testContinueLabelNested: function (self) {
		var clumpy = new Clumpy(),
			i, j,
			a = [],
			b = [],
			iBound = 100,
			jBound = 100;
		
		// control
		myLabel:
		for (i = 0; i < iBound; i++) {
			a.push([]);
			if (i === 3) {
				continue;
			}
			for (j = 0; j < jBound; j++) {
				if (j === 2) {
					continue myLabel;
				}
				a[i].push([i,j]);
			}
		}
		
		// test
		return clumpy.
		label('myLabel').
		for_loop(
			function(){i = 0;},
			function(){return i < iBound;},
			function(){i++;},
			function(){
				return clumpy.
				once(function () {
					b.push([]);
					if (i === 3) {
						return clumpy.
						continue_loop();
					}
				}).
				for_loop(
					function(){j = 0;},
					function(){return j < jBound;},
					function(){j++;},
					function(){
						if (j === 2) {
							return clumpy.
							continue_loop('myLabel');
						}
						b[i].push([i,j]);
					}
				);
			}
		).
		once(function () {
			self.assertEq(a, b);
			self.next();
		});
	},

	testBreakLabelNested: function (self) {
		var clumpy = new Clumpy(),
			i, j,
			a = [],
			b = [],
			iBound = 100,
			jBound = 100;
		
		// control
		myLabel:
		for (i = 0; i < iBound; i++) {
			if (i > iBound / 2) {
				break;
			}
			a.push([]);
			for (j = 0; j < jBound; j++) {
				if (j > jBound / 2) {
					break myLabel;
				}
				a[i].push([i,j]);
			}
		}
		
		// test
		return clumpy.
		label('myLabel').
		for_loop(
			function(){i = 0;},
			function(){return i < iBound;},
			function(){i++;},
			function(){
				return clumpy.
				once(function () {
					if (i > iBound / 2) {
						return clumpy.
						break_loop();
					}
					b.push([]);
				}).
				for_loop(
					function(){j = 0;},
					function(){return j < jBound;},
					function(){j++;},
					function(){
						if (j > jBound / 2) {
							return clumpy.
							break_loop('myLabel');
						}
						b[i].push([i,j]);
					}
				);
			}
		).
		once(function () {
			self.assertEq(a, b);
			self.next();
		});
	},
	
	testMultipleInstances: function (self) {
	
		var myself = testClumpy,
			started = 0,
			finished = 0;
		
		function start(test) {
			started += 1;
			myself[test].call(null, {
				next: function () {
					finished += 1;
					if (finished === started) {
						self.next();
					}
				},
				assertEq: function (a, b) {
					return self.assertEq(a, b);
				}
			});
		}
		
		start('testFor');
		start('testForIn');
		start('testWhile');
		start('testDoWhile');
		start('testContinueUnnested');
		start('testBreakUnnested');
		start('testContinueNested');
		start('testBreakNested');
		start('testContinueLabelUnnested');
		start('testBreakLabelUnnested');
		start('testContinueLabelNested');
		start('testBreakLabelNested');
	},
	
	testNestedDeep: function (self) {
		var clumpy = new Clumpy(),
			i, j, k, l,
			a = [],
			b = [],
			bound = 10;
		
		// control
		for (i = 0; i < bound; i++) {
			for (j = 0; j < bound; j++) {
				for (k = 0; k < bound; k++) {
					a.push([i,j,k]);
				}
				for (k = -1; k < bound; k++) {
					a.push([i,j,k]);
				}
				for (k = -2; k < bound; k++) {
					a.push([i,j,k]);
				}
			}
			for (j = -1; j < bound; j++) {
				for (k = 0; k < bound; k++) {
					a.push([i,j,k]);
				}
				for (k = -1; k < bound; k++) {
					a.push([i,j,k]);
				}
				for (k = -2; k < bound; k++) {
					for (l = 0; l < bound; l++) {
						a.push([i,j,k,l]);
					}
				}
			}
		}

		// test
		return clumpy.
		for_loop(
			function(){i = 0;},
			function(){return i < bound;},
			function(){i++;},
			function(){
				return clumpy.
				for_loop(
					function(){j = 0;},
					function(){return j < bound;},
					function(){j++;},
					function(){
						return clumpy.
						for_loop(
							function(){k = 0;},
							function(){return k < bound;},
							function(){k++;},
							function(){
								b.push([i,j,k]);
							}
						).
						for_loop(
							function(){k = -1;},
							function(){return k < bound;},
							function(){k++;},
							function(){
								b.push([i,j,k]);
							}
						).
						for_loop(
							function(){k = -2;},
							function(){return k < bound;},
							function(){k++;},
							function(){
								b.push([i,j,k]);
							}
						);
					}
				).
				for_loop(
					function(){j = -1;},
					function(){return j < bound;},
					function(){j++;},
					function(){
						return clumpy.
						for_loop(
							function(){k = 0;},
							function(){return k < bound;},
							function(){k++;},
							function(){
								b.push([i,j,k]);
							}
						).
						for_loop(
							function(){k = -1;},
							function(){return k < bound;},
							function(){k++;},
							function(){
								b.push([i,j,k]);
							}
						).
						for_loop(
							function(){k = -2;},
							function(){return k < bound;},
							function(){k++;},
							function(){
								return clumpy.
								for_loop(
									function(){l = 0;},
									function(){return l < bound;},
									function(){l++;},
									function(){
										b.push([i,j,k,l]);
									}
								);
							}
						);
					}
				);
			}
		).
		once(function () {
			self.assertEq(a, b);
			self.next();
		});
	},
	
	testReuse: function (self) {
		var clumpy = new Clumpy(),
			i,
			a = [],
			b = [],
			bound = 20000;

		// control
		for (i = 0; i < bound; i++) {
			a.push(i);
		}
		
		return clumpy.
		for_loop(
			function () { i = 0; },
			function () { return i < bound; },
			function () { i += 1; },
			function () {
				b.push(i);
			}
		).
		once(function () {
			setTimeout(function () {
				clumpy.once(function () {
					self.assertEq(a, b);
					self.next();
				});
			}, 1000);
		});
	},

	testBrowserResponsiveness: function (self) {
		var message = "This test starts starts an infinite loop, generating random numbers, and then stops it after one minute.  During this time, evaluate the responsiveness of your browser.  Since this is a subjective test, it will always pass.  Do you want to perform this test?",
			clumpy = new Clumpy(),
			myBox = new EchoBox('responsiveness', 200);
			
		if (confirm(message)) {
		
			setTimeout(function () {
				clumpy.pause();
				alert('Browser Responsiveness Test is complete.');
				self.next();
			}, 60000);
			
			return clumpy.
			while_loop(
				function(){return true;},
				function(){
					myBox.writeln(Math.random());
				}
			);
			
		} else {
			self.next();
		}
	}
	
};
