function SpiidokuAdv(grid, area_h, area_w, n_v_area, n_h_area) {
	// An array with all the cells [line][column]
	var cells;

	function makeDOM() {
		// Creates the table
		var table = $('<table class="spiidoku_adv_table"></table>');
		var tbody = $('<tbody></tbody>');
		table.append(tbody);

		// Creates the cells
		cells = new Array();
		for(var i=0; i < (area_h * n_v_area); i++) {
			cells[i] = new Array();
			var tr = $('<tr></tr>');
			for(var j=0; j < (area_w * n_h_area); j++) {
				cells[i][j] = $('<td class="spiidoku_adv_cell_pre">&nbsp;</td>');
				tr.append(cells[i][j]);

				// Getting the position
				if(i % area_h == 0 && j % area_w == 0) { // top left
					cells[i][j].addClass('spiidoku_adv_cell_top_left');
				} else if((i + 1) % area_h == 0 && j % area_w == 0) { // bottom left
					cells[i][j].addClass('spiidoku_adv_cell_bottom_left');
				} else if((i + 1) % area_h == 0 && (j + 1) % area_w == 0) { //bottom right
					cells[i][j].addClass('spiidoku_adv_cell_bottom_right');
				} else if(i % area_h == 0 && (j + 1) % area_w == 0) { // top right
					cells[i][j].addClass('spiidoku_adv_cell_top_right');
				} else if(i % area_h == 0) { // top
					cells[i][j].addClass('spiidoku_adv_cell_top');
				} else if((i + 1) % area_h == 0) { // bottom
					cells[i][j].addClass('spiidoku_adv_cell_bottom');
				}

				// Getting the position (bis)
				if(i != 0 && i % area_h == 0) {
					cells[i][j].addClass('spiidoku_adv_cell_hspace');
				}
				if(j != 0 && j % area_w == 0) {
					cells[i][j].addClass('spiidoku_adv_cell_vspace');
				}

				// Make some cells darker
				if((Math.floor(i / area_h) % 2) != (Math.floor(j / area_w) % 2)) {
					cells[i][j].addClass('darker');
				}

				cells[i][j].setColor = function(color) {
					c = $(this);
					c.removeClass('spiidoku_adv_cell_pre');
					c.removeClass('spiidoku_adv_cell_good');
					c.removeClass('spiidoku_adv_cell_bad');
					c.addClass('spiidoku_adv_cell_'+color);
				};
			}
			tbody.append(tr);
		}

		RoundCorners();

		return table;
	}

	this.fill = function(values) {
		if(values.length != (area_h * area_w * n_v_area * n_h_area)) {
			throw "values length not good";
		}

		for(var i=0; i < values.length; i++) {
			var l = Math.floor(i/(area_w * n_h_area));
			var c = i % (area_w * n_h_area);

			var value = values.substring(i, i+1);

			if(value == "+") {
				cells[l][c].setColor('good');
				cells[l][c].html('&nbsp;');
			} else if(value == "-") {
				cells[l][c].setColor('bad');
				cells[l][c].html('&nbsp;');
			} else {
				cells[l][c].setColor('pre');
				cells[l][c].html(value);
			}
		}
	}

	var dom = makeDOM();
	grid.append(dom);
}

/**
 * Creates a spiidoku object
 *
 * @param grid      table   that is the root of the widget
 * @param area_h    int     height of an area
 * @param area_w    int     width of an area
 * @param n_v_area  int     number of vertical area
 * @param n_h_area  int     number of horizontal area
 */
