
var commandProcessor = Class.create({
	initialize: function() {
		this.undoable_commands = new Array();
		this.next_command_id = 0;
	},  
	execute: function(command) {
		command.execute(this.next_command_id++);
		if (command.is_undoable)
		{
			this.undoable_commands.push(command);
			update_keypad_buttons(bb.GetActiveCell_TableIndex());
		}
	},
	undo: function()
	{
		if (this.undoable_commands.length > 0)
		{
			if (bb.currentHintData)
			{
				bb.ClearHint(bb.currentHintData);
			}
			this.undoable_commands.pop().undo();
			update_keypad_buttons(bb.GetActiveCell_TableIndex());
		}
	},
	clear_undo: function()
	{
		this.undoable_commands.length = 0;
	}
});

Ajax.Responders.register({
	onCreate: function() { 
		$('Loading' ).show(); 
	},
	onComplete: function() {
		if (0 == Ajax.activeRequestCount)
		{
			$('Loading' ).hide();
		}
	}
});

var Undo_Command = Class.create({
	initialize: function() {
	},  
	execute: function() {
		CommandProcessor.undo();
	}
});

var NewPuzzle_Command = Class.create({
	initialize: function(difficulty) {
		this.difficulty = difficulty;
	},  
	execute: function() {
		CommandProcessor.clear_undo();
		var request = new Ajax.Request('cgi-bin/SudokuEngineCGI.cgi?NewPuzzle-'+this.difficulty+'-'+Math.floor(Math.random()*500011) ,
						{
							method:'GET',
							contentType: "application/x-www-form-urlencoded",
							onSuccess: function(transport)
							{ 
								var response = transport.responseText || "no response text";
								bb.NewGame(response);
								
								GameBoard_ButtonClicked();
								var cmd = new FillValidCandidates_Command();
								CommandProcessor.execute( cmd );
							},
							onFailure: function()
							{ 
								alert(g_ajaxrequest_failed) 
							}
						});
	}
});

var SetCandidateValue_Command = Class.create({
	initialize: function(cell_table_index, candidateToSet, candidateValue) {
		this.is_undoable = true;
		this.cell_table_index = cell_table_index;
		this.candidateToSet = candidateToSet;
		this.candidateValue = candidateValue;
	},  
	execute: function() {
		if (bb.currentHintData)
		{
			bb.ClearHint(bb.currentHintData);
		}
		bb.SetCandidateValue(null, this.cell_table_index, this.candidateToSet, this.candidateValue);
	},

	undo: function() {
		bb.SetCandidateValue(null, this.cell_table_index, this.candidateToSet, !this.candidateValue);
	}
});

var SetUserValue_Command = Class.create({
	initialize: function(cell_table_index, user_value_to_set) {
		this.is_undoable = true;
		this.cell_table_index = cell_table_index;
		this.user_value_to_set = user_value_to_set;
	},  
	
	execute: function() {
		this.uservalue_table_index = this.cell_table_index;
		this.old_candidates = bb.SerializeCandidates();	
		if (bb.currentHintData)
		{
			bb.ClearHint(bb.currentHintData);
		}
		
		row_group_index = bb.GetRowIndexFromTableIndex(this.cell_table_index);
		col_group_index = bb.GetColumnIndexFromTableIndex(this.cell_table_index);
		box_group_index = bb.GetBoxIndexFromTableIndex(this.cell_table_index);
		
		for( i = 0, len = bb.Tbn*bb.Tbn; i < len; ++i)
		{	
			table_index = bb.Row_CellGroupIndexToCellTableIndex(i, row_group_index);
			if(bb.Cells[table_index].user_value == 0)
			{
				bb.SetCandidateValue(null, table_index, this.user_value_to_set, false);
			}
			table_index = bb.Col_CellGroupIndexToCellTableIndex(i, col_group_index);
			if(bb.Cells[table_index].user_value == 0)
			{
				bb.SetCandidateValue(null, table_index, this.user_value_to_set, false);
			}
			table_index = bb.Box_CellGroupIndexToCellTableIndex(i, box_group_index);
			if(bb.Cells[table_index].user_value == 0)
			{
				bb.SetCandidateValue(null, table_index, this.user_value_to_set, false);
			}
		}
	
		bb.SetUserValue(null, this.cell_table_index, this.user_value_to_set);
		
		for( i = 0, len = bb.Tbn*bb.Tbn*bb.Tbn*bb.Tbn; i < len; ++i)
		{	
			if(bb.Cells[i].user_value == 0)
			{
				break;
			}
		}
		
		if(i == len)
		{	
			var serialized_grid = bb.SerializeGrid();
			var request = new Ajax.Request('cgi-bin/SudokuEngineCGI.cgi?CheckForCorrectGrid-'+serialized_grid, 
			{
				method:'get', 
				contentType: "application/x-www-form-urlencoded",
				onSuccess: function(transport)
				{
					var response = transport.responseText || "no response text";
					if (response.charAt(0) == '1')
					{
						alert(g_resource_puzzle_solved_msg);
					}
					else
					{
						alert(g_resource_puzzle_wrong_solved_msg);
					}
					
				},
				onFailure: function()
				{ 
					
				}
			});			
		}
			
	},

	undo: function() {
		bb.SetUserValue( null, this.uservalue_table_index, 0 );
		bb.SetGridCandidates( this.old_candidates );
	}
});

