
// Yahoo2PGN
// By: Ben Marini 
// Additions By: Douglass Davis
// fixed to handle en passant, unfinished games, and to work on firefox


                                                                     
chessBoard =   [["*","*","*","*","*","*","*","*","*","*","*","*"],  // rank    index
                ["*","*","*","*","*","*","*","*","*","*","*","*"],  // ----    -----
                ["*","*","r","n","b","q","k","b","n","r","*","*"],  // 8       2
                ["*","*","p","p","p","p","p","p","p","p","*","*"],  // 7       3
                ["*","*"," "," "," "," "," "," "," "," ","*","*"],  // 6       4
                ["*","*"," "," "," "," "," "," "," "," ","*","*"],  // 5       5
                ["*","*"," "," "," "," "," "," "," "," ","*","*"],  // 4       6
                ["*","*"," "," "," "," "," "," "," "," ","*","*"],  // 3       7
                ["*","*","P","P","P","P","P","P","P","P","*","*"],  // 2       8
                ["*","*","R","N","B","Q","K","B","N","R","*","*"],  // 1       9
                ["*","*","*","*","*","*","*","*","*","*","*","*"],
                ["*","*","*","*","*","*","*","*","*","*","*","*"]];


currentMoveNumber=0;
currentMoveColor = "";
promoteTo ="";

function viewGame() 
{
   if (document.converter.output.value == "") {
       alert("You must convert a game to PGN before you can view it.");
   } 

   else {
        document.showgame.pgn.value = document.converter.output.value;
        document.showgame.submit();
   }
}

function saveGame() 
{
   if (document.converter.output.value == "") {
       alert("You must convert a game to PGN before you can save it.");
   } 

   else {
        document.savegame.pgn.value = document.converter.output.value;
        document.savegame.submit();
   }
}

function startOver()
{
   document.converter.output.value=""
   document.converter.input.value=""

   document.converter.winner[0].checked=false; 
   document.converter.winner[1].checked=false; 
   document.converter.winner[2].checked=false; 
   document.converter.winner[3].checked=false; 

   location.href="#yahoocode"

   document.converter.input.focus()
   document.converter.input.select()
}


function convert()
{ 
  // trim
  document.converter.input.value = 
        document.converter.input.value.replace(/^\s+|\s+$/g,"");

  if (document.converter.input.value.length <= 30 ) {
    location.href='#yahoocode';
    alert('Please paste the Yahoo game in the text box before clicking the convert button.');
  }
  else if (document.converter.winner[0].checked == false && 
      document.converter.winner[1].checked == false && 
      document.converter.winner[2].checked == false &&
      document.converter.winner[3].checked == false)
  {
    location.href='#mark_result';
    alert('Please enter a result for the game.');
  }

  else
  {
    document.converter.output.value = convertHead() + "\n" + convertBody();
    document.converter.output.focus();
    document.converter.output.select();
                                                                     
    chessBoard =   [["*","*","*","*","*","*","*","*","*","*","*","*"],  // rank    index
                    ["*","*","*","*","*","*","*","*","*","*","*","*"],  // ----    -----
                    ["*","*","r","n","b","q","k","b","n","r","*","*"],  // 8       2
                    ["*","*","p","p","p","p","p","p","p","p","*","*"],  // 7       3
                    ["*","*"," "," "," "," "," "," "," "," ","*","*"],  // 6       4
                    ["*","*"," "," "," "," "," "," "," "," ","*","*"],  // 5       5
                    ["*","*"," "," "," "," "," "," "," "," ","*","*"],  // 4       6
                    ["*","*"," "," "," "," "," "," "," "," ","*","*"],  // 3       7
                    ["*","*","P","P","P","P","P","P","P","P","*","*"],  // 2       8
                    ["*","*","R","N","B","Q","K","B","N","R","*","*"],  // 1       9
                    ["*","*","*","*","*","*","*","*","*","*","*","*"],
                    ["*","*","*","*","*","*","*","*","*","*","*","*"]];
    location.href='#pgncode';
  }
}

function debugBoard()
{
    var boardString = "";
    for (var r = 0; r < 12; r++) {
        for (var f = 0; f< 12 ; f++) {
            boardString += chessBoard[r][f];
        }
        boardString +="\n";
    }

    return boardString;
}