function Spiidoku(grid, area_h, area_w, n_v_area, n_h_area) {
	// An array with all the cells [line][column]
	var cells;
	var changeNotify = [];

	var makeDOM = function() {
		var i, j;

		// Making the cells
		cells = new Array();
		for(i=0; i < area_h * n_v_area; i++) {
			cells[i] = new Array();
			for(j=0; j < area_w * n_h_area; j++) {
				cells[i][j] = $('<input maxlength="1" class="spiidoku_input" disabled="disabled" />');
				cells[i][j][0].coords = [i, j];

				cells[i][j].keyup(function(evt) {
					if(evt.which != 0) {
						evt.preventDefault();
					}

					if(evt.which >= 49 && evt.which <= (48 + (area_h * area_w))) { // if it is a number
						$(this).val(evt.which - 48);
						// Trigger change event
						triggerChange();
					} else if(evt.keyCode >= 37 && evt.keyCode <= 40) { // if it is an arrow
						function findNearest(p, p_min, p_max, dir) {
							var find = Array();
							var i,j,nearest = {dist: 1000, pos: undefined};

							// Look to the direction
							i = p.l + dir.l;
							j = p.c + dir.c;
							while(i <= p_max.l && j <= p_max.c && i >= p_min.l && j >= p_min.c) {
								if(!cells[i][j].attr('disabled')) {
									return {l: i, c: j};
								}

								i += dir.l;
								j += dir.c;
							}

							// If nothing in the direction, find the nearest
							for(i = p_min.l; i <= p_max.l; i++) {
								for(j = p_min.c; j <= p_max.c; j++) {
									if(!cells[i][j].attr('disabled')) {
										var dist = Math.sqrt(Math.pow(p.l - i, 2) + Math.pow(p.c - j, 2));
										if(dist < nearest.dist) {
											nearest.dist = dist;
											nearest.pos = {
												l: i,
												c: j
											}
										}
									}
								}
							}

							return nearest.pos;
						}

						var near;
						if(evt.keyCode == 37) {
							near = findNearest(
								{l: this.coords[0], c: this.coords[1]},
								{l: 0, c: 0},
								{l: (area_h * n_v_area) - 1, c: this.coords[1] - 1},
								{l: 0, c: -1}
							);
						} else if(evt.keyCode == 38) {
							near = findNearest(
								{l: this.coords[0], c: this.coords[1]},
								{l: 0, c: 0},
								{l: this.coords[0] - 1, c: (area_w * n_h_area) - 1},
								{l: -1, c: 0}
							);
						} else if(evt.keyCode == 39) {
							near = findNearest(
								{l: this.coords[0], c: this.coords[1]},
								{l: 0, c: this.coords[1] + 1},
								{l: (area_h * n_v_area) - 1, c: (area_w * n_h_area) - 1},
								{l: 0, c: 1}
							);
						} else if(evt.keyCode == 40) {
							near = findNearest(
								{l: this.coords[0], c: this.coords[1]},
								{l: this.coords[0] + 1, c: 0},
								{l: (area_h * n_v_area) - 1, c: (area_w * n_h_area) - 1},
								{l: 1, c: 0}
							);
						}

						if(near != undefined) {
							cells[near.l][near.c].focus();
						}
					}
				});
				cells[i][j].keypress(function(evt) {
					if(evt.which != 0) {
						evt.preventDefault();
					}

					if(evt.which >= 49 && evt.which <= (48 + (area_h * area_w))) { // if it is a number
						$(this).val(evt.which - 48);
						// Trigger change event
						triggerChange();
					}
				});
			}
		}

		var table = $('<table class="spiidoku_table"></table>');
		var tbody = $('<tbody></tbody>');
		table.append(tbody);

		for(i=0; i < area_h * n_v_area; i++) {
			var tr = $('<tr class="spiidoku_line"></tr>');
			for(j=0; j < area_w * n_h_area; j++) {
				var td = $('<td class="spiidoku_cell"></td>');
				td.append(cells[i][j]);
				cells[i][j].td = td;

				// Getting the position
				if(i % area_h == 0 && j % area_w == 0) { // top left
					td.addClass('spiidoku_cell_top_left');
				} else if((i + 1) % area_h == 0 && j % area_w == 0) { // bottom left
					td.addClass('spiidoku_cell_bottom_left');
				} else if((i + 1) % area_h == 0 && (j + 1) % area_w == 0) { //bottom right
					td.addClass('spiidoku_cell_bottom_right');
				} else if(i % area_h == 0 && (j + 1) % area_w == 0) { // top right
					td.addClass('spiidoku_cell_top_right');
				} else if(i % area_h == 0) { // top
					td.addClass('spiidoku_cell_top');
				} else if((i + 1) % area_h == 0) { // bottom
					td.addClass('spiidoku_cell_bottom');
				}

				if((Math.floor(i / area_h) % 2) == (Math.floor(j / area_w) % 2)) {
					td.addClass('darker');
				}

				tr.append(td);
			}
			tbody.append(tr);
		}

		RoundCorners();

		return table;
	}

	this.fill = function(values) {
		var i;

		if(values.length != (area_h * area_w * n_v_area * n_h_area)) {
			throw "values length not good";
		}

		for(i=0; i < values.length; i++) {
			var l = Math.floor(i/(area_w * n_h_area));
			var c = i % (area_w * n_h_area);

			var value = values.substring(i, i+1);

			if(value == ' ' || value == '*') {
				cells[l][c].removeAttr('disabled');
				cells[l][c].val('');
				cells[l][c].addClass('spiidoku_cell_user');
			} else {
				cells[l][c].attr('disabled', 'disabled');
				cells[l][c].val(value);
				cells[l][c].removeClass('spiidoku_cell_user');
				cells[l][c].td.empty();

				cells[l][c].td.append($('<div class="'+cells[l][c].attr('class')+'">'+value+'</div>'));
			}
		}
	}

	/**
	 * Checks the grid, and returns true if the game is finised
	 *
	 * TODO: color the grid to display the good lines/areas to the user
	 */
	this.check = function() {
		var i, j, k, l, data;

		// Checking an array
		function linear_check(data) {
			var i, j;
			for(i = 1; i <= (area_h * area_w); i++) {
				var count = 0;
				for(j=0; j < (area_h * area_w); j++) {
					if(parseInt(data[j]) == i) {
						count++;
					}
				}
				if(count != 1) {
					return false;
				}
			}
			return true;
		}

		// Checking lines
		for(i = 0; i < (area_h * area_w); i++) {
			data = new Array();
			for(j = 0; j < (area_h * area_w); j++) {
				data[j] = cells[i][j].val();
			}
			if(!linear_check(data)) return false;
		}

		// Checking columns
		for(j = 0; j < (area_h * area_w); j++) {
			data = new Array();
			for(i = 0; i < (area_h * area_w); i++) {
				data[i] = cells[i][j].val();
			}
			if(!linear_check(data)) return false;
		}

		// Checking areas
		for(i = 0; i < n_v_area; i++) {
			for(j = 0; j < n_h_area; j++) {
				data = new Array();
				var c = 0;
				for(k = i * area_h; k < (i + 1) * area_h; k++) {
					for(l = j * area_w; l < (j + 1) * area_w; l++) {
						data[c++] = cells[k][l].val();
					}
				}
				if(!linear_check(data)) return false;
			}
		}

		return true;
	}

	this.serialize = function() {
		var out = "";

		for(var i=0; i < (area_h * n_v_area); i++) {
			for(var j=0; j < (area_w * n_h_area); j++) {
				if(cells[i][j].attr('disabled') || cells[i][j].val() == "") {
					out += "*";
				} else {
					out += cells[i][j].val();
				}
			}
		}

		return out;
	}

	/**
	 * Adds a callback to call when the grid changes
	 */
	this.change = function(callback) {
		changeNotify.push(callback);
	}

	/**
	 * Triggers the change event
	 */
	function triggerChange() {
		var i;
		for(i in changeNotify) {
			changeNotify[i]();
		}
	}

	/**
	 * Makes the grid ineditable
	 */
	this.freeze = function() {
		for(var i=0; i < (area_h * n_v_area); i++) {
			for(var j=0; j < (area_w * n_h_area); j++) {
				cells[i][j].attr('disabled', 'disabled');
			}
		}
	}

	var dom = makeDOM();
	grid.append(dom);
}