var DeleteUserValue_Command = Class.create({
	initialize: function(cell_table_index, user_value_to_delete) {
		this.is_undoable = true;
		this.cell_table_index = cell_table_index;
		this.user_value_to_delete = user_value_to_delete;
	},  
	
	execute: function() {
		if (bb.currentHintData)
		{
			bb.ClearHint(bb.currentHintData);
		}
		bb.ClearCell(null, this.cell_table_index);
		bb.SetUserValue(null, this.cell_table_index, 0);
	},
	
	undo: function()
	{
		bb.ClearCell(null, this.cell_table_index);
		bb.SetUserValue(null, this.cell_table_index,this.user_value_to_delete);
	}
});

var DeleteCandidates_Command = Class.create({
	initialize: function(cell_table_index, candidates_to_delete) {
		this.is_undoable = true;
		this.cell_table_index = cell_table_index;
		this.candidates_to_delete = candidates_to_delete;
	},  
	
	execute: function() {
		if (bb.currentHintData)
		{
			bb.ClearHint(bb.currentHintData);
		}
		bb.ClearCell(null, this.cell_table_index);
		bb.SetCandidateValue(null, this.cell_table_index, 0, true);
	},
	
	undo: function()
	{
		bb.ClearCell(null, this.cell_table_index);
		
		for (ci = 0; ci < bb.Tbn*bb.Tbn; ++ci) {
		
			candidate_to_delete = this.candidates_to_delete & g_mask[ci];
			if(candidate_to_delete)
			{
				bb.SetCandidateValue(null, this.cell_table_index, ci + 1, true);
			}
		}
	}
});

var CheckForCorrectGrid_Command = Class.create({
	initialize: function(table_data) {
		this.table_data = table_data;
	},  
	
	execute: function() {
		var serialized_grid = bb.SerializeGrid();
		
		var request = new Ajax.Request('cgi-bin/SudokuEngineCGI.cgi?CheckForCorrectGrid-'+serialized_grid, 
						{
							method:'get',
							contentType: "application/x-www-form-urlencoded",
							onSuccess: function(transport)
							{
								var response = transport.responseText || "no response text";
								if (response.charAt(0) == '1')
								{
									alert(g_resource_puzzle_ok_msg);
								}
								else
								{
									alert(g_resource_puzzle_wrong_msg);
								}
								GameBoard_ButtonClicked();
							},
							onFailure: function()
							{ 
								alert(g_ajaxrequest_failed) 
							}
						});
	}
});

