/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Collapse Main Controller Class
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
var Collapse = new Class({

	Implements: [Events, Options],
	
	options: {/*
		onStart: $empty,
		onCollapse: $empty,
		onHighlight: $empty,*/
		cols: 12,
		rows: 15,
		grid: 30
	},
	
	initialize: function(container, options){
		this.setOptions(options);
		this.cols = this.options.cols;
		this.rows = this.options.rows;
		this.types = Collapse.Blocks.getValues().splice(1, 3);
		this.blocks = [];
		this.columns = [];
		this.container = $(container).setStyle('width', this.cols * this.options.grid);
		
		this.build();
		this.newGame();
	},
	
	build: function(){
		var createTable = function(side){
			return new Element('div', {
				'class': 'side'
			}).adopt(new Element('table', {
				'cellpadding': 0,
				'cellspacing': 0
			}).setStyle('float', side).adopt(new Element('tbody').adopt(new Element('tr'))));
		};
		
		this.container.adopt(new Element('div').addEvents({
			'mousedown': this.process.bindWithEvent(this, 'collapse'),
			'mouseover': this.process.bindWithEvent(this, 'highlight')
		}).adopt(createTable('right'), createTable('left')));
	},
	
	clearGame: function(){
		this.blocks.map(function(block){ block.element.destroy(); });
		this.columns.map(function(column){ column.element.destroy(); });
		this.blocks = [];
		this.columns = [];
	},

	newGame: function(){
		this.clearGame();
		var columns = [];
		
		for (var col = 0; col < this.cols; col++){
			var blocks = [], top = col < (this.cols / 2).floor();
			var column = new Collapse.Column(top, {
				rows: this.rows,
				width: this.options.grid
			});
			this.columns[col] = column;
			
			for (var row = this.rows; row--;){
				var block, type = $random(0, 20);
				if (type == 0) block = new Collapse.Block.Bomb(5, { size: this.options.grid });
				else if (type == 1) block = new Collapse.Block({ size: this.options.grid });
				else block = new Collapse.Block.Color(this.types.getRandom(), { size: this.options.grid });
				
				block.setPos(col, row);
				column.blocks[row] = block;
				blocks.push(block.element);
			}
			columns.push(column.element.adopt(blocks));
		}
		
		var sides = this.container.getElements('tr'), half = (columns.length / 2).floor();
		
		sides[0].adopt(columns.slice(0, half));
		sides[1].adopt(columns.slice( - half));
		
		this.restructure();
		
		this.fireEvent('onStart');
	},
	
	process: function(event, callback){
		var block = event.target.retrieve('block');
		this[callback](block ? block.process(this.columns) : [], event.shift);
	},
	
	highlight: function(collection){
		if (this.collection) this.collection.each(function(block){ block.element.set('class', block.type); });
		collection.each(function(block){ block.element.addClass('active'); });
		this.collection = collection;

		this.fireEvent('onHighlight', [collection]);
	},
	
	collapse: function(collection, slow){
		if (!collection.length) return;
		
		var elements = [], self = this;
		for (var index = collection.length; index--;){
			var block = collection[index];
			elements.push(block.element.hide());
			this.columns[block.col].blocks.erase(block);
		}
		
		var misplaced = this.restructure();
		
		new Fx.TweenMany(elements, {
			duration: slow ? 2000 : 200,
			property: 'height',
			transition: 'sine:in',
			onComplete: function(){
				$$(arguments).destroy();
				self.redraw(misplaced, slow);
			}
		}).start(this.options.grid, 0);
		
		this.fireEvent('onCollapse', [elements]);
	},
	
	restructure: function(){
		var blocks = [], columns = [], misplaced = [];
		
		this.columns.each(function(column, col){
			((column.empty || column.blocks.length > 0) ? columns : misplaced).push(column);
		});
		
		misplaced.each(function(column){
			column.empty = true;
			columns = column.top ? [column].concat(columns) : columns.concat(column);
		});
		
		columns.each(function(column, col){
			column.blocks.each(function(block, row){
				if (block) blocks.push(block.setPos(col, row));
			});
		});
		
		this.columns = columns;
		this.blocks = blocks;
		return misplaced;
	},
	
	redraw: function(misplaced, slow){
		if (!misplaced.length) return;
		
		var elements = misplaced.map(function(column){
			return column.element;
		});
		
		new Fx.TweenMany(elements, {
			duration: slow ? 2000 : 200,
			property: 'width',
			transition: 'sine:out',
			onComplete: function(){
				misplaced.each(function(column){
					column.shift();
				});
			}
		}).start(this.options.grid, 0);
	},
	
	print: function(){
		return this.columns.map(function(column){
			return column.blocks.map(function(block){
				return [block.row, block.col, block.element];
			});
		});
	}
	
});

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Collapse Column Class
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
Collapse.Column = new Class({
	
	Implements: Options,
	
	options: {
		rows: 15,
		width: 30
	},
	
	initialize: function(top, options){
		this.setOptions(options);
		this.blocks = [];
		this.top = top;
		
		this.element = new Element('td', {
			valign: 'bottom',
			styles: {
				width: this.options.width,
				height: this.options.width * this.options.rows
			}
		});
	},
	
	shift: function(){
		this.element.setStyle('width', this.options.width).inject(this.element.getParent(), this.top ? 'top' : 'bottom');
	}

});