function getHead()
{
    var gameString = document.converter.input.value;
    var lines = gameString.split(/\n/);
    
    var head = new Array();
    

    for (var i = 0; i< 4 ; i++) {
        head[i] = lines[i].split(/[\:\s]+/);
    }

    return head;
}

function convertHead()
{
  var gameString = document.converter.input.value;
  var headSplit = getHead();
  
  var head = '[Event "Yahoo! Chess Game"]\n[Site "Yahoo! Chess"]\n' +
             '[Date "' + convertDate() + '"]\n[Round ""]\n[White "' +
             headSplit[1][1] + '"]\n[Black "' + headSplit[2][1] + '"]\n' +
             '[Result "' + findResult() + '"]';
  
  return head;
}


function convertDate()
{
  
  var head=getHead();
  var date = "";
  var month = "";
 
  date += head[3][8]+'.';
  month = head[3][2]

  if (month == "Jan"){date += "01.";}
  if (month == "Feb"){date += "02.";}
  if (month == "Mar"){date += "03.";}
  if (month == "Apr"){date += "04.";}
  if (month == "May"){date += "05.";}
  if (month == "Jun"){date += "06.";}
  if (month == "Jul"){date += "07.";}
  if (month == "Aug"){date += "08.";}
  if (month == "Sep"){date += "09.";}
  if (month == "Oct"){date += "10.";}
  if (month == "Nov"){date += "11.";}
  if (month == "Dec"){date += "12.";}
  
  date += head[3][3];
  
  return date;
}

function findResult()
{
  if (document.converter.winner[0].checked == true)
  {
    return document.converter.winner[0].value;
  }
  if (document.converter.winner[1].checked == true)
  {
    return document.converter.winner[1].value;
  }
  if (document.converter.winner[2].checked == true)
  {
    return document.converter.winner[2].value;
  }
  if (document.converter.winner[3].checked == true)
  {
    return document.converter.winner[3].value;
  }
}

function changeMoveColor()
{
   if (currentMoveColor=="") {
      currentMoveColor="white"
   } else {
      currentMoveColor="black"
   }
}


function convertBody()
{              
  var gameString = document.converter.input.value;
  var gameSplit  = gameString.split(/[\s\n\r]+/); 
  var aNumber    = /[0-9]/;
  var body       = "";
  var firstMove;


  for (var firstMove = 0; firstMove < gameSplit.length; firstMove++)
  {
     if ( gameSplit[firstMove] == '1.' )
        break;
  }


  for (var i = firstMove; i < gameSplit.length; i++)
  {
    moveNum = i - firstMove + 15;

    // for some reason firefox returns the last
    // blank line as an empty string.

    if ( gameSplit[i]== "" )
      continue;

    if (aNumber.test(gameSplit[i].charAt(0)))
    {
      body += "\n" + gameSplit[i] + " ";
      currentMoveNumber = gameSplit[i].split(/\./)[0]
      currentMoveColor = ""
    }
    
    else if (gameSplit[i] == "o-o")
    {
      body += "O-O ";
      changeMoveColor();
      castleKingside(moveNum);
    }
    
    else if (gameSplit[i] == "o-o-o")
    {
      body += "O-O-O ";
      changeMoveColor();
      castleQueenside(moveNum);
    }
    
    else
    {
      changeMoveColor();
      body += convertMove(gameSplit[i]) + " ";
      updateBoard(gameSplit[i]);
    }

  }
  
  body += findResult();
  
  return body; 
}


function isPawnPromotion(move)
{
  var i = Number(chx(move.charAt(0))); // FromFile Index
  var j = Number(chy(move.charAt(1))); // FromRank Index
  var k = Number(chx(move.charAt(3))); // ToFile Index
  var l = Number(chy(move.charAt(4))); // ToRank Index

   if ( (  (move.charAt(4) == '8') && (chessBoard[j][i] == "P")  ) || 
         (  (move.charAt(4) == '1') && (chessBoard[j][i] == "p")  ) ) {
      return true;
   }
}