var FillValidCandidates_Command = Class.create({
	initialize: function(table_data) {
		this.is_undoable = true;
		this.old_candidates = new Array();
	},
	
	execute: function() {
		var serialized_grid = bb.SerializeGrid();
		var i = 0; var len = 0;
		for( i = 0, len = bb.Cells.length; i < len; ++i)
		{
			this.old_candidates.push( bb.Cells[i].candidates );
		}
		
		var request = new Ajax.Request('cgi-bin/SudokuEngineCGI.cgi?FillValidCandidates-'+serialized_grid, 
						{
							method:'get',
							contentType: "application/x-www-form-urlencoded",
							onSuccess: function(transport)
							{
								var response = transport.responseText || "no response text";
					
								var candidates_string_array = response.split(',');
								var candidates_int_array = new Array();
								var i = 0; var len = 0;
								for( i = 0, len = candidates_string_array.length; i < len; ++i)
								{
									candidates_int_array.push( parseInt( candidates_string_array[i] ) );
								}
								GameBoard_ButtonClicked();
								bb.SetGridCandidates( candidates_int_array );
							},
							onFailure: function()
							{ 
								alert(g_ajaxrequest_failed) 
							}
						});
		request.command = this;
	},
	
	undo: function() {
		bb.SetGridCandidates( this.old_candidates );
	}
});

var FillAllCandidates_Command = Class.create({
	initialize: function(table_data) {
		this.is_undoable = true;
		this.old_candidates = new Array();
	},
	
	execute: function() {
		var i = 0; var len = 0;
		for( i = 0, len = bb.Cells.length; i < len; ++i)
		{
			this.old_candidates.push( bb.Cells[i].candidates );
		}
		
		var candidates_int_array = new Array();
		var fullBits = (1 << bb.Tbn*bb.Tbn) - 1;
		var i = 0; var len = 0;
		for( i = 0, len = bb.Tbn*bb.Tbn*bb.Tbn*bb.Tbn; i < len; ++i)
		{
			candidates_int_array.push( fullBits );
		}
		bb.SetGridCandidates( candidates_int_array );
		GameBoard_ButtonClicked();
	},
	
	undo: function() {
		bb.SetGridCandidates( this.old_candidates );
	}
});


var ClearAllCandidates_Command = Class.create({
	initialize: function(table_data) {
		this.is_undoable = true;
		this.old_candidates = new Array();

		var i = 0; var len = 0;
		for( i = 0, len = bb.Cells.length; i < len; ++i)
		{
			this.old_candidates.push( bb.Cells[i].candidates );
		}
	},
	
	execute: function() {
		var serialized_grid = bb.SerializeGrid();
		this.old_candidates = bb.SerializeCandidates();
		
		var candidates_int_array = new Array();
		var i = 0; var len = 0;
		for( i = 0, len = bb.Tbn*bb.Tbn*bb.Tbn*bb.Tbn; i < len; ++i)
		{
			candidates_int_array.push( 0 );
		}
		bb.SetGridCandidates( candidates_int_array );
		GameBoard_ButtonClicked();
	},
	
	undo: function() {
		bb.SetGridCandidates( this.old_candidates );
	}
});

var RemoveWrongValues_Command = Class.create({
	initialize: function(table_data) {
		this.is_undoable = true;
		this.old_user_values = new Array();
	},
	
	execute: function() {
		this.old_user_values = bb.SerializeGrid();
		var serialized_grid_uservalues = this.old_user_values;
		var serialized_grid_titulars = bb.SerializeGridTitulars();
		
		var request = new Ajax.Request('cgi-bin/SudokuEngineCGI.cgi?RemoveWrongValues-'+serialized_grid_uservalues+'-'+serialized_grid_titulars, 
						{
							method:'get',
							contentType: "application/x-www-form-urlencoded", 
							onSuccess: function(transport)
							{
								var response = transport.responseText || "no response text";
					
								var uservalues_int_array = new Array();
								var i = 0; var len = 0;
								for( i = 0, len = response.length; i < len; ++i)
								{
									uservalues_int_array.push( parseInt(response.charAt(i)) );
								}

								bb.SetGridUserValues( uservalues_int_array );
								GameBoard_ButtonClicked();
							},
							onFailure: function()
							{ 
								alert(g_ajaxrequest_failed) 
							}
						});
		request.command = this;
	},
	
	undo: function() {
		bb.SetGridUserValues( this.old_user_values );
	}
});

