(function(window, $, page) {
	
	var NI = window.NI,
	    HALF_PI = window.Math.PI/2;
	
	page.classes.Canvas_cycler = function(options) {
		
		var me, o, cycler, ctx;
		
		me = this;
		o = $.extend({
			$e: null,
			speed: 0.02,
			strokeStyle: "#e3e3e3",
			lineWidth: 3,
			
			//callbacks
			on_canvas_unsupported: $.noop,
			on_play: $.noop,
			on_pause: $.noop,
			on_cycle_complete: $.noop
		}, options);
		
		function init() {
			var $c;
			
			if (typeof o.$e === "string") {
				o.$e = $(o.$e);
			}
			if (!(o.$e instanceof $) || !o.$e.length) {
				console.warn("Canvas_cycler: missing $e");
				return false;
			}
			
			$c = $("<canvas></canvas>");
			ctx = $c[0].getContext("2d");
			if (!ctx) {
				o.on_canvas_unsupported();
				console.warn("Canvas_cycler: canvas not supported");
				return false;
			}
			
			ctx.canvas.width = o.$e.width();
			ctx.canvas.height = o.$e.height();
			
			$c.appendTo(o.$e);
			
			cycler = new NI.anim.Cycler({
				speed: o.speed ? o.speed : undefined,
				
				on_play: function() {
					o.$e.removeClass("state-paused");
					o.on_play.apply(me);
				},
				on_pause: function() {
					ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
					
					ctx.beginPath();
					ctx.arc(ctx.canvas.width/2, ctx.canvas.height/2, ctx.canvas.width/2 - o.lineWidth, 
						0, window.Math.PI*2, false);
					
					ctx.strokeStyle = o.strokeStyle;
					ctx.lineWidth = o.lineWidth;
					ctx.stroke();
					
					o.$e.addClass("state-paused");
					o.on_pause.apply(me);
				},
				on_before_update: function() {
					// don't update if the element container is hidden:
					return o.$e.is(":visible");
				},
				on_update: function(theta) {
					ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
					
					ctx.beginPath();
					ctx.arc(ctx.canvas.width/2, ctx.canvas.height/2, ctx.canvas.width/2 - o.lineWidth, 
						-HALF_PI, theta-HALF_PI, false);
					
					ctx.strokeStyle = o.strokeStyle;
					ctx.lineWidth = o.lineWidth;
					ctx.stroke();
				},
				on_cycle_complete: function() {
					o.on_cycle_complete.apply(me);
				}
			});
			
			$c.click(function() {
				if (cycler.isCycling()) {
					cycler.pause();
				} else {
					cycler.play();
				}
			});
		}
		
		this.play = function() {
			cycler.play();
			return this;
		};
		
		this.pause = function() {
			cycler.pause();
			return this;
		};
		
		this.isCycling = function() {
			return cycler.isCycling();
		};
		
		this.reset = function() {
			cycler.reset();
			return this;
		};
		
		if (init() !== false) {
			
		}
	};

}(this, this.jQuery, this.page));