function isEnPassant(move)
{
  var i = Number(chx(move.charAt(0))); // FromFile Index
  var j = Number(chy(move.charAt(1))); // FromRank Index
  var k = Number(chx(move.charAt(3))); // ToFile Index
  var l = Number(chy(move.charAt(4))); // ToRank Index

 
  if ( ( (chessBoard[j][i] == "p") ||
         (chessBoard[j][i] == "P") )
       && 
       (chessBoard[l][k] == " " &&  i != k ))
  {
     return true;
  }
  else {
    return false;
  }
}


// Yahoo format of non-castle move:
// (File)(Rank)(x|-)(File)(Rank)[+|++]
// 
// the x is for capture, - is for regular move.
//
// Yahoo Bug: as of 12/14/06, yahoo does not add an x in the case of
// en passant captures.



// PGN format of non-castle move:
//
//  [K|Q|R|B|N][x][FromFile|FromRank|FromSquare](ToSquare)[=Q][+|++]
//
// 1) File, 2) Rank, or 3) FromSquare given only if necessary to disambiguate
//
// PGN format of enpassant move (according to some)
//    (FromFile)x(ToFile)(ToRank)ep
// 

function convertMove(move)
{

  var piece = "";
  var takes = "";
  var check = "";
  var promote = "";
  var backRank = /[18]/;
  var i = Number(chx(move.charAt(0))); // FromFile Index
  var j = Number(chy(move.charAt(1))); // FromRank Index
  var k = Number(chx(move.charAt(3))); // ToFile Index
  var l = Number(chy(move.charAt(4))); // ToRank Index


  if (isEnPassant(move)) {
       return move.charAt(0) + "x" + move.charAt(3) + move.charAt(4) + "ep"
  }

  if ((chessBoard[j][i] != " ") &&
      (chessBoard[j][i] != "p") &&
      (chessBoard[j][i] != "P"))
  {
    piece = chessBoard[j][i].toUpperCase();
  }
  
  if (move.charAt(2) == "x")
  {
    if ((chessBoard[j][i] == "p") ||
        (chessBoard[j][i] == "P"))
    {
      takes = move.charAt(0) + "x";
    }
    else
    {
      takes = "x";
    }
  }
  
  if (move.length == 6)
  {
    check = "+";
  }
  
  if (move.length == 7)
  {
    check = "#";
  }
  
 
  // if a pawn promotion
 
  if ( isPawnPromotion(move) )
  { 
      promotePrompt="In move "+currentMoveNumber + ", was the "+ currentMoveColor + " pawn promoted to a ";

      if (confirm(promotePrompt+ "Queen? (OK for yes, cancel for no)")) {
         promotePiece="Q";
      } else if (confirm(promotePrompt+ "Rook?  (OK for yes, cancel for no)")) {
         promotePiece="R";
      } else if (confirm(promotePrompt+ "Knight?  (OK for yes, cancel for no)")) {
         promotePiece="N";
      } else if (confirm(promotePrompt+ "Bishop?  (OK for yes, cancel for no)")) {
         promotePiece="B";
      }
      else {
         alert("Since no piece was specified, the piece will be promted to a queen");
         promotePiece="Q";
      }

      promote = "="+ promotePiece;
  }
 

  
  return   piece + 
          checkAmbig(move) +
          takes + 
          move.charAt(3) + 
          move.charAt(4) + 
          promote + 
          check;
  
  
}

// get array index from file

function chy(y)
{
  var yArray = [0,9,8,7,6,5,4,3,2];
  return yArray[y];
}

// get array index from rank

function chx(x)
{
  if (x == "a") {return 2;}
  if (x == "b") {return 3;}
  if (x == "c") {return 4;}
  if (x == "d") {return 5;}
  if (x == "e") {return 6;}
  if (x == "f") {return 7;}
  if (x == "g") {return 8;}
  if (x == "h") {return 9;}
}