var ReplaceWrongValues_Command = Class.create({
	initialize: function(table_data) {
		this.is_undoable = true;
		this.old_user_values = new Array();
	},
	
	execute: function() {
		this.old_user_values = bb.SerializeGrid();
		var serialized_grid_uservalues = this.old_user_values;
		var serialized_grid_titulars = bb.SerializeGridTitulars();
		
		var request = new Ajax.Request('cgi-bin/SudokuEngineCGI.cgi?ReplaceWrongValues-'+serialized_grid_uservalues+'-'+serialized_grid_titulars, 
						{
							method:'get',
							contentType: "application/x-www-form-urlencoded", 
							onSuccess: function(transport)
							{
								var response = transport.responseText || "no response text";
					
								var uservalues_int_array = new Array();
								var i = 0; var len = 0;
								for( i = 0, len = response.length; i < len; ++i)
								{
									uservalues_int_array.push( parseInt( response.charAt(i) ) );
								}

								bb.SetGridUserValues( uservalues_int_array );
								GameBoard_ButtonClicked();
							},
							onFailure: function()
							{ 
								alert(g_ajaxrequest_failed) 
							}
						});
		request.command = this;
	},
	
	undo: function() {
		bb.SetGridUserValues( this.old_user_values );
	}
});

var SolveGrid_Command = Class.create({
	initialize: function(table_data) {
		this.old_user_values = new Array();
	},
	
	execute: function() {
		CommandProcessor.clear_undo();
		var serialized_grid_titulars = bb.SerializeGridTitulars();
		
		var request = new Ajax.Request('cgi-bin/SudokuEngineCGI.cgi?SolveGrid-'+serialized_grid_titulars, 
						{
							method:'get',
							contentType: "application/x-www-form-urlencoded",
							onSuccess: function(transport)
							{
								var response = transport.responseText || "no response text";
					
								var uservalues_int_array = new Array();
								var i = 0; var len = 0;
								for( i = 0, len = response.length; i < len; ++i)
								{
									uservalues_int_array.push( parseInt( response.charAt(i) ) );
								}

								bb.SetGridUserValues( uservalues_int_array );
								GameBoard_ButtonClicked();
							},
							onFailure: function()
							{ 
								alert(g_ajaxrequest_failed) 
							}
						});
		request.command = this;
	}
});

