function broadcast() {
	// Ajax request object, used to fetch broadcast lists and/or pgn files (broadcasts)
	this.ajaxRequest = new ajaxRequest();

	// Load PGN parser
	this.parser = new parser();
	
	// Stores parsed/unparsed games
	this.games = [];

	// Handles the logics of chess board
	this.board = new chessBoard();
	
	// Handles the display and layout
	this.gui = new broadcastGUI();

	// Fetches the broadcasts list to get path to pgn file
	this.loadBroadcast =
	function(path, game, noupdate) {
		this.path = path;
		this.selectedGame = game;
		if (noupdate != "true") {
			setTimeout("broadcast.updater();", 20000);
			this.noupdate = false;
		} else {
			this.noupdate = true;
		}

		this.ajaxRequest.send(this.path);
	}

	this.jump = true;
	
	this.switchjump =
	function() {
		if (this.jump) {
			this.jump = false;
		} else {
			this.jump = true;
		}
	}
	
	
	this.changeLanguage =
	function(index) {
		this.gui.displayLang = document.getElementById("langselect").options[index].value;
		setCookie("displayLang", this.gui.displayLang, 365)
		this.ajaxRequest.send(this.path);
	}



	this.respondLoadPGNfile =
	function(PGN) {
		this.parser.parsePGN(PGN);
		this.loadGame(this.selectedGame);
	}

	this.loadGame =
	function(gameNum) {
		var game = this.games[gameNum];

		if (game.lastStamp == -1) {
			this.parser.parseNotation(this.board, game);
		}

		this.board.loadFEN(game.currPosition);
		

		if (game.lastStamp != -1 && game.tags["Stamp"] && game.lastStamp < game.tags["Stamp"]) {
			this.parser.parseNotation(this.board, game);
			this.board.loadFEN(game.currPosition);
			this.gui.drawGameHeader(game, this.board);
			this.gui.drawNotation(game);
			this.gui.drawBoardPosition(game, this.board);
			if (this.jump && this.selectedGame == gameNum) {
				this.loadMove('end');
			}
		} else if (this.selectedGame != gameNum || game.lastStamp == -1) {
			game.lastStamp = 0;
			this.gui.drawGameHeader(game, this.board);
			this.gui.drawNotation(game);
			this.gui.drawBoardPosition(game, this.board);
		}
		if (game.tags["Stamp"]) {
			game.lastStamp = game.tags["Stamp"];
		}
		this.selectedGame = gameNum;
		this.gui.drawGamesList(this.games, this.selectedGame);
		this.gui.drawGameLink(this.path, this.selectedGame);
	}
	
	this.loadMove =
	function(id) {
		var game = this.games[this.selectedGame];
		if (id == "end") {
			id = game.lastMove;
		}
		var fen = game.FENs[game.displayNotation[id]["fenlink"].variation][game.displayNotation[id]["fenlink"].number];
		this.board.loadFEN(fen);
		game.currPosition = fen; 
		var oldid = game.notationMove;
		game.notationMove = id;
		this.gui.displayMove(game, this.board, oldid);
	}

	// Reloads broadcast file every 10 seconds
	this.updater =
	function() {
		this.ajaxRequest.send(this.path);
		setTimeout("broadcast.updater();", 20000);
	}
	
	this.keyHandler=
	function(e) {
		var keynum;
		if(!e) // IE
			e = window.event;
		keynum = e['keyCode'];
		if (keynum == 37)
			broadcast.previousMove();
		else if (keynum == 39) {
			broadcast.nextMove();
			alert(keynum);
			}
	}

	this.nextMove =
	function() {
		var game = this.games[this.selectedGame];
		var level = 0;
		if (game.notationMove == "start") {
			var id = -1;
		} else {
			id = game.notationMove;
		}
		for (var i = id + 1; i < game.displayNotation.length; i++) {
			var token = game.displayNotation[i];
			
			if (token["type"] == "regular") {
				if (level == 0) {
					this.loadMove(i);
					break;
				}
			} else if (token["type"] == "variation_start") {
				level++;
			} else if (token["type"] == "variation_end") {
				if (level == 0) {
					break;
				} else {
					level--;
				}
			}
		}
	}

	this.previousMove =
	function() {
		var game = this.games[this.selectedGame];
		var level = 0;
		var id = game.notationMove;
		if (id == "start") {
			return;
		} else if(id == 0) {
			this.loadMove("start");
			return;
		} 
		for (var i = id - 1; i >= 0; i--) {
			var token = game.displayNotation[i];
			if (token["type"] == "regular") {
				if (level == 0) {
					this.loadMove(i);
					break;
				}
			} else if (token["type"] == "variation_start") {
				if (level == 0) {
					break;
				} else {
					level--;
				}
			} else if (token["type"] == "variation_end") {
				level++;
			}
			if (i==0) {
				this.loadMove("start");
				break;
			}
		}
	}
	
	this.savePGN = 
	function() {
		location = "getpgn.php?action=save&saveid=" + this.path;
	}
	
	this.ostats = function() {
		window.open("http://chessok.com/?page_id=352&fen=" + encodeURIComponent(this.board.currentFEN()));
	}

	this.endstats = function() {
		window.open("http://chessok.com/?page_id=361&fen=" + encodeURIComponent(this.board.currentFEN()));
	}
	
	this.blockNotation =
	function() {
		this.block = true;
	}
	this.allowNotation =
	function() {
		this.block = false;
	}
}

// Chess Game object, merely holds what we extracted from PGN file

function chessGame() {
	// Raw notation with a bunch of tokens (comments, NAGs, recursive variations)
	this.notation;

	// Storage of recursive variations notations
	this.variations = [];
	this.variations[0] = "";

	// Game tags (from PGN game header)
	this.tags = [];

	// After we parse the notation, the whole game is stored in FENs for every consecutive move.
	// This way its so much easier to handle move jumps
	// FENs[0][...] - main line
	// FENs[1][...] - variation #1 etc
	this.FENs = [];
	// There is always a main line
	this.FENs[0] = [];

	// To see if game was updated since last visit
	this.lastStamp = -1;

	// The position we are at (FEN)
	this.currPosition = "";
	
	// At default
	this.notationMove = "start";

	// Last move
	this.lastMove;

	// Used for display
	this.displayNotation = [];
}

	// Keyboard handler to browse notation with arrows
	
	function keyHandler(e) {
		var keynum;
		if(!e) // IE
			e = window.event;
		keynum = e['keyCode'];
		if (keynum == 37 && !broadcast.block)
			broadcast.previousMove();
		else if (keynum == 39 && !broadcast.block)
			broadcast.nextMove();
	}
	document.onkeydown = keyHandler;
	


function getCookie(c_name) {
	if (document.cookie.length > 0) {
		c_start = document.cookie.indexOf(c_name + "=")
		if (c_start != -1) {
			c_start = c_start + c_name.length + 1 
			c_end = document.cookie.indexOf(";", c_start)
			if (c_end==-1)
				c_end=document.cookie.length;
			return unescape(document.cookie.substring(c_start, c_end));
		}
	}
	return "";
}

function setCookie(c_name, value, expiredays) {
	var exdate = new Date()
	exdate.setDate(exdate.getDate() + expiredays)
	document.cookie = c_name + "=" + escape(value) + ((expiredays==null) ? "" : ";expires=" + exdate.toGMTString());
} 