function updateBoard(move)
{
  var i = Number(chx(move.charAt(0)));
  var j = Number(chy(move.charAt(1)));
  var k = Number(chx(move.charAt(3)));
  var l = Number(chy(move.charAt(4)));
  
  if (isPawnPromotion(move) ){

      chessBoard[j][i] = " ";

      if (move.charAt(4) == 1 ) {
         chessBoard[l][k] = promotePiece.toLowerCase();
      }
      else  {
         chessBoard[l][k] = promotePiece;
      }
  }
  else if (isEnPassant(move)) {
     chessBoard[l][k] = chessBoard[j][i];
     chessBoard[j][i] = " ";
     chessBoard[j][k] = " ";
  
  }
  else {
     chessBoard[l][k] = chessBoard[j][i];
     chessBoard[j][i] = " ";
  }
}

function castleKingside(moveNum)
{

  if (currentMoveColor == "white")
  {
    //castle white
    chessBoard[9][9] = " ";
    chessBoard[9][8] = "K";
    chessBoard[9][7] = "R";
    chessBoard[9][6] = " ";
  }
  else
  {
    //castle black
    chessBoard[2][9] = " ";
    chessBoard[2][8] = "k";
    chessBoard[2][7] = "r";
    chessBoard[2][6] = " ";
  }
}

function castleQueenside(moveNum)
{
  if (currentMoveColor == "white")
  {
    //white
    chessBoard[9][2] = " ";
    chessBoard[9][4] = "K";
    chessBoard[9][5] = "R";
    chessBoard[9][6] = " ";
  }
  else
  {
    //black
    chessBoard[2][2] = " ";
    chessBoard[2][4] = "k";
    chessBoard[2][5] = "r";
    chessBoard[2][6] = " ";
  }
    
}

function checkAmbig(move)
{
  var i = Number(chx(move.charAt(0)));
  var j = Number(chy(move.charAt(1)));
  var k = Number(chx(move.charAt(3)));
  var l = Number(chy(move.charAt(4)));
  var piece = "";
  
  piece = chessBoard[j][i];
  
  if ((piece == 'r') ||
      (piece == 'R'))
  {
    return checkRook(piece, move);
  }
  
  if ((piece == 'n') ||
      (piece == 'N'))
  {
    return checkKnight(piece, move);
  }
  
  if ((piece == 'q') ||
      (piece == 'Q'))
  {
    return checkQueen(piece, move);
  }
  
  return "";
}

function checkRook(piece, move)
{
  var i = Number(chx(move.charAt(0)));
  var j = Number(chy(move.charAt(1)));
  var k = Number(chx(move.charAt(3)));
  var l = Number(chy(move.charAt(4)));
  
  var up    = lookUp(piece,l,k,i);
  var down  = lookDown(piece,l,k,i);
  var left  = lookLeft(piece,l,k,i);
  var right = lookRight(piece,l,k,i);
  
  var rooks = up + down + left + right;
  
  if (rooks > 100)
  {
    // use rank to disambiguate if we have to
    if ((up >= 1) && (down >= 1)) return move.charAt(1);

    // otherwise use file.
    return move.charAt(0);
  }
  return "";
}

// returns 100 if on same FromFile
// 1 if not on same FromFile.

function lookUp(piece,l,k,i)
{
  for (l = l - 1; chessBoard[l][k] != '*';l--)
  {
    if (chessBoard[l][k] == piece)
    {
      if (k == i) return 100;
      return 1;
    }
    
    if (chessBoard[l][k] != ' ') break;
  }
  
  return 0;
}

function lookDown(piece,l,k,i)
{
  for (l = l + 1; chessBoard[l][k] != '*';l++)
  {
    if (chessBoard[l][k] == piece)
    {
      if (k == i) return 100;
      return 1;
    }
    
    if (chessBoard[l][k] != ' ') break;
  }
  
  return 0;
}

function lookLeft(piece,l,k,i)
{
  for (k = k - 1; chessBoard[l][k] != '*';k--)
  {
    if (chessBoard[l][k] == piece)
    {
      if (k == i) return 100;
      return 1;
    }
    
    if (chessBoard[l][k] != ' ') break;
  }
  
  return 0;
}

function lookRight(piece,l,k,i)
{
  for (k = k + 1; chessBoard[l][k] != '*';k++)
  {
    if (chessBoard[l][k] == piece)
    {
      if (k == i) return 100;
      return 1;
    }
    
    if (chessBoard[l][k] != ' ') break;
  }
  
  return 0;
}