function SpiidokuClock(div) {
	var obj = this;
	var t_start = 0, t_stop = 0;
	var timer;

	this.durationToString = function() {
		var duration = parseInt(obj.getElapsedTime() / 1000);

		var min = parseInt(duration / 60);
		var sec = duration % 60;

		if(min < 10) min = '0'+min;
		if(sec < 10) sec = '0'+sec;

		return min + ':' + sec;
	}

	function draw() {
		div.html('<p class="spiidoku_clock">'+obj.durationToString()+'</p>');
	}

	this.start = function() {
		var d = new Date();
		t_start = d.getTime();

		timer = setInterval(draw, 333);
	}

	this.stop = function() {
		var d = new Date();
		t_stop = d.getTime();

		clearInterval(timer);
	}

	this.reset = function() {
		t_start = 0;
		t_stop = 0;
	}

	this.getElapsedTime = function() {
		var d = new Date();
		var t_now = d.getTime();

		if(t_stop != 0) {
			t_now = t_stop;
		}

		return t_now - t_start;
	}
}

function RoundCorners() {
	// TODO: make this work
	/*if(typeof(DD_roundies) != "undefined") {
		DD_roundies.addRule('#spiidoku', '10px');
		DD_roundies.addRule('#spiidoku_modal', '10px');
		DD_roundies.addRule('.spiidoku_cell_top_left', '10px');
		DD_roundies.addRule('.spiidoku_cell_top_right', '10px');
		DD_roundies.addRule('.spiidoku_cell_bottom_right', '10px');
		DD_roundies.addRule('.spiidoku_cell_bottom_left', '10px');
	}*/
}