var InfoPuzzle_Command = Class.create({
	initialize: function(table_data) {
		
	},
	
	execute: function() {
		
		var serialized_grid = bb.SerializeGrid();
	
		var request = new Ajax.Request('cgi-bin/SudokuEngineCGI.cgi?PuzzleInfo-'+serialized_grid, 
						{
							method:'get',
							contentType: "application/x-www-form-urlencoded",
							onSuccess: function(transport)
							{
								var response = transport.responseText || "no response text";
								var info_array = response.split(',');
								var info; 
								if (info_array[0] == '0')
								{
									info = g_resource_puzzle_solveble;
									info +="\n";
								}
								else
								{
									info = g_resource_puzzle_not_solveble;
									info +="\n";
				
								}
								
								info += g_resource_rating;
								info += ": ";
								info += info_array[1];
								info +="\n";
								
								
								if(info_array[2]!=0){info += g_pattern_names["IllegalValue"]; info += ": ";info += info_array[2];info +="\n";}
								if(info_array[3]!=0){info += g_pattern_names["IllegalCandidate"]; info += ": ";info += info_array[3];info +="\n";}
								if(info_array[4]!=0){info += g_pattern_names["NakedSingle"]; info += ": ";info += info_array[4];info +="\n";}
								if(info_array[5]!=0){info += g_pattern_names["HiddenSingle"]; info += ": ";info += info_array[5];info +="\n";}
								if(info_array[6]!=0){info += g_pattern_names["BoxLineReduction"]; info += ": ";info += info_array[6];info +="\n";}
								if(info_array[7]!=0){info += g_pattern_names["PointingPair"]; info += ": ";info += info_array[7];info +="\n";}
								if(info_array[8]!=0){info += g_pattern_names["NakedPair"]; info += ": ";info += info_array[8];info +="\n";}
								if(info_array[9]!=0){info += g_pattern_names["NakedTriple"]; info += ": ";info += info_array[9];info +="\n";}
								if(info_array[10]!=0){info += g_pattern_names["NakedQuad"]; info += ": ";info += info_array[10];info +="\n";}
								if(info_array[11]!=0){info += g_pattern_names["HiddenPair"]; info += ": ";info += info_array[11];info +="\n";}
								if(info_array[12]!=0){info += g_pattern_names["HiddenTriple"]; info += ": ";info += info_array[12];info +="\n";}
								if(info_array[13]!=0){info += g_pattern_names["HiddenQuad"]; info += ": ";info += info_array[13];info +="\n";}
								if(info_array[14]!=0){info += g_pattern_names["RemotePair"]; info += ": ";info += info_array[14];info +="\n";}
								if(info_array[15]!=0){info += g_pattern_names["XWing"]; info += ": ";info += info_array[15];info +="\n";}
								if(info_array[16]!=0){info += g_pattern_names["Swordfish"]; info += ": ";info += info_array[16];info +="\n";}
								if(info_array[17]!=0){info += g_pattern_names["Jellyfish"]; info += ": ";info += info_array[17];info +="\n";}
							
								alert(info);

							},
							onFailure: function()
							{ 
								alert(g_ajaxrequest_failed) 
							}
						});
		request.command = this;
	}
});


var RestartPuzzle_Command = Class.create({
	initialize: function(table_data) {
		this.is_undoable = false;
	},
	
	execute: function() {
		var serialized_grid_titulars = bb.SerializeGridTitulars();
		var uservalues_int_array = new Array();
		var i = 0; var len = 0;
		for(i = 0, len = serialized_grid_titulars.length; i < len; ++i)
		{
			uservalues_int_array.push( parseInt(serialized_grid_titulars.charAt(i)) );
		}
		bb.SetGridUserValues( uservalues_int_array );
		var cmd = new ClearAllCandidates_Command();
		CommandProcessor.execute( cmd );
		var cmd = new FillValidCandidates_Command();
		CommandProcessor.execute( cmd );
		CommandProcessor.clear_undo();
		GameBoard_ButtonClicked();
	}
});


var GetHint_Command = Class.create({
	initialize: function(table_data) {
		this.is_undoable = false;
	},
	
	execute: function() {
		this.old_user_values = bb.SerializeGrid();
		var serialized_grid_uservalues = bb.SerializeGrid();
		var serialized_grid_candidates = bb.SerializeCandidates().toJSON().replace(/,/gi ,"");
		serialized_grid_candidates = serialized_grid_candidates.substr(1, serialized_grid_candidates.length - 2);
		
		var request = new Ajax.Request('cgi-bin/SudokuEngineCGI.cgi?GetHint-'+serialized_grid_uservalues+'-'+serialized_grid_candidates, 
						{
							method:'get',
							contentType: "application/x-www-form-urlencoded",
							onSuccess: function(transport)
							{
								var response = transport.responseText || "no response text";
								var data = response.evalJSON();
								if (bb.currentHintData)
								{
									bb.ClearHint(bb.currentHintData);
								}
								bb.HighlightHint(data);
								$('HintContent').update(g_pattern_names[data['PatternName']]);
								ShowHintTooltip(true);
							},
							onFailure: function()
							{ 
								alert(g_ajaxrequest_failed) 
							}
						});
		request.command = this;
	}
});

var SaveToFile_Command = Class.create({
	initialize: function(table_data) {
		this.is_undoable = false;
	},
	
	execute: function(commandId) {
		var serialized_grid_uservalues = bb.SerializeGrid();
		document.location = 'SudokuTime_Domain.php?savetofile=' + serialized_grid_uservalues;
	}
});