function checkKnight(piece, move)
{
  var i = Number(chx(move.charAt(0)));
  var j = Number(chy(move.charAt(1)));
  var k = Number(chx(move.charAt(3)));
  var l = Number(chy(move.charAt(4)));
  
  var knights  = 0;
  var knights1 = 0;
  var knights2 = 0;
  var knights3 = 0;
  var knights4 = 0;
  
  if (chessBoard[l-2][k+1] == piece) knights1++;
  if (chessBoard[l+2][k+1] == piece) knights1++;
  if (chessBoard[l-2][k-1] == piece) knights2++;
  if (chessBoard[l+2][k-1] == piece) knights2++;
  if (chessBoard[l-1][k+2] == piece) knights3++;
  if (chessBoard[l+1][k+2] == piece) knights3++;
  if (chessBoard[l-1][k-2] == piece) knights4++;
  if (chessBoard[l+1][k-2] == piece) knights4++;
  
  knights = knights1 + knights2 + knights3 + knights4;
  
  if ((knights1 > 1) ||
      (knights2 > 1) ||
      (knights3 > 1) ||
      (knights4 > 1))
  {
    return move.charAt(1);
  }
  
  if (knights > 1) return move.charAt(0);
  return "";
}

function checkQueen(piece, move)
{
  var i = Number(chx(move.charAt(0)));
  var j = Number(chy(move.charAt(1)));
  var k = Number(chx(move.charAt(3)));
  var l = Number(chy(move.charAt(4)));
  
  var upleft     = lookUpLeft(piece,l,k,i);
  var up         = lookUp(piece,l,k,i);
  var upright    = lookUpRight(piece,l,k,i);
  var downleft   = lookDownLeft(piece,l,k,i);
  var down       = lookDown(piece,l,k,i);
  var downright  = lookDownRight(piece,l,k,i);
  var left       = lookLeft(piece,l,k,i);
  var right      = lookRight(piece,l,k,i);
  
  var pieceUp    = lookUp(piece,j,i);
  var pieceDown  = lookDown(piece,j,i);
  
  var queens = upleft +
               up + 
               upright +
               downleft +
               down + 
               downright +
               left + 
               right;
  
  if (queens > 100)
  {
    // TODO: may need better disambiguation in extremely rare circumstances.
    // should use 3 digit code (# w/same fromfile, # w/same fromrank, #other)

    // if more than one queen on same FromFile use FromRank to disambiguate 
    if (queens >= 200) return move.charAt(1);
    // otherwise, just use FromFile 
    return move.charAt(0);
  }
  return "";
}

function lookUpLeft(piece,l,k,i)
{
  l = l-1;
  k = k-1;
  for (;;)
  {
    if (chessBoard[l][k] == '*') break;
    if (chessBoard[l][k] == piece)
    {
      if (k == i) return 100;
      return 1;
    }
    
    if (chessBoard[l][k] != ' ') break;
    l--;
    k--;
  }
  
  return 0;
}

function lookUpRight(piece,l,k,i)
{
  l = l-1;
  k = k+1;
  for (;;)
  {
    if (chessBoard[l][k] == '*') break;
    if (chessBoard[l][k] == piece)
    {
      if (k == i) return 100;
      return 1;
    }
    
    if (chessBoard[l][k] != ' ') break;
    l--;
    k++;
  }
  
  return 0;
}

function lookDownRight(piece,l,k,i)
{
  l = l+1;
  k = k+1;
  for (;;)
  {
    if (chessBoard[l][k] == '*') break;
    if (chessBoard[l][k] == piece)
    {
      if (k == i) return 100;
      return 1;
    }
    
    if (chessBoard[l][k] != ' ') break;
    l++;
    k++;
  }
  
  return 0;
}

function lookDownLeft(piece,l,k,i)
{
  l = l+1;
  k = k-1;
  for (;;)
  {
    if (chessBoard[l][k] == '*') break;
    if (chessBoard[l][k] == piece)
    {
      if (k == i) return 100;
      return 1;
    }
    
    if (chessBoard[l][k] != ' ') break;
    l++;
    k--;
  }
  
  return 0;
}