function SpiidokuControler() {
	var obj = this;
	var root = $('#spiidoku');

	var modal_div = $('<div id="spiidoku_modal"></div>');
	var modal = new SpiidokuModal(modal_div);

	var fb = $('<a name="fb_share" type="button_count" share_url="http://www.lesudokugratuit.com/fr/page/Spiidoku/spiidoku" href="http://www.facebook.com/sharer.php">Partager</a><script src="http://static.ak.fbcdn.net/connect.php/js/FB.Share" type="text/javascript"></script>');

	this.modeSelect = function(hash) {
		//this.duel();return;
		if(hash == "duel") {
			this.duel();
		} else if(hash == "solo") {
			this.solo();
		} else {
			bar = $('<div class="spiidoku_info_bar"></div>');
			bar.append($('<div class="spiidoku_logo"><img src="/images/spiidoku/logo.png" alt="spiidoku" /></div>'));
			root.append(bar);
			modal.ask('En quel mode souhaitez vous jouer ?', {
				'Solo': function() {
					obj.solo();
				},
				'Duel': function() {
					obj.duel();
				}
			}, fb);
		}
	}

	this.duel = function() {
		// The keepalive
		var keepalive;
		// Is the title epileptic ?
		var waiting = false;
		var noconfirm = false;

		obj.init();

		// Creating the bar
		bar = $('<div class="spiidoku_info_bar"></div>');
		bar.append($('<div class="spiidoku_logo"><img src="/images/spiidoku/logo_duel.gif" alt="spiidoku mode duel" /></div>'));

		// Adding the clock to the bar
		var clock_div = $('<div class="spiidoku_clock_block">00:00</div>');
		var clock = new SpiidokuClock(clock_div);
		bar.append(clock_div);

		// Adding the link to stop
		var link = $('<a href="#" class="spiidoku_cancel" onclick="return false;"><img src="/images/spiidoku/close.gif" alt="fermer" /></a>');
		link.click(function() {
			if(noconfirm) {
				kill();
				$.post('/spiidoku/update', {'giveup':true});
			} else {
				modal.ask('Voulez vous vraiment déclarer forfait ?', {
					'Oui': function() {
						kill();
						$.post('/spiidoku/update', {'giveup':true});
					},
					'Non': function() {
					}
				});
			}
		});
		bar.append(link);

		// Adding the bar to the page
		root.append(bar);

		// Creating a div for the grid
		var grid_div = $('<div class="spiidoku_grid_container_duel_self"></div>');
		grid_div.append($('<div class="spiidoku_nick spiidoku_nick_left">Vous</div>'));
		var grid = new Spiidoku(grid_div, 2, 3, 3, 2);
		grid.change(function() {
			waiting = false;
			$.post('/spiidoku/update', {'grid':grid.serialize()}, function(data, txt, xhr) {
				if(data == "valid") {
					kill('Félicitations ! Vous avez remporté le duel');
				} else if(data == "valid-sub") {
					if(document.fb_mode != true) {
						kill('Félicitations ! Vous avez remporté le duel. <a tagrget="_blank" href="/fr/utilisateur/new">Inscrivez vous</a> pour conserver vos victoires !', true);
					} else {
						kill('Félicitations ! Vous avez remporté le duel.', true);
					}
				}
			});
		});

		// Creating a div for the adv grid
		var adv_grid_div = $('<div class="spiidoku_grid_container_duel_adv"></div>');
		var adv_nick = $('<div class="spiidoku_nick spiidoku_nick_right">Votre adversaire</div>');
		adv_grid_div.append(adv_nick);
		var adv_grid = new SpiidokuAdv(adv_grid_div, 2, 3, 3, 2);

		// Adding the grids to the root
		var cnt = $('<div class="spiidoku_duel_container"></div>');
		cnt.append(grid_div);
		cnt.append(adv_grid_div);
		root.append(cnt);

		// A function to kill everything
		function kill(msg, sub) {
			clock.stop();
			grid.freeze();
			ipc.close();
			clearInterval(keepalive);
			waiting = false;

			if(msg != undefined) {
				if(sub && document.fb_mode != true) {
					modal.ask(msg, {
						"Ok": function() {
							obj.stop();
						},
						"Inscrivez vous": function() {
							window.open('/fr/utilisateur/new', 'Le Sudoku Gratuit');
						}
					});
				} else if(sub) {
					try {
						modal.subscribe(msg, function() {
							obj.stop()
						});
					} catch(err) {
					}
				} else {
					modal.say(msg, function() {
						obj.stop();
					});
				}
			}
			else obj.stop();
		};

		// A function to make the title of the page change
		this.epilepticTitle = function(step, original) {
			if(waiting) {
				var steps = ['»---', '-»--', '--»-', '---»'];
				document.title = '['+steps[step % steps.length]+'] Spiidoku - Le duel commence !';
				setTimeout(function() {
					obj.epilepticTitle(step+1, original);
				}, 333);
			} else {
				document.title = original;
			}
		};

		// ---
		// Communication part... Let's begin the fun
		// ---

		var group_info;
		$.ajax({
			async: false,
			cache: false,
			dataType: "json",
			error: function(xhr, txt, err) {
				modal.say('Une erreur est survenue. Vous pouvez tenter de recharger la page.');
			},
			success: function(data, txt, xhr) {
				group_info = data;
			},
			url: '/spiidoku/get_group'
		});

		// Register the event to wait for actions from the other player
		ipc.listenTo("spiidoku-update-"+group_info.uid+"-"+group_info.gid, function(data) {
			sdata = jQuery.parseJSON(data);

			if(sdata.other_gaveup != undefined) {
				kill('Vous avez gagné par forfait !');
				return;
			}

			adv_grid.fill(sdata.other);

			if(sdata.other_won != undefined) {
				if(sdata.sub != undefined) {
					kill('Vous avez perdu ! Mais vous pouvez rententer votre chance dans un nouveau duel ! <a target="_blank" href="/fr/utilisateur/new">Inscrivez vous</a> pour conserver vos victoires !', true);
				} else {
					kill('Vous avez perdu ! Mais vous pouvez rententer votre chance dans un nouveau duel !');
				}
			}
		});

		// If we need to wait for the other player
		if(group_info.statut == 'Commence') {
			// First, let's make the user wait
			modal.say('En attente d\'un joueur...<br /><br /><img src="/images/spiidoku/waiting.gif" alt="" />', undefined, fb);
			noconfirm = true;

			ipc.listenTo("spiidoku-ready-"+group_info.uid+"-"+group_info.gid, function(data) {
				waiting = true;
				noconfirm = false;
				obj.epilepticTitle(0, document.title);

				sdata = jQuery.parseJSON(data);

				grid.fill(sdata.grid);
				adv_grid.fill(sdata.other);
				var plur = (parseInt(sdata.other_vict) > 1) ? 's' : '';
				adv_nick.html(sdata.other_nick + ' <div>' + sdata.other_vict + ' victoire'+plur+'/7 jours</div>');

				modal.close();
				clock.start();
			});
		} else {
			grid.fill(group_info.grid);
			adv_grid.fill(group_info.other);
			var plur = (parseInt(group_info.other_vict) > 1) ? 's' : '';
			adv_nick.html(group_info.other_nick + ' <div>' + group_info.other_vict + ' victoire'+plur+'/7 jours</div>');
			clock.start();
			// TODO : fill with the already present values for current user (in case of browser reload)
		}

		keepalive = setInterval(function(){
			$.post('/spiidoku/update', {keepalive: true});
		}, 60000);

		// Starting the poll !
		ipc.longPoll();
	}

	this.solo = function() {
		var bar, grid;
		var num;

		obj.init();

		// Creating the bar
		bar = $('<div class="spiidoku_info_bar"></div>');
		bar.append($('<div class="spiidoku_logo"><img src="/images/spiidoku/logo_solo.gif" alt="spiidoku mode solo" /></div>'));

		// Adding the clock to the bar
		var clock_div = $('<div class="spiidoku_clock_block">00:00</div>');
		var clock = new SpiidokuClock(clock_div);
		bar.append(clock_div);

		// Adding the link to stop
		var link = $('<a href="#" class="spiidoku_cancel" onclick="return false;"><img src="/images/spiidoku/close.gif" alt="fermer" /></a>');
		link.click(function() {
			obj.abort();
			return false;
		});
		bar.append(link);

		// Adding the bar to the page
		root.append(bar);

		// Getting the numbers of the grid
		$.ajax({
			async: false,
			cache: false,
			dataType: "text",
			error: function(xhr, txt, err) {
				modal.say('Une erreur est survenue. Vous pouvez tenter de recharger la page.');
			},
			success: function(data, txt, xhr) {
				num = data;
			},
			url: '/spiidoku/randgrid'
		});

		// Creating a div for the grid
		var grid_div = $('<div class="spiidoku_grid_container_solo"></div>');
		var grid = new Spiidoku(grid_div, 2, 3, 3, 2);
		grid.fill(num);

		// When the grid changes, you check it and finish the game when it is complete
		grid.change(function(){
			if(grid.check()) {
				clock.stop();
				modal.say('Félicitations ! Vous avez complété le Spiidoku en ' + clock.durationToString() + ' !', function(){
					obj.init();
					window.setTimeout(obj.modeSelect, 500);
				});
			}
		});

		root.append(grid_div);

		// Starting the clock
		clock.start();
	}

	this.abort = function() {
		modal.ask('Voulez vous vraiment arrêter cette partie ?', {
			'Oui': function() {
				obj.stop();
			},
			'Non': function() {
			}
		});
	}

	this.stop = function() {
		obj.init();
		window.setTimeout(obj.modeSelect, 500);
	}

	this.init = function() {
		root.empty();
		root.append($('<div id="spiidoku_modal_container"></div>').append(modal_div));
		root.show();
	}
}

/**
 * When document is ready :)
 */
$(document).ready(function() {
	// Create the SpiidokuIPC object
	ipc = new SpiidokuIPC();

	control = new SpiidokuControler();
	control.init();

	var hash = window.location.hash.substring(1);
	control.modeSelect(hash);
});

/**
 * Spiidoku modal infos
 */
function SpiidokuModal(div) {
	var box = div;
	var obj = this;

	/**
	 * Display an info message with an "OK" button. When the user clicks, the
	 * function onOk() is called
	 */
	this.say = function(msg, onOk, bonus) {
		box.empty();

		// Generate the text element
		var txt = $('<p></p>');
		txt.html(msg);
		box.append(txt);

		// Generate the button
		if(onOk != undefined) {
			var but = $('<a href="#">OK</a>');
			but.click(function() {
				box.fadeOut(100);
				onOk();
				return false;
			});
			box.append(but);
		}

		if(bonus != undefined) {
			box.append($('<div class="spiidoku-fb-button"></div>').append(bonus));
		}

		// Display
		box.fadeIn(100);
	};

	/**
	 * Asks the user to choose something
	 */
	this.ask = function(msg, ans, bonus) {
		box.empty();

		// Generate the question
		var txt = $('<p></p>');
		txt.html(msg);
		box.append(txt);

		// Generate the buttons
		for(a in ans) {
			var but = $('<a href="#">'+a+'</a>');
			but.click(function() {
				box.fadeOut(100);
				ans[this.innerHTML]();
				return false;
			});
			box.append(but);
		}

		if(bonus != undefined) {
			box.append($('<div class="spiidoku-fb-button"></div>').append(bonus));
		}

		// Display
		box.fadeIn(100);
	};

	this.subscribe = function(msg, callback) {
		box.empty();

		var text = $('<p></p>');
		text.html(msg);
		box.append(text);

		function submit() {
			$.post('/juser/create', $('#spiidoku_sub_form').serialize(),  function(data) {
				if(data == '"success"') {
					obj.ask('Félicitations, vous êtes maintenant inscrit !', {
						'Ok': function() {
							callback();
						},
					});
				} else {
					$('#spiidoku_sub_error').html('Les données sont incorrectes');
				}
			});
		}

		var form = $('<form id="spiidoku_sub_form" action="/juser/create" method="post">\n' +
			'<strong>Inscrivez vous maintenant</strong>\n' +
			'<p id="spiidoku_sub_error"></p>\n' +
			'<table id="spiidoku_sub_table">\n' +
				'<tr><th>Pseudo</th><td><input type="text" name="data[pseudo]" /></td></tr>\n' +
				'<tr><th>Email</th><td><input type="text" name="data[email]" /></td></tr>\n' +
				'<tr><th>Mot de passe</th><td><input type="password" name="data[password]" /></td></tr>\n' +
				'<tr><th>Mot de passe</th><td><input type="password" name="data[rpassword]" /></td></tr>\n' +
			'</table>\n' +
			'<input type="hidden" name="data[genre]" value="' + ((document.info[0].sex == "male") ? '1' : ((document.info[0].relationship_status != "married") ? '2' : '3')) + '" />\n' +
			'<input type="hidden" name="data[nom]" value="' + document.info[0].last_name + '" />\n' +
			'<input type="hidden" name="data[prenom]" value="' + document.info[0].first_name.replace('"', '\\"') + '" />\n' +
		'</form>');
		box.append(form);

		var but = $('<a href="#">Non merci</a>').click(function(evt) {
			box.fadeOut(100);
			callback();
			evt.preventDefault();
		});
		box.append(but);

		but = $('<a href="#">S\'inscrire</a>').click(function(evt) {
			submit();
			evt.preventDefault();
		});
		box.append(but);

		form.submit(function(evt) {
			submit();
			evt.preventDefault();
		});

		box.fadeIn(100);
	};

	this.close = function() {
		box.fadeOut(100);
		box.empty();
	}
}


