define(["helper/Basic", "Tone/event/Pattern", "Tone/core/Tone", "Tone/core/Transport", "helper/Offline", "Tone/type/Time"],
	function (Basic, Pattern, Tone, Transport, Offline, Time) {

		describe("Pattern", function(){

			Basic(Pattern);

			context("Constructor", function(){

				it("takes a callback, an array of values and a pattern name", function(){
					return Offline(function(){
						var callback = function(){};
						var pattern = new Pattern(callback, [0, 1, 2, 3], "down");
						expect(pattern.callback).to.equal(callback);
						expect(pattern.values).to.deep.equal([0, 1, 2, 3]);
						expect(pattern.pattern).to.equal("down");
						pattern.dispose();
					});
				});

				it("can be constructed with no arguments", function(){
					return Offline(function(){
						var pattern = new Pattern();
						pattern.dispose();
					});
				});

				it("can pass in arguments in options object", function(){
					return Offline(function(){
						var callback = function(){};
						var pattern = new Pattern({
							"callback" : callback,
							"iterations" : 4,
							"probability" : 0.3,
							"interval" : "8t",
							"values" : [1, 2, 3],
							"pattern" : "upDown"
						});
						expect(pattern.callback).to.equal(callback);
						expect(pattern.interval.valueOf()).to.equal(Time("8t").valueOf());
						expect(pattern.iterations).to.equal(4);
						expect(pattern.values).to.deep.equal([1, 2, 3]);
						expect(pattern.probability).to.equal(0.3);
						expect(pattern.pattern).to.equal("upDown");
						pattern.dispose();
					});
				});
			});

			context("Get/Set", function(){

				it("can set values with object", function(){
					return Offline(function(){
						var callback = function(){};
						var pattern = new Pattern();
						pattern.set({
							"callback" : callback,
							"values" : ["a", "b", "c"],
							"index" : 2
						});
						expect(pattern.callback).to.equal(callback);
						expect(pattern.values).to.deep.equal(["a", "b", "c"]);
						expect(pattern.index).to.equal(2);
						pattern.dispose();
					});
				});

				it("can set get a the values as an object", function(){
					return Offline(function(){
						var callback = function(){};
						var pattern = new Pattern({
							"callback" : callback,
							"pattern" : "random",
							"probability" : 0.3,
						});
						var values = pattern.get();
						expect(values.pattern).to.equal("random");
						expect(values.probability).to.equal(0.3);
						pattern.dispose();
					});
				});
			});

			context("Callback", function(){

				it("is invoked after it's started", function(){
					var invoked = false;
					return Offline(function(Transport){
						new Pattern(function(){
							invoked = true;
						}, [0, 1, 2]).start(0);
						Transport.start();
					}, 0.2).then(function(){
						expect(invoked).to.be.true;
					});
				});

				it("passes in the scheduled time and pattern index to the callback", function(){
					var invoked = false;
					return Offline(function(Transport){
						var startTime = 0.05;
						var pattern = new Pattern(function(time, note){
							expect(time).to.be.a.number;
							expect(time - startTime).to.be.closeTo(0.3, 0.01);
							expect(note).to.be.equal("a");
							invoked = true;
						}, ["a"], "up");
						Transport.start(startTime);
						pattern.start(0.3);
					}, 0.4).then(function(){
						expect(invoked).to.be.true;
					});
				});

				it("passes in the next note of the pattern", function(){
					var counter = 0;
					return Offline(function(Transport){
						var pattern = new Pattern(function(time, note){
							expect(note).to.equal(counter % 3);
							counter++;
						}, [0, 1, 2], "up").start(0);
						pattern.interval = "16n";
						Transport.start(0);
					}, 0.7).then(function(){
						expect(counter).to.equal(6);
					});
				});
			});

		});
	});