(function(){
  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
  this.Class = function(){};
  Class.extend = function(prop) {
    var _super = this.prototype;
    initializing = true;
    var prototype = new this();
    initializing = false;
    for (var name in prop) {
      prototype[name] = typeof prop[name] == "function" &&
        typeof _super[name] == "function" && fnTest.test(prop[name]) ?
        (function(name, fn){
          return function() {
            var tmp = this._super;
            this._super = _super[name];
            var ret = fn.apply(this, arguments);       
            this._super = tmp;
            return ret;
          };
        })(name, prop[name]) :
        prop[name];
    }
    function Class() {
      if ( !initializing && this.init )
        this.init.apply(this, arguments);
    }
    Class.prototype = prototype;
    Class.constructor = Class;
    Class.extend = arguments.callee;
    return Class;
  };
})();
(function($) {
	var el=function(i){return jQuery(document.createElement(i));}
	$.Memory={
		defaults: {
			card: {
				base_class: 'card',
				hidden_class: 'hidden_card',
			},
			game: {
				stats: true,
				board: document.body,
			}
			
		},
		Card: Class.extend({
			init: function(opt) {
				this.opt=$.extend({}, $.Memory.defaults.card,opt);
				var cls=this.opt.base_class+' '+this.opt.memory_class;
				this.element=el('div').addClass(cls);
				this.hidden_element=el('div').addClass(this.opt.hidden_class);
				this.value=this.opt.memory_class;
			},
			hide: function(){
				this.hidden_element.show().insertBefore(this.element.hide());
			},
			show: function(){
				this.element.show().insertBefore(this.hidden_element.hide());
			}
		}),
		Game: Class.extend({
			init: function(opt) {
				this.cards=[];
				this.selected={};
				this.timeout=null;
				this.begin_time={};
				this.end_time={};
				this.current_stat={};
				this.opt=$.extend({},{
					card_classes:[],
				},$.Memory.defaults.game,opt||{});
				this.settings=new $.Memory.Settings(this,{});
				var i=this.opt.card_classes.length;
				this.count=i;
				this.bin=el('div').appendTo(this.opt.board).hide();
				this.stats=el('div').appendTo(this.opt.board).addClass('stats').append(el('h3').text(' Statistik Memoryspel'));
				this.stats_table=el('table').appendTo(this.stats).append(el('thead').append(el('tr').append(el('th').text('Nivå')).append(el('th').text('Tid')).append(el('th').text('Försök')))).append(el('tbody'));
				this.table=el('table').appendTo(this.opt.board).append(el('thead')).append(el('tbody'));
			},
			fill_cards: function(){
				this.cards=[];
				this.opt.card_classes=this.settings.obj.classes;
				var base_class=(this.settings.obj.hasOwnProperty('base_class') ? this.settings.obj.base_class : 'card');
				var i=this.opt.card_classes.length;
				while(i--) {
					this.cards.push(new $.Memory.Card({memory_class:this.opt.card_classes[i], base_class:base_class}));
					this.cards.push(new $.Memory.Card({memory_class:this.opt.card_classes[i], base_class:base_class}));
				}
			},
			append_stat:function(){
				var row=el('tr').appendTo(this.stats_table.find('tbody'));
				el('td').text(this.settings.level).appendTo(row);
				row.time=el('td').appendTo(row);
				row.tries=el('td').appendTo(row).text('0');
				return row;
			},
			shuffle: function(){
				var i = this.cards.length;
				if ( i === 0 ) {return false;}
				while ( --i ) {
					 j = Math.floor( Math.random() * ( i + 1 ) );
					 var tempi = this.cards[i];
					 var tempj = this.cards[j];
					 this.cards[i] = tempj;
					 this.cards[j] = tempi;
				}
			},
			play: function(){
				this.settings.show();
			},
			start: function(){
				if (!this.cards.length) {
					this.fill_cards();
				}
				this.shuffle();
				var i=this.cards.length,
					cols=0,
					table=this.table.find('tbody'),
					row=el('tr').appendTo(table);
				this.count=this.opt.card_classes.length;
				while(i--) {
					cols+=1;
					if (cols > this.settings.obj.cols) {
						row=el('tr').appendTo(this.table);
						cols=1;
					}
					this.cards[i].hidden_element.show().appendTo(el('td').appendTo(row));
				}
				this.begin_time=new Date();
				this.current_stat=this.append_stat();
				this.unbind_cards();
				
			},
			restart: function(){
				this.reset();
				this.fill_cards();
				this.start();
			},
			check: function(){
				if (this.count===1) {
					this.end_game();
				}
				else {
					this.count-=1;
					this.unbind_cards();
				}
			},
			unbind_cards: function(dont_bind){
				var game=this,i=this.cards.length;
				while(i--) {
					this.cards[i].hidden_element.unbind('click');
				}
				if (!dont_bind){game.bind_cards()};
			},
			bind_cards: function(){
				var game=this;
				this.selected={};
				$.each(this.cards,function(k,v) {
					v.hidden_element.click(function(){
						if (game.selected.hasOwnProperty('element')) {//one card has already been selected
							var count=parseInt(game.current_stat.tries.text(),10) || 0;
							game.current_stat.tries.text(count+1);
							if (game.selected.value===v.value) {//match
								game.check();
							}
							else {//no match
								clearTimeout(game.timeout);
								game.unbind_cards(true);
								game.timeout=setTimeout(function(){
									v.hide();
									game.selected.hide();
									game.unbind_cards();
								}, game.settings.obj.speed || 1500);
							}
						}
						else {
							game.selected=v;
						}
						v.show();
						return false;
					});
				});
			},
			end_game: function(){
				var game=this;
				this.end_time=new Date();
				this.current_stat.time.text(((this.end_time-this.begin_time)/1000).toFixed(2)+'s');
				clearTimeout(this.timeout);
				this.timeout=setTimeout(function(){
					$(game.settings.link).trigger('click');
				},2000);
			},
			reset: function(){
				var i=this.cards.length;
				while(i--) {
					var card=this.cards[i];
					card.element.appendTo(this.bin).hide();
					card.hidden_element.appendTo(this.bin).hide();
				};
			}
		}),
		Settings: Class.extend({
			init:function(game,opt){
				this.game=game;
				this.speed=opt.speed || 1000;
				this.link=el('a').attr({href: '#'}).addClass(opt.link || 'settings_link');
				this.level='beginner';
				this.obj=this.game.opt.levels[this.level];
				var s=this;
				$(document).ready(function(){
					$(s.link).prependTo(s.game.stats).gui_settings(s.game);
				});
			},
			set_level: function(level) {
				this.level=level;
				this.obj=this.game.opt.levels[level];
			},
			show: function(){
				this.link.trigger('click');
			},
			hide: function(){
				this.link.show();
			}
		})
	};
	$.fn.gui_settings=function(game,opt) {
		opt=$.extend({},opt||{});
		return $(this).simple_gui({
			callbacks: {
				make: function(base_func){
					var count=0,
						g=base_func({container: 'settings_gui'});
					g.title.text('Inställningar');
					el('h5').appendTo(g.content.empty()).text('Välj nivå');
					g.list=el('ul').appendTo(g.content);
					g.links=[];
					$.each(game.opt.levels, function(k,v) {
						g.links.push(el('a').appendTo(el('li').appendTo(g.list)).text(k).attr({href: '#'}));
					});
					return g;
					
				},
				bind: function(g) {
					$.each(g.links, function(k,v) {
						v.click(function(){
							game.settings.set_level($(this).text());
							g.hide();
							game.restart();
							return false;
						});
					});
				},
				show: function(g) {
					$('a.selected').removeClass('selected');
					$('a[text='+game.settings.level+']').addClass('selected');
					g.container.fadeIn('fast');
					game.settings.link.css({visibility: 'hidden'});
				},
				hide: function(g) {
					g.container.fadeOut('fast');
					game.settings.link.css({visibility: 'visible'});
				},
				position: function(g,e) {
					//var w=$(window).width(),ow=g.container.outerWidth(),h=$(window).height(), oh=g.container.outerHeight();
					//g.css({left:w/2-ow/2, top: h/2-oh/2});
					
					var w=$(window).width(),ow=g.container.outerWidth(),h=$(window).height(), oh=g.container.outerHeight();
					g.css({left:w/2-ow/2, top: h/2-oh/2+60});
					
				}
			}
		});
	}
		
})(jQuery);

