dojo.provide("acf.games.CheckerBoard");
dojo.require("acf.games.Board");
dojo.require("dojo.io.script");
dojo.require("dojo.io.iframe");
dojo.require("dojox.io.windowName");
dojo.declare("acf.games.CheckerBoard",[acf.games.Board], {
constructor: function() {
this.position = this.emptyPosition;
this.move = 'b';
}
// Server files
,gameSearchFile: 'https://usacheckers.com/games/search.php'
,positionSearchFile: 'https://usacheckers.com/games/findPosition.php'
,gameSearchFile: 'https://usacheckers.com/games/findGame.php'
,loadFile: 'https://usacheckers.com/games/load.php'
,parseFile: 'https://usacheckers.com/games/parseGame.php'
,uploadFile: 'https://usacheckers.com/games/upload.php'
// Playable squares (l - light, d - dark, b - both, n - neither)
,playableSquares: 'd'
// What mode to draw (setup,game,image,etc)
,mode: 'SETUP'
// What action to do (static,parse,load,etc)
,action: 'STATIC'
// Should we hide everything?
,hideAll: false
// Should we hide all menus?
,hideMenus: false
// Should we hide PDN? (image)
,hidePDN: false
// Should we hide Moves? (image)
,hideMoves: false
// PDN (portable draughts notation) string for the game
,pdnText: ''
// PDN (portable draughts notation) string for a position
,fen: ''
// String position, each playable square is a character
// w - white man, W - white king, b - black man, B - black king, . - empty
,position: ''
// Array of all positions
,positionList: null
// Position number to start a game at
,startPosition: 0
// Whose move it is (w or b)
,move: ''
// Default starting position for 8x8 checkers
,defaultPosition: 'bbbbbbbbbbbb........wwwwwwwwwwww'
// Empty 8x8 board
,emptyPosition: '................................'
// ACF game_id in DB
,gameId: -1
// Should the toolbar be hidden?
,hiddenToolbar: false
// Image for White man
,wmImg: dojo.moduleUrl("acf","resources/images/wm.gif")
// Image for Red man
,bmImg: dojo.moduleUrl("acf","resources/images/bm.gif")
// Image for White king
,wkImg: dojo.moduleUrl("acf","resources/images/wk.gif")
// Image for Red king
,bkImg: dojo.moduleUrl("acf","resources/images/bk.gif")
// Image for Deleting pieces
,delImg: dojo.moduleUrl("acf","resources/images/trash_can.png")
,drawPosition: function() {
var p = this.position;
for(var i = 0; i < p.length; i++) {
var s = 'square_'+(i+1);
dojo.attr(this[s],'value',p[i]);
// Empty all squares before re-adding pieces
if(this[s].hasChildNodes()) {
dojo.empty(this[s]);
}
// p[i] doesn't work in i.e.
var c = p.charAt(i);
switch(c) {
case 'b':
dojo.query(dojo.create('img',{src: this.bmImg, title: 'Red Piece on '+(i+1)})).place(this[s]);
// Sync the DnD
if(this.dndEnabled) {
this[s].dnd.sync();
}
break;
case 'B':
dojo.query(dojo.create('img',{src: this.bkImg, title: 'Red King on '+(i+1)})).place(this[s]);
// Sync the DnD
if(this.dndEnabled) {
this[s].dnd.sync();
}
break;
case 'w':
dojo.query(dojo.create('img',{src: this.wmImg, title: 'White Piece on '+(i+1)})).place(this[s]);
// Sync the DnD
if(this.dndEnabled) {
this[s].dnd.sync();
}
break;
case 'W':
dojo.query(dojo.create('img',{src: this.wkImg, title: 'White King on '+(i+1)})).place(this[s]);
// Sync the DnD
if(this.dndEnabled) {
this[s].dnd.sync();
}
break;
default:
break;
}
}
}
,setProblemDetails: function() {
this.showMove();
this.problem_description.innerHTML = "
"+this.gameDetails.result_text+"";
}
,showMove: function() {
if(this.move.length > 0) {
this.move = this.move.toLowerCase();
var m = (this.move == 'w') ? 'White' : 'Red';
m = ''+m+' to Move';
var t = (this.titleText.length == 0) ? m : this.titleText+'
'+m;
this.setTitle(t);
//this.title.innerHTML = t;
}
}
// Determine if this square should accept the incoming piece
,_isAccepted: function(p_source,p_nodes) {
// Check board mode
// Check space against piece
var s = this.square;
var p = dojo.attr(p_nodes[0],'value');
/*
console.log(s);
console.log(p);
*/
return true;
}
// On drop of a piece, set some values
,_doDrop: function(p_source,p_nodes,p_copy,p_target) {
if(dojo.dnd.manager().target !== this) {
return;
}
var s = this.square;
var p = dojo.attr(p_nodes[0],'value');
// If not copying, we are moving around on the board
// Need to unset the value on the from square
if(!p_copy) {
var f = p_source.square;
this.board._setPiece(f,'.');
}
p_target.forInItems(dojo.hitch(p_target,function(o,i,m) {
var n = dojo.byId(i);
// Anchor should be the item we're dropping
if(!dojo.hasClass(n,'dojoDndItemAnchor')) {
this.delItem(i);
dojo.destroy(n);
}
else {
// Set the value for the node
dojo.attr(n,'value',p);
}
}));
/*
console.log(s);
console.log(p);
*/
this.board._setPiece(s,p);
}
// Change the current position
,_setPiece: function(p_square,p_value) {
// Borrowed regex expression to replace 1 char from
// http://bytes.com/topic/javascript/answers/771950-change-single-character-string
// string[num] = 'new string'; does not work
var p = this.position;
var re = new RegExp('^(.{'+ --p_square +'}).(.*)$','');
this.position = p.replace(re,'$1'+p_value+'$2');
}
,generateFEN: function() {
var s = '[FEN "'+this.move.toUpperCase();
var w = '';
var b = '';
var p = this.position;
for(var i = 0; i < p.length; i++) {
var sq = i+1;
switch(p.charAt(i)) {
case 'w':
w += sq+', ';
break;
case 'W':
w += 'K'+sq+', ';
break;
case 'b':
b += sq+', ';
break;
case 'B':
b += 'K'+sq+', ';
break;
default:
break;
}
}
w = w.replace(/\, $/,"")
b = b.replace(/\, $/,"")
s += ':W'+w+':B'+b+'"]';
this.fen = s;
}
,showFEN: function() {
this.generateFEN();
this.pdn.innerHTML = this.fen;
}
,setFen: function(p_fen) {
}
,setPositionFromFen: function() {
var f = this.fen.split(':');
// Remove [FEN and all spaces and quotes
this.move = f[0].replace(/FEN/i,'').replace(/\[/,'').replace(/\"/,'').replace(/ +/,'').toLowerCase();
var w = (f[1].charAt(0).toUpperCase() == 'W') ? f[1].replace(/w/i,'').split(',')
: f[2].replace(/w/i,'').split(',');
var b = (f[2].charAt(0).toUpperCase() == 'B') ? f[2].replace(/b/i,'').split(',')
: f[1].replace(/b/i,'').split(',');
for(var i = 0; i < w.length; i++) {
var p = dojo.trim(w[i]);
var v = (p.charAt(0).toUpperCase() == 'K') ? 'W' : 'w';
//var s = p.replace(/k/i,'');
// Strip all non-numeric characters
var s = p.replace(/[^0-9]/g,'');
this._setPiece(s,v);
}
for(var i = 0; i < b.length; i++) {
var p = dojo.trim(b[i]);
var v = (p.charAt(0).toUpperCase() == 'K') ? 'B' : 'b';
//var s = p.replace(/k/i,'');
// Strip all non-numeric characters
var s = p.replace(/[^0-9]/g,'');
this._setPiece(s,v);
}
this.drawPosition();
this.showMove();
this.showFEN();
}
/* Move to Board.js ? Or remove from Board.html ? */
,showPDN: function() {
this.pdn.innerHTML = this.pdnText;
}
,togglePdn: function(p_hide) {
var v = (typeof p_hide == 'boolean') ? !p_hide : (this.pdn.style.display == 'none');
// Currently not visible
if(v) {
dojo.removeClass(this.pdn_toggle_btn.iconNode,'show');
dojo.addClass(this.pdn_toggle_btn.iconNode,'hide');
this.show('pdn');
}
else {
dojo.removeClass(this.pdn_toggle_btn.iconNode,'hide');
dojo.addClass(this.pdn_toggle_btn.iconNode,'show');
this.hide('pdn');
}
}
,setDetails: function() {
var d = this.gameDetails;
this.wplayer.innerHTML = (d && d.white_player) ? d.white_player : '?';
this.bplayer.innerHTML = (d && d.black_player) ? d.black_player : '?';
if(d.provided_by) {
this.copyright.innerHTML = 'Game provided by: '+d.provided_by+'';
this.show('copyright');
}
else {
this.hide('copyright');
}
var s = (d && d.style) ? '['+d.style+'] ' : '';
var e = (d && d.event) ? d.event : '';
var dt = (d && d.date) ? 'Date: '+d.date : '';
var t = (s) ? s : '';
t += (e) ? e : '';
t += (dt) ? ' - ' + dt : '';
this.setTitle(t);
if(this.mode.indexOf('PROBLEM') > -1) {
this.setProblemDetails();
}
}
,flipBoard: function() {
var b = (this._board) ? this._board : this;
b.inherited(arguments);
b.drawPosition();
}
,_removeBank: function() {
var b = this.bank;
if(b.hasChildNodes()) {
dojo.empty(b);
}
b.style.display = 'block';
}
,_createBank: function() {
var b = this.bank;
b.style.backgroundImage = 'url('+this.bankImg+')';
if(b.hasChildNodes()) {
dojo.empty(b);
}
//TODO don't allow pieces to overlap
var x = new dojo.dnd.Source(b,{copyOnly: true});
x.accept = null;
//
var s = dojo.create('div');
dojo.attr(s,'value','w');
dojo.attr(s,'title','White Piece');
dojo.addClass(s,'dojoDndItem piece');
dojo.query(dojo.create('img',{src: this.wmImg})).place(s);
dojo.place(s,b);
//
s = dojo.create('div');
dojo.attr(s,'value','b');
dojo.attr(s,'title','Red Piece');
dojo.addClass(s,'dojoDndItem piece');
dojo.query(dojo.create('img',{src: this.bmImg})).place(s);
dojo.place(s,b);
//
s = dojo.create('div');
dojo.attr(s,'value','W');
dojo.attr(s,'title','White King');
dojo.addClass(s,'dojoDndItem piece');
dojo.query(dojo.create('img',{src: this.wkImg})).place(s);
dojo.place(s,b);
//
s = dojo.create('div');
dojo.attr(s,'value','B');
dojo.attr(s,'title','Red King');
dojo.addClass(s,'dojoDndItem piece');
dojo.query(dojo.create('img',{src: this.bkImg})).place(s);
dojo.place(s,b);
//
var t = dojo.create('div');
// Add the piece class just so it scales correctly
var y = new dojo.dnd.Source(t,{isSource: false});
var i = dojo.create('img',{src: this.delImg});
dojo.addClass(t,'piece');
dojo.attr(t,'title','Delete Piece');
dojo.place(i,t);
dojo.place(t,b);
// Delete all nodes on drop
dojo.connect(y,"onDndDrop",function (p_source,p_nodes,p_copy,p_target) {
if(dojo.dnd.manager().target !== this) {
return;
}
var f = p_source.square;
p_source.board._setPiece(f,'.');
this.deleteSelectedNodes();
});
y.startup();
//
x.startup();
// Don't want table cell because it doesn't scale
//b.style.display = 'table-cell';
//this._resize();
setTimeout(dojo.hitch(this,'_resize'),250);
}
,_setupMode: function() {
this.mode = 'SETUP';
this.dndEnabled = true;
this._createBoard();
this.toolbar.hideToolbar(this.hiddenToolbar);
this.controls.hideToolbar(true);
this.hide('game_details');
this.show('left');
var sh = (this.hideMenus) ? 'hide' : 'show';
this[sh]('menu');
this.hide('right');
this.show('pdn_container');
this.hide('problem_container');
this.toggleNumbers(this.showNumbers);
this._createBank();
if(this.position != this.emptyPosition) {
this.generateFEN();
this.setPositionFromFen();
}
this._onAfterMode();
}
,_imageMode: function() {
this.mode = 'IMAGE';
this.dndEnabled = false;
this._createBoard();
this.toolbar.hideToolbar(this.hiddenToolbar);
this.controls.hideToolbar(true);
this.hide('game_details');
this.hide('left');
var sh = (this.hideMenus) ? 'hide' : 'show';
this[sh]('menu');
this.hide('right');
this.show('pdn_container');
this.hide('problem_container');
this.toggleNumbers(this.showNumbers);
/* If we change modes, we may need to generate a FEN */
if(this.position != this.emptyPosition) {
this.generateFEN();
}
this.setPositionFromFen();
this._onAfterMode();
}
,_gameMode: function() {
this.mode = 'GAME';
this.dndEnabled = false;
this._createBoard();
this.toolbar.hideToolbar(this.hiddenToolbar);
this.controls.hideToolbar(false);
this.show('game_details');
this.hide('left');
var sh = (this.hideMenus) ? 'hide' : 'show';
this[sh]('menu');
this.show('right');
this.show('pdn_container');
this.hide('problem_container');
this.toggleNumbers(this.showNumbers);
/* If we change modes, we may need to reset start position */
if(this.moveList) {
this.setMove(this.startPosition);
this.showPDN();
this.togglePdn(this.hidePDN);
this.setDetails();
}
this._onAfterMode();
}
// Problem mode hides the move list and PDN until user clicks "Show Answer"
,_problemMode: function() {
this.mode = 'PROBLEM';
this.dndEnabled = false;
this._createBoard();
this.toolbar.hideToolbar(this.hiddenToolbar);
this.controls.hideToolbar(true);
this.show('game_details');
this.hide('left');
var sh = (this.hideMenus) ? 'hide' : 'show';
this[sh]('menu');
this.hide('right');
this.hide('pdn_container');
this.show('problem_container');
this.toggleNumbers(this.showNumbers);
if(this.hidePDN) {
dojo.connect(this,'_createMoves',this,function() {
dojo.query('.move').addClass('blackout');
});
}
this._onAfterMode();
}
,_loadMode: function() {
this._gameMode();
this.getGame();
}
,_parseProblemMode: function() {
this._problemMode();
this.parseGame();
}
,_parseMode: function() {
this._gameMode();
this.parseGame();
this.setTitle(t);
}
,_forumMode: function() {
this._gameMode();
this.parseGame();
this.hide('menuFile');
this.hide('menuMode');
// Hide for now since it's not yet working
this.hide('menuView');
// Hide for now since it's not yet working
this.hide('menuHelp');
this.show('menuTools');
this._onAfterMode();
}
,setMode: function(p_mode) {
if(p_mode && typeof(p_mode) == 'string') {
this.mode = p_mode;
}
switch(this.mode) {
case 'IMAGE':
this._imageMode();
break;
case 'LOAD':
this._loadMode();
break;
case 'PARSE':
this._parseMode();
break;
case 'FORUM':
this._forumMode();
break;
case 'GAME':
this._gameMode();
break;
case 'PARSEPROBLEM':
this._parseProblemMode();
break;
case 'PROBLEM':
this._problemMode();
break;
default:
this._setupMode();
break;
}
}
,_onAfterMode: function() {
// Resize the board
this._resize();
this.onAfterMode();
}
,onAfterMode: function(){}
,loadXHRGames: function(p_data) {
if(typeof(p_data) == "string") {
p_data = dojo.fromJson(p_data);
}
if(p_data.items) {
switch(p_data.items.length) {
case 0:
this.loadFailed();
break;
case 1:
// LoadXHRGame expects items to be the game, not an array of games
p_data.items = p_data.items[0];
this.loadXHRGame(p_data);
break;
default:
this.buildStoreFromDetails(p_data.items);
//console.log('Provide list of games.');
//console.log(p_data.items);
break;
}
}
}
,loadXHRGame: function(p_data) {
if(p_data.items) {
this.loadGame(p_data.items);
}
}
,buildStoreFromDetails: function(p_games) {
var l = Array();
dojo.forEach(p_games,function(g,i) {
var d = g.details;
var x = new Object();
x['P_EVENT'] = (d.event) ? d.event : 'Unknown';
x['P_STYLE'] = (d.style) ? d.style : 'Unknown';
x['P_CATEGORY'] = (d.category) ? d.category : 'Unknown';
x['P_YEAR'] = (d.year) ? d.year : '????';
x['P_BLACK_PLAYER'] = (d.black_player) ? d.black_player : '?';
x['P_WHITE_PLAYER'] = (d.white_player) ? d.white_player : '?';
x['P_RESULT_TEXT'] = (d.result) ? d.result : '*';
l.push(x);
});
this.listGames(l);
}
,listGames: function(p_games) {
console.log(p_games);
// Stub right now...
}
,loadGame: function(p_game) {
try {
this.moveList = p_game.movelist;
this.positionList = p_game.positions;
this.commentList = p_game.comments;
this.turnList = p_game.turns;
this.gameDetails = p_game.details;
this._createMoves();
this.pdnText = p_game.pdn;
this.showPDN();
// Set move before details so we know who's move it is
this.setMove(this.startPosition);
this.setDetails();
}
catch(e) {
this.loadFailed();
}
// Resize now that we have a game loaded
this._resize();
}
,loadFailed: function() {
this.showPDN();
this.position = this.emptyPosition;
var t = 'Failed to Load Game
';
this.setTitle(t);
}
,loadGameFromList: function(p_row) {
var game_id = p_row[0].P_ID[0];
this.gameId = game_id;
this.games_win.hide();
this.getGame();
}
,setMove: function(p_idx) {
this.inherited(arguments);
this.setPosition(p_idx);
this.move = (this.turnList[p_idx] == 'B') ? 'b' : 'w';
}
,setPosition: function(p_idx) {
if(this.positionList && this.positionList.length > p_idx) {
this.position = this.positionList[p_idx];
this.drawPosition();
}
// else position doesn't exist
}
// Server calls
,doSearch: function() {
// Call search file
}
,getCheckBoxParams: function(c) {
var p_c = new Array();
var use_c = false;
for(var v in c) {
if(c[v][0] != undefined) {
p_c.push(c[v][0]);
}
else {
use_c = true;
}
}
// Check if empty ?
return (use_c) ? p_c : false;
}
// In case we want to add more params
,getSearchObj: function() {
var o = this.f_search.getSearchObj();
return o;
}
// Use normal search + position
,getPositionSearch: function() {
var o = this.f_search.getSearchObj();
o['P_POSITION'] = this.position;
return o;
}
// Server calls
,gameSearch: function() {
// Check for game mode?
var s = this.f_search._getGridStructure();
this.f_search.f_grid.attr('structure', s);
this.f_search.loadFile = this.gameSearchFile;
this.f_search._getSearchObj = dojo.hitch(this,'getSearchObj');
this.games_win.show();
}
// Server calls
,findPosition: function() {
if(this.postion != this.emptyPosition) {
var cs = this.f_search.f_grid.get('structure');
// Only set structure if it's not already set
if(cs[cs.length-1].field != 'P_NEXT_5') {
var s = this.f_search._getGridStructure();
s.push({ name: "Run-Up", field: "P_RUN_UP", width: "12em" });
s.push({ name: "Next 5", field: "P_NEXT_5", width: "12em" });
this.f_search.f_grid.set('structure',s);
}
this.f_search.loadFile = this.positionSearchFile;
this.f_search._getSearchObj = dojo.hitch(this,'getPositionSearch');
this.games_win.show();
}
}
,getGame: function() {
if(this.gameId != -1) {
//,'P_CALLBACK': 'callback'
//dojo.xhrPost({
dojo.io.script.get({
url: this.loadFile
,content: {
'P_GAME_ID': this.gameId
,'P_CALLBACK': 'acf_callback'
}
,callbackParamName: 'acf_callback'
,handleAs: "json"
,load: dojo.hitch(this,'loadXHRGame')
,error: function(error) {
//console.log(error);
}
});
}
}
,parseGame: function() {
if(this.pdnText.length) {
dojo.attr(this.i_pdn,'value',this.pdnText);
var p = {
//dojo.io.script.get({
url: this.parseFile
,method: "POST"
,form: this.f_parse
,content: {
'P_WINDOW': 'Y'
}
,callbackParamName: 'acf_callback'
,handleAs: "json"
,load: dojo.hitch(this,'loadXHRGames')
,error: function(error) {
//console.log(error);
}
};
//dojo.io.iframe.send(p);
var d = dojox.io.windowName.send("POST",p);
}
}
,uploadPDN: function() {
// Call upload file with io frame
}
,clearBoard: function() {
this.position = this.emptyPosition;
this._createBoard(); // Be sure to start with a clean slate
this.generateFEN();
this.setPositionFromFen();
}
,copyClipboard: function() {
this.pdnText = this.clipboard_data.attr('value');
this._parseMode();
this.inherited(arguments);
}
,postCreate: function() {
// Have to do this here because constructor doesn't read html yet
this.inherited(arguments);
this.startPosition = (this.startPosition) ? parseInt(this.startPosition) : 0;
dojo.connect(this.f_search,'loadGame',this,'loadGameFromList');
//this.setMode();
// Use a timeout in case the rest of the page isn't painted yet
setTimeout(dojo.hitch(this,'setMode'),0);
// Always hide this since it's not useful
this.hide('menuMode');
}
//Build menu
//Build grid
//cookie for prefs
//cookie for games
});