// Thanks to Lutz Tautenhahn whose LT-PGN-VIEWER this
// code is adapted from - see http://www.lutanho.net/.

// Global variables.
var i, j, s;
var kb_focus;

// Constants.
var ColorName = new Array("w","b","t");
var MaxMove=500;
var PieceName="KQRBNP";
var PieceCode = new Array(6);
for (i=0; i<6; i++) PieceCode[i]=PieceName.charCodeAt(i);
var StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";

// Object conctructor. Methods will be added by prototypes.
function PGNGame(id, ImagePath, ImageOffset)
{
  // Instance variables initialised from arguments.
  this.VarName     = 'g' + id;
  this.ImagePath   = ImagePath;
  this.ImageOffset = ImageOffset;

  // Other instance variable initialisations.
  this.isRotated=false;
  this.ActiveAnchor=-1;
  this.CurVar=0;
  this.HalfMove = new Array(MaxMove+1);
  this.HistMove = new Array(MaxMove);
  this.StartAnchor=-1;
  this.Board = new Array(8);
  for (i=0; i<8; i++) this.Board[i] = new Array(8);
  this.Castling = new Array(2);
  for (i=0; i<2; i++) this.Castling[i] = new Array(2);
  this.HistPiece = new Array(2);
  for (i=0; i<2; i++) this.HistPiece[i] = new Array(MaxMove);
  this.HistPosX = new Array(2);
  for (i=0; i<2; i++) this.HistPosX[i] = new Array(MaxMove);
  this.HistPosY = new Array(2);
  for (i=0; i<2; i++) this.HistPosY[i] = new Array(MaxMove);
  this.HistType = new Array(2);
  for (i=0; i<2; i++) this.HistType[i] = new Array(MaxMove);
  this.PieceType = new Array(2);
  for (i=0; i<2; i++) this.PieceType[i] = new Array(16);
  this.PiecePosX = new Array(2);
  for (i=0; i<2; i++) this.PiecePosX[i] = new Array(16);
  this.PiecePosY = new Array(2);
  for (i=0; i<2; i++) this.PiecePosY[i] = new Array(16);
  this.PieceMoves = new Array(2);
  for (i=0; i<2; i++) this.PieceMoves[i] = new Array(16);
  this.ShortPgnMoveText=new Array(3);
  for (i=0; i<3; i++) this.ShortPgnMoveText[i] = new Array();
  this.ShortPgnMoveText[0][0]='';

  // Instance variables initialised elsewhere.
  this.CanPass        = null;
  this.EnPass         = null;
  this.MoveType       = null;
  this.MoveCount      = null;
  this.StartMove      = null;
  this.TargetDocument = null;

  // Initialisation requiring instance methods.
  this.InitImages();

  // Make this game the keyboard focus.
  kb_focus = this;
}

// Instance methods, created using prototype mechanism.
PGNGame.prototype.ApplyPgnMoveText = function(ss, rroot)
{
  var vv=0;
  if (! isNaN(rroot)) 
  {
    vv=this.ShortPgnMoveText[0].length; 
    this.ShortPgnMoveText[0][vv]=""; 
  }
  else 
  {
    this.ShortPgnMoveText[0].length=1;
    this.TargetDocument=window.document;
    if (! rroot) this.StartAnchor=-1;
  }  
  var ii, uu="", uuu="", cc, bb=0, bbb=0, ll=ss.length;
  for (ii=0; ii<ll; ii++)  
  {
    cc=ss.substr(ii,1);
    if (cc=="{") bbb++;
    if (cc=="}") bbb--; 
    if (((cc==")")||(cc=="]"))&&(bbb==0)) 
    {
      bb--;
      if (bb==0)
      {
        if (bbb==0) uu+=this.ApplyPgnMoveText(uuu, vv);
        else uu+=uuu;
        uuu="";
      }  
    }  
    if (bb==0) uu+=cc;
    else uuu+=cc;
    if (((cc=="(")||(cc=="["))&&(bbb==0)) bb++; 
  }
  if (! isNaN(rroot))
  {
    ii=0, jj=0, bb=0;
    while ((ii<uu.length-1)&&(((ii>0)&&(uu.charAt(ii-1)!=" "))||(isNaN(parseInt(uu.charAt(ii)))))) ii++;
    while ((ii<uu.length-1)&&(! isNaN(parseInt(uu.charAt(ii))))) { bb=10*bb+parseInt(uu.charAt(ii)); ii++; }
    if (ii<uu.length-1)
    {
      uuu=uu.substr(ii, 3);
      switch (uuu)
      {
        case "...": jj=1; break;
        case " ..": jj=1; break;
      }
      if (jj==0)  
      {
        uuu=uu.substr(ii, 4);
        switch (uuu)
        {
          case "....": jj=1; break;
          case ". ..": jj=1; break;
          case " ...": jj=1; break;
        }
      }
      if (jj==0)  
      {
        uuu=uu.substr(ii, 5);
        if (uuu==". ...") jj=1;
      }
    }  
    bb=2*(bb-1)+jj;
    this.SetPgnMoveText(uu, vv, rroot, bb);
  }
  else this.SetPgnMoveText(uu);
  return(vv);
}
PGNGame.prototype.EvalMove = function(ii, ttype0, xx0, yy0, ttype1, xx1, yy1, ccapt, sstore)
{
  var ddx, ddy, xx, yy, jj=-1, ttype2=-1, xx2=xx1, yy2=xx1, ttype3=-1, xx3=-1, yy3=-1, ff;
  if (ttype0==6) //O-O-O with Chess960 rules
  {
    if (this.Castling[this.MoveType][1]==0) return(false);
    if (this.PieceMoves[this.MoveType][0]>0) return(false);
    jj=0;
    while (jj<16)
    {
      if ((this.PiecePosX[this.MoveType][jj]<this.PiecePosX[this.MoveType][0])&&
          (this.PiecePosY[this.MoveType][jj]==this.MoveType*7)&&
          (this.PieceType[this.MoveType][jj]==2))
        jj+=100;
      else jj++;
    }
    if (jj==16) return(false);
    jj-=100;
    if (this.PieceMoves[this.MoveType][jj]>0) return(false);
    this.Board[this.PiecePosX[this.MoveType][0]][this.MoveType*7]=0;
    this.Board[this.PiecePosX[this.MoveType][jj]][this.MoveType*7]=0;
    ff=this.PiecePosX[this.MoveType][jj];
    if (ff>2) ff=2;
    while ((ff<this.PiecePosX[this.MoveType][0])||(ff<=3))
    {
      if (this.Board[ff][this.MoveType*7]!=0)
      {
        this.Board[this.PiecePosX[this.MoveType][0]][this.MoveType*7]=1-2*this.MoveType;
        this.Board[this.PiecePosX[this.MoveType][jj]][this.MoveType*7]=(1-2*this.MoveType)*3;
        return(false);
      }
      ff++;
    }
    this.Board[this.PiecePosX[this.MoveType][0]][this.MoveType*7]=1-2*this.MoveType;
    this.Board[this.PiecePosX[this.MoveType][jj]][this.MoveType*7]=(1-2*this.MoveType)*3;  
    if (this.StoreMove(0, 0, 2, this.MoveType*7, jj, 2, 3, this.MoveType*7, sstore))
      return(true);
    return(false);
  }
  if (ttype0==7) //O-O with Chess960 rules
  {
    if (this.Castling[this.MoveType][0]==0) return(false);
    if (this.PieceMoves[this.MoveType][0]>0) return(false);
    jj=0;
    while (jj<16)
    { 
      if ((this.PiecePosX[this.MoveType][jj]>this.PiecePosX[this.MoveType][0])&&
          (this.PiecePosY[this.MoveType][jj]==this.MoveType*7)&&
          (this.PieceType[this.MoveType][jj]==2))
        jj+=100;
      else jj++;
    }
    if (jj==16) return(false);
    jj-=100;
    if (this.PieceMoves[this.MoveType][jj]>0) return(false);
    this.Board[this.PiecePosX[this.MoveType][0]][this.MoveType*7]=0;
    this.Board[this.PiecePosX[this.MoveType][jj]][this.MoveType*7]=0;
    ff=this.PiecePosX[this.MoveType][jj];
    if (ff<6) ff=6;
    while ((ff>this.PiecePosX[this.MoveType][0])||(ff>=5))
    {
      if (this.Board[ff][this.MoveType*7]!=0)
      {
        this.Board[this.PiecePosX[this.MoveType][0]][this.MoveType*7]=1-2*this.MoveType;
        this.Board[this.PiecePosX[this.MoveType][jj]][this.MoveType*7]=(1-2*this.MoveType)*3;
        return(false);
      }
      ff--;
    }
    this.Board[this.PiecePosX[this.MoveType][0]][this.MoveType*7]=1-2*this.MoveType;
    this.Board[this.PiecePosX[this.MoveType][jj]][this.MoveType*7]=(1-2*this.MoveType)*3;      
    if (this.StoreMove(0, 0, 6, this.MoveType*7, jj, 2, 5, this.MoveType*7, sstore))
      return(true);
    return(false);
  }
  if (ttype0==8) // NullMove
  {
    if (this.StoreMove(0, 0, this.PiecePosX[this.MoveType][0], this.PiecePosY[this.MoveType][0], -1, -1, -1, -1, sstore))
      return(true);
    return(false);
  }  
  if ((this.PiecePosX[this.MoveType][ii]==xx1)&&(this.PiecePosY[this.MoveType][ii]==yy1))
    return(false);
  if ((ccapt==0)&&(this.Board[xx1][yy1]!=0))
    return(false);
  if ((ccapt>0)&&(sign(this.Board[xx1][yy1])!=(2*this.MoveType-1)))
  {
    if ((ttype0!=5)||(this.CanPass!=xx1)||(yy1!=5-3*this.MoveType))
      return(false);
  }
  if ((xx0>=0)&&(xx0!=this.PiecePosX[this.MoveType][ii])) return(false);
  if ((yy0>=0)&&(yy0!=this.PiecePosY[this.MoveType][ii])) return(false);
  if (ttype0==0)
  {
    if (Math.abs(this.PiecePosX[this.MoveType][ii]-xx1)>1) return(false);
    if (Math.abs(this.PiecePosY[this.MoveType][ii]-yy1)>1) return(false);
  }
  if (ttype0==1)
  {
    if ((Math.abs(this.PiecePosX[this.MoveType][ii]-xx1)!=Math.abs(this.PiecePosY[this.MoveType][ii]-yy1))&&
        ((this.PiecePosX[this.MoveType][ii]-xx1)*(this.PiecePosY[this.MoveCount%2][ii]-yy1)!=0))
      return(false);
  }
  if (ttype0==2)
  { 
    if ((this.PiecePosX[this.MoveType][ii]-xx1)*(this.PiecePosY[this.MoveType][ii]-yy1)!=0)
      return(false);
  }
  if (ttype0==3)
  {
    if (Math.abs(this.PiecePosX[this.MoveType][ii]-xx1)!=Math.abs(this.PiecePosY[this.MoveType][ii]-yy1))
      return(false);
  }
  if (ttype0==4)
  {
    if (Math.abs(this.PiecePosX[this.MoveType][ii]-xx1)*Math.abs(this.PiecePosY[this.MoveType][ii]-yy1)!=2)
      return(false);
  }
  if ((ttype0==1)||(ttype0==2)||(ttype0==3))
  {
    ddx=sign(xx1-this.PiecePosX[this.MoveType][ii]);
    ddy=sign(yy1-this.PiecePosY[this.MoveType][ii]);
    xx=this.PiecePosX[this.MoveType][ii]+ddx;
    yy=this.PiecePosY[this.MoveType][ii]+ddy;
    while ((xx!=xx1)||(yy!=yy1))
    {
      if (this.Board[xx][yy]!=0) return(false);
      xx+=ddx;
      yy+=ddy;
    }
  }
  if (ttype0==5)
  {
    if (Math.abs(this.PiecePosX[this.MoveType][ii]-xx1)!=ccapt) return(false);
    if ((yy1==7*(1-this.MoveType))&&(ttype0==ttype1)) return(false);
    if (ccapt==0)
    {
      if (this.PiecePosY[this.MoveType][ii]-yy1==4*this.MoveType-2)
      {
        if (this.PiecePosY[this.MoveType][ii]!=1+5*this.MoveType) return(false);
        if (this.Board[xx1][yy1+2*this.MoveType-1]!=0) return(false);
      }
      else
      {
        if (this.PiecePosY[this.MoveType][ii]-yy1!=2*this.MoveType-1) return(false);
      }
    }
    else
    {
      if (this.PiecePosY[this.MoveType][ii]-yy1!=2*this.MoveType-1) return(false);
    }
  }
  if (ttype1!=ttype0)
  {
    if (ttype0!=5) return(false);
    if (ttype1>=5) return(false);
    if (yy1!=7-7*this.MoveType) return(false);
  }
  if ((ttype0<=5)&&(ccapt>0))
  {
    jj=15;
    while ((jj>=0)&&(ttype3<0))
    {
      if ((this.PieceType[1-this.MoveType][jj]>0)&&
          (this.PiecePosX[1-this.MoveType][jj]==xx1)&&
          (this.PiecePosY[1-this.MoveType][jj]==yy1))
        ttype3=this.PieceType[1-this.MoveType][jj];
      else
        jj--;
    }
    if ((ttype3==-1)&&(ttype0==5)&&(this.CanPass>=0))
    {
      jj=15;
      while ((jj>=0)&&(ttype3<0))
      {
        if ((this.PieceType[1-this.MoveType][jj]==5)&&
            (this.PiecePosX[1-this.MoveType][jj]==xx1)&&
            (this.PiecePosY[1-this.MoveType][jj]==yy1-1+2*this.MoveType))
          ttype3=this.PieceType[1-this.MoveType][jj];
        else
          jj--;
      }
    }
    ttype3=-1;
  }  
  if (this.StoreMove(ii, ttype1, xx1, yy1, jj, ttype3, xx3, yy3, sstore))
    return(true);
  return(false);
}
PGNGame.prototype.GetHTMLMoveText = function(vvariant)
{
  var vv=0, tt, ii, uu="", uuu="", cc, bb=0, bbb=0;
  var ss="", sstart=0, nn=MaxMove, ffst=0,llst,ssearch,ssub,ffull,mmove0="",mmove1="", gg="";
  if (this.StartAnchor!=-1) gg=",'"+this.StartAnchor+"'";
  if (vvariant) 
  {
    vv=vvariant;
    if (! isNaN(this.ShortPgnMoveText[0][vv]))
    {
      this.SetMove(this.ShortPgnMoveText[0][vv], this.ShortPgnMoveText[1][vv]);  
      if (this.MoveCount!=this.ShortPgnMoveText[0][vv]) return("("+this.ShortPgnMoveText[0][vv]+")");
      this.CurVar=this.ShortPgnMoveText[1][vv];
      return(GetDiagram());
    }  
    if (this.ShortPgnMoveText[2][vv]<0) return(this.ShortPgnMoveText[0][vv]);
    this.SetMove(this.ShortPgnMoveText[2][vv], this.ShortPgnMoveText[1][vv]);
    if (this.MoveCount!=this.ShortPgnMoveText[2][vv]) return(this.ShortPgnMoveText[0][vv]);
    this.CurVar=vvariant;
  }  
  else this.MoveBack(MaxMove);
  tt=this.ShortPgnMoveText[0][vv];
  ffull=Uncomment(this.ShortPgnMoveText[0][this.CurVar]);
  for (ii=0; (ii<nn)&&(ffst>=0)&&(this.MoveCount<MaxMove); ii++)
  {
    ssearch=Math.floor(this.MoveCount/2+2)+".";
    llst=ffull.indexOf(ssearch);
    ssearch=Math.floor(this.MoveCount/2+1)+".";
    ffst=ffull.indexOf(ssearch);
    if (ffst>=0)
    {
      ffst+=ssearch.length;
      if (llst<0)
        ssub=ffull.substring(ffst);
      else
        ssub=ffull.substring(ffst, llst);
      mmove0=GetMove(ssub,this.MoveType);
      if (mmove0!="")
      {
        if (this.ParseMove(mmove0, true)>0)
        {
          mmove1=mmove0;
          if (this.MoveType==0)
            this.HistMove[this.MoveCount-this.StartMove]=Math.floor((this.MoveCount+2)/2)+"."+mmove1;
          else
            this.HistMove[this.MoveCount-this.StartMove]=Math.floor((this.MoveCount+2)/2)+". ... "+mmove1;
          this.MoveCount++;
          this.MoveType=1-this.MoveType;
        }  
        else
        { if (this.MoveType==1)
          {
            ssub=Math.floor(this.MoveCount/2+1);
            ssearch=ssub+"....";
            ffst=ffull.indexOf(ssearch);
            if (ffst<0) { ssearch=ssub+". ..."; ffst=ffull.indexOf(ssearch); }
            if (ffst<0) { ssearch=ssub+". .."; ffst=ffull.indexOf(ssearch); }
            if (ffst<0) { ssearch=ssub+" ..."; ffst=ffull.indexOf(ssearch); }
            if (ffst<0) { ssearch=ssub+"..."; ffst=ffull.indexOf(ssearch); }
            if (ffst<0)
            {
              ssearch=ssub+" ..";
              ffst=ffull.indexOf(ssearch);
            }
            if (ffst>=0) 
            {
              ffst+=ssearch.length;
              if (llst<0) ssub=ffull.substring(ffst);
              else ssub=ffull.substring(ffst, llst);
              mmove0=GetMove(ssub,0);
              if (mmove0!="")
              {
                if (this.ParseMove(mmove0, true)>0)
                {
                  mmove1=mmove0;
                  this.HistMove[this.MoveCount-this.StartMove]=Math.floor((this.MoveCount+2)/2)+". ... "+mmove1;
                  this.MoveCount++;
                  this.MoveType=1-this.MoveType;
                }  
                else
                {
                  ffst=-1;
                }
              }
            }
          }
          else
          {
            ffst=-1;
          }
        }
      }
      else ffst=-1;
    }
    if (mmove1!="")
    {
      sstart=-1;
      do sstart=tt.indexOf(mmove1, sstart+1);
      while ((sstart>0)&&(IsInComment(tt, sstart)));
      if (sstart>=0)
      {
      	ss+=tt.substr(0,sstart);
        ss+='<a href="javascript:'+this.VarName+'.SetMove{{'+this.MoveCount+','+vv+gg+'}}" name="'+this.MoveName(vv)+'"';
        if (vv==0) ss+=' class="ml"';
        ss+='>'+mmove1+'</a>';
        tt=tt.substr(sstart+mmove1.length);
      }
      else ffst=-1;
    }
  }
  ss+=tt;

  var ll=ss.length;
  for (ii=0; ii<ll; ii++)  
  {
    cc=ss.substr(ii,1);
    if (cc=="{") bbb++;
    if (cc=="}") bbb--; 
    if (((cc==")")||(cc=="]"))&&(bbb==0)) 
    {
      bb--;
      if (bb==0)
      {
        if (bbb==0)
        {
          if (! isNaN(this.ShortPgnMoveText[0][uuu]))
          {
            cc=uu.length-1;
            uu=uu.substr(0,cc);
            cc="";
          }
          uu+=this.GetHTMLMoveText(uuu);
        }
        else uu+=uuu;
        uuu="";
      }  
    }  
    if (bb==0) uu+=cc;
    else uuu+=cc;
    if (((cc=="(")||(cc=="["))&&(bbb==0)) bb++; 
  }  
  if (! vvariant) 
  {
    this.SetMove(0,0);
    tt=uu.split("{{");
    ll=tt.length;
    uu=tt[0];
    for (ii=1; ii<ll; ii++) uu+="("+tt[ii];
    tt=uu.split("}}");
    ll=tt.length;
    uu=tt[0];
    for (ii=1; ii<ll; ii++) uu+=")"+tt[ii];
    tt=uu.split("{");
    ll=tt.length;
    uu=tt[0];
    for (ii=1; ii<ll; ii++) uu+='<span class="pgncomment">'+tt[ii];
    tt=uu.split("}");
    ll=tt.length;
    uu=tt[0];
    for (ii=1; ii<ll; ii++) uu+="</span>"+tt[ii];    	
  }
  return(uu);
}
PGNGame.prototype.HighlightMove = function()
{
  var ii, cc, bb, jj=0, ll=this.TargetDocument.anchors.length;
  var nn = this.MoveName(this.CurVar);
  if (ll==0) return;
  if (! this.TargetDocument.anchors[0].style) return;
  if ((this.ActiveAnchor>=0)&&(ll>this.ActiveAnchor))
  {
    this.TargetDocument.anchors[this.ActiveAnchor].style.textDecoration='none';
    this.ActiveAnchor=-1;
  }
  if (isNaN(this.StartAnchor))
  {
    while ((jj<ll)&&(this.TargetDocument.anchors[jj].name!=this.StartAnchor)) jj++;
  }
  for (ii=jj; ((ii<ll)&&(this.ActiveAnchor<0)); ii++)
  {
    if (this.TargetDocument.anchors[ii].name==nn)
    {
      this.ActiveAnchor=ii;
      this.TargetDocument.anchors[this.ActiveAnchor].style.textDecoration='underline';
      return;
    }
  }
}
PGNGame.prototype.Init = function(FenString)
{
  var cc, ii, jj, kk, ll, mm, nn;
  if (FenString == '') FenString = StartFen;
  if (FenString == StartFen)
  {
    for (ii=0; ii<2; ii++)
    {
      this.PieceType[ii][0]=0;
      this.PiecePosX[ii][0]=4;
      this.PieceType[ii][1]=1;
      this.PiecePosX[ii][1]=3;
      this.PieceType[ii][6]=2;
      this.PiecePosX[ii][6]=0;
      this.PieceType[ii][7]=2;
      this.PiecePosX[ii][7]=7;
      this.PieceType[ii][4]=3;
      this.PiecePosX[ii][4]=2;
      this.PieceType[ii][5]=3;
      this.PiecePosX[ii][5]=5;
      this.PieceType[ii][2]=4;
      this.PiecePosX[ii][2]=1;
      this.PieceType[ii][3]=4;
      this.PiecePosX[ii][3]=6;
      for (jj=0; jj<8; jj++)
      {
        this.PieceType[ii][jj+8]=5;
        this.PiecePosX[ii][jj+8]=jj;
      }
      for (jj=0; jj<16; jj++)
      {
        this.PieceMoves[ii][jj]=0;
        this.PiecePosY[ii][jj]=(1-ii)*Math.floor(jj/8)+ii*(7-Math.floor(jj/8));
      }
    }
    for (ii=0; ii<8; ii++)
    {
      for (jj=0; jj<8; jj++) this.Board[ii][jj]=0;
    }
    for (ii=0; ii<2; ii++)
    {
      for (jj=0; jj<16; jj++) this.Board[this.PiecePosX[ii][jj]][this.PiecePosY[ii][jj]]=(this.PieceType[ii][jj]+1)*(1-2*ii);
    }
    for (ii=0; ii<2; ii++)
    {
      for (jj=0; jj<2; jj++) this.Castling[ii][jj]=1;
    }
    this.EnPass=-1;
    this.HalfMove[0]=0;
    this.StartMove=0;
    this.MoveCount=this.StartMove;
    this.MoveType=this.StartMove%2;
    this.CurVar=0;
    if (this.TargetDocument) this.HighlightMove();
  }
  else
  {
    for (ii=0; ii<2; ii++)
    {
      for (jj=0; jj<16; jj++)
      {
        this.PieceType[ii][jj]=-1;
        this.PiecePosX[ii][jj]=0;
        this.PiecePosY[ii][jj]=0;
        this.PieceMoves[ii][jj]=0;
      }
    }
    ii=0; jj=7; ll=0; nn=1; mm=1; cc=FenString.charAt(ll++);
    while (cc!=" ")
    {
      if (cc=="/")
      {
        if (ii!=8)
        {
          alert("Invalid FEN [1]: char "+ll+" in "+FenString);
          this.Init('');
          return;
        }
        ii=0;
        jj--;
      }
      if (ii==8) 
      {
        alert("Invalid FEN [2]: char "+ll+" in "+FenString);
        this.Init('');
        return;
      }
      if (! isNaN(cc))
      {
        ii+=parseInt(cc);
        if ((ii<0)||(ii>8))
        {
          alert("Invalid FEN [3]: char "+ll+" in "+FenString);
          this.Init('');
          return;
        }
      }
      if (cc.charCodeAt(0)==PieceName.toUpperCase().charCodeAt(0))
      {
        if (this.PieceType[0][0]!=-1)
        {
          alert("Invalid FEN [4]: char "+ll+" in "+FenString);
          this.Init('');
          return;
        }     
        this.PieceType[0][0]=0;
        this.PiecePosX[0][0]=ii;
        this.PiecePosY[0][0]=jj;
        ii++;
      }
      if (cc.charCodeAt(0)==PieceName.toLowerCase().charCodeAt(0))
      {
        if (this.PieceType[1][0]!=-1)
        {
          alert("Invalid FEN [5]: char "+ll+" in "+FenString);
          this.Init('');
          return;
        }  
        this.PieceType[1][0]=0;
        this.PiecePosX[1][0]=ii;
        this.PiecePosY[1][0]=jj;
        ii++;
      }
      for (kk=1; kk<6; kk++)
      {
        if (cc.charCodeAt(0)==PieceName.toUpperCase().charCodeAt(kk))
        {
          if (nn==16)
          {
            alert("Invalid FEN [6]: char "+ll+" in "+FenString);
            this.Init('');
            return;
          }          
          this.PieceType[0][nn]=kk;
          this.PiecePosX[0][nn]=ii;
          this.PiecePosY[0][nn]=jj;
          nn++;
          ii++;
        }
        if (cc.charCodeAt(0)==PieceName.toLowerCase().charCodeAt(kk))
        {
          if (mm==16)
          {
            alert("Invalid FEN [7]: char "+ll+" in "+FenString);
            this.Init('');
            return;
          }  
          this.PieceType[1][mm]=kk;
          this.PiecePosX[1][mm]=ii;
          this.PiecePosY[1][mm]=jj;
          mm++;
          ii++;
        }
      }
      if (ll<FenString.length) cc=FenString.charAt(ll++);
      else cc=" ";
    }
    if ((ii!=8)||(jj!=0))
    {
      alert("Invalid FEN [8]: char "+ll+" in "+FenString);
      this.Init('');
      return;
    }
    if ((this.PieceType[0][0]==-1)||(this.PieceType[1][0]==-1))
    {
      alert("Invalid FEN [9]: char "+ll+" missing king");
      this.Init('');
      return;
    }
    if (ll==FenString.length)
    {
      FenString+=" w ";
      FenString+=PieceName.toUpperCase().charAt(0);
      FenString+=PieceName.toUpperCase().charAt(1);
      FenString+=PieceName.toLowerCase().charAt(0);
      FenString+=PieceName.toLowerCase().charAt(1);      
      FenString+=" - 0 1";
      ll++;
    }
    cc=FenString.charAt(ll++);
    if ((cc=="w")||(cc=="b"))
    {
      if (cc=="w") this.StartMove=0;
      else this.StartMove=1;
    }
    else
    {
      alert("Invalid FEN [11]: char "+ll+" invalid active color");
      this.Init('');
      return;
    }
    ll++;
    if (ll>=FenString.length)
    {
      alert("Invalid FEN [12]: char "+ll+" missing castling availability");
      this.Init('');
      return;
    }
    this.Castling[0][0]=0; this.Castling[0][1]=0; this.Castling[1][0]=0; this.Castling[1][1]=0;
    cc=FenString.charAt(ll++);
    while (cc!=" ")
    {
      if (cc.charCodeAt(0)==PieceName.toUpperCase().charCodeAt(0)) this.Castling[0][0]=1; 
      if (cc.charCodeAt(0)==PieceName.toUpperCase().charCodeAt(1)) this.Castling[0][1]=1; 
      if (cc.charCodeAt(0)==PieceName.toLowerCase().charCodeAt(0)) this.Castling[1][0]=1; 
      if (cc.charCodeAt(0)==PieceName.toLowerCase().charCodeAt(1)) this.Castling[1][1]=1; 
      if (ll<FenString.length) cc=FenString.charAt(ll++);
      else cc=" ";
    }
    if (ll==FenString.length)
    {
      alert("Invalid FEN [13]: char "+ll+" missing en passant target square");
      this.Init('');
      return;
    }
    this.EnPass=-1;
    cc=FenString.charAt(ll++);
    while (cc!=" ")
    {
      if ((cc.charCodeAt(0)-97>=0)&&(cc.charCodeAt(0)-97<=7)) this.EnPass=cc.charCodeAt(0)-97; 
      if (ll<FenString.length) cc=FenString.charAt(ll++);
      else cc=" ";
    }
    if (ll==FenString.length)
    {
      alert("Invalid FEN [14]: char "+ll+" missing halfmove clock");
      this.Init('');
      return;
    }
    this.HalfMove[0]=0;
    cc=FenString.charAt(ll++);
    while (cc!=" ")
    {
      if (isNaN(cc))
      {
        alert("Invalid FEN [15]: char "+ll+" invalid halfmove clock");
        this.Init('');
        return;
      }
      this.HalfMove[0]=this.HalfMove[0]*10+parseInt(cc);
      if (ll<FenString.length) cc=FenString.charAt(ll++);
      else cc=" ";
    }
    if (ll==FenString.length)
    {
      alert("Invalid FEN [16]: char "+ll+" missing fullmove number");
      this.Init('');
      return;
    }
    cc=FenString.substring(ll++);
    if (isNaN(cc))
    {
      alert("Invalid FEN [17]: char "+ll+" invalid fullmove number");
      this.Init('');
      return;
    }
    if (cc<=0)
    {
      alert("Invalid FEN [18]: char "+ll+" invalid fullmove number");
      this.Init('');
      return;
    }
    this.StartMove+=2*(parseInt(cc)-1);
    for (ii=0; ii<8; ii++)
    {
      for (jj=0; jj<8; jj++) this.Board[ii][jj]=0;
    }
    for (ii=0; ii<2; ii++)
    {
      for (jj=0; jj<16; jj++)
      {
        if (this.PieceType[ii][jj]!=-1) this.Board[this.PiecePosX[ii][jj]][this.PiecePosY[ii][jj]]=(this.PieceType[ii][jj]+1)*(1-2*ii);
      }
    }
    this.MoveCount=this.StartMove;
    this.MoveType=this.StartMove%2;
    this.CurVar=0;
    if (this.TargetDocument) this.HighlightMove();
  }
}
PGNGame.prototype.InitImages = function()
{
  var ii, jj;
  this.BoardPic = new Image();
  this.BoardPic.src = this.ImagePath+"t.gif";
  this.PiecePic = new Array(2);
  for (i=0; i<2; i++) this.PiecePic[i] = new Array(6);
  for (ii=0; ii<2; ii++)
  {
    this.PiecePic[ii][0] = new Image(); this.PiecePic[ii][0].src = this.ImagePath+ColorName[ii]+"k.gif";
    this.PiecePic[ii][1] = new Image(); this.PiecePic[ii][1].src = this.ImagePath+ColorName[ii]+"q.gif";
    this.PiecePic[ii][2] = new Image(); this.PiecePic[ii][2].src = this.ImagePath+ColorName[ii]+"r.gif";
    this.PiecePic[ii][3] = new Image(); this.PiecePic[ii][3].src = this.ImagePath+ColorName[ii]+"b.gif";
    this.PiecePic[ii][4] = new Image(); this.PiecePic[ii][4].src = this.ImagePath+ColorName[ii]+"n.gif";
    this.PiecePic[ii][5] = new Image(); this.PiecePic[ii][5].src = this.ImagePath+ColorName[ii]+"p.gif";
  }
  this.DocImg=new Array();
}
PGNGame.prototype.IsCheck = function(xx, yy, tt)
{
  var ii0=xx, jj0=yy, ddi, ddj, bb;
  for (ddi=-2; ddi<=2; ddi+=4)
  {
    for (ddj=-1; ddj<=1; ddj+=2)
    {
      if (IsOnBoard(ii0+ddi, jj0+ddj))  
      {
        if (this.Board[ii0+ddi][jj0+ddj]==10*tt-5) return(1);
      }
    }
  }
  for (ddi=-1; ddi<=1; ddi+=2)
  {
    for (ddj=-2; ddj<=2; ddj+=4)
    {
      if (IsOnBoard(ii0+ddi, jj0+ddj)) 
      {
        if (this.Board[ii0+ddi][jj0+ddj]==10*tt-5) return(1);
      }
    }
  }
  for (ddi=-1; ddi<=1; ddi+=2)
  {
    ddj=1-2*tt;
    {
      if (IsOnBoard(ii0+ddi, jj0+ddj)) 
      {
        if (this.Board[ii0+ddi][jj0+ddj]==12*tt-6) return(1);
      }
    }
  }
  if ((Math.abs(this.PiecePosX[1-tt][0]-xx)<2)&&(Math.abs(this.PiecePosY[1-tt][0]-yy)<2)) 
    return(1);
  for (ddi=-1; ddi<=1; ddi+=1)
  {
    for (ddj=-1; ddj<=1; ddj+=1)
    {
      if ((ddi!=0)||(ddj!=0))
      {
        ii0=xx+ddi; 
        jj0=yy+ddj;
        bb=0;
        while ((IsOnBoard(ii0, jj0))&&(bb==0))
        {
          bb=this.Board[ii0][jj0];
          if (bb==0)
          {
            ii0+=ddi;
            jj0+=ddj;
          }
          else
          {
            if (bb==4*tt-2) return(1); 
            if ((bb==6*tt-3)&&((ddi==0)||(ddj==0))) return(1); 
            if ((bb==8*tt-4)&&(ddi!=0)&&(ddj!=0)) return(1); 
          }  
        }
      }
    }
  }
  return(0);
}
PGNGame.prototype.MoveBack = function(nn)
{
  var ii, jj, cc;
  for (jj=0; (jj<nn)&&(this.MoveCount>this.StartMove); jj++)
  {
    this.MoveCount--;
    this.MoveType=1-this.MoveType;
    cc=this.MoveCount-this.StartMove;
    ii=this.HistPiece[1][cc];
    if ((0<=ii)&&(ii<16)) //we must do this here because of Chess960 castling
    {
      this.Board[this.PiecePosX[this.MoveType][ii]][this.PiecePosY[this.MoveType][ii]]=0; 
      this.Board[this.HistPosX[1][cc]][this.HistPosY[1][cc]]=(this.HistType[1][cc]+1)*(1-2*this.MoveType);
    }
    ii=this.HistPiece[0][cc]; 
    this.Board[this.PiecePosX[this.MoveType][ii]][this.PiecePosY[this.MoveType][ii]]=0;
    this.Board[this.HistPosX[0][cc]][this.HistPosY[0][cc]]=(this.HistType[0][cc]+1)*(1-2*this.MoveType);
    this.PieceType[this.MoveType][ii]=this.HistType[0][cc];
    this.PiecePosX[this.MoveType][ii]=this.HistPosX[0][cc];
    this.PiecePosY[this.MoveType][ii]=this.HistPosY[0][cc];
    this.PieceMoves[this.MoveType][ii]--;
    ii=this.HistPiece[1][cc];
    if ((0<=ii)&&(ii<16))
    {
      this.PieceType[this.MoveType][ii]=this.HistType[1][cc];
      this.PiecePosX[this.MoveType][ii]=this.HistPosX[1][cc];
      this.PiecePosY[this.MoveType][ii]=this.HistPosY[1][cc];
      this.PieceMoves[this.MoveType][ii]--;
    }
    ii-=16;
    if (0<=ii)
    {
      this.Board[this.HistPosX[1][cc]][this.HistPosY[1][cc]]=(this.HistType[1][cc]+1)*(2*this.MoveType-1);
      this.PieceType[1-this.MoveType][ii]=this.HistType[1][cc];
      this.PiecePosX[1-this.MoveType][ii]=this.HistPosX[1][cc];
      this.PiecePosY[1-this.MoveType][ii]=this.HistPosY[1][cc];
      this.PieceMoves[1-this.MoveType][ii]--;
    }
    if (this.CurVar!=0)
    {
      if (this.MoveCount==this.ShortPgnMoveText[2][this.CurVar])
      {
        this.CurVar=this.ShortPgnMoveText[1][this.CurVar];
      }  
    }    
  }
  if (this.TargetDocument) this.HighlightMove();
  this.RefreshBoard();
  kb_focus = this;
}
PGNGame.prototype.MoveForward = function(nn, rr)
{
  var ii,ffst=0,llst,ssearch,ssub,ffull,mmove0="",mmove1="";
  ffull=Uncomment(this.ShortPgnMoveText[0][this.CurVar]);
  for (ii=0; (ii<nn)&&(ffst>=0)&&(this.MoveCount<MaxMove); ii++)
  {
    ssearch=Math.floor(this.MoveCount/2+2)+".";
    llst=ffull.indexOf(ssearch);
    ssearch=Math.floor(this.MoveCount/2+1)+".";
    ffst=ffull.indexOf(ssearch);
    if (ffst>=0)
    {
      ffst+=ssearch.length;
      if (llst<0) ssub=ffull.substring(ffst);
      else ssub=ffull.substring(ffst, llst);
      mmove0=GetMove(ssub,this.MoveType);
      if (mmove0!="")
      {
        if (this.ParseMove(mmove0, true)>0)
        {
          mmove1=mmove0;
          if (this.MoveType==0) this.HistMove[this.MoveCount-this.StartMove]=Math.floor((this.MoveCount+2)/2)+"."+mmove1;
          else this.HistMove[this.MoveCount-this.StartMove]=Math.floor((this.MoveCount+2)/2)+". ... "+mmove1;
          this.MoveCount++;
          this.MoveType=1-this.MoveType;
        }  
        else
        {
          if (this.MoveType==1)
          {
            ssub=Math.floor(this.MoveCount/2+1);
            ssearch=ssub+"....";
            ffst=ffull.indexOf(ssearch);
            if (ffst<0) { ssearch=ssub+". ..."; ffst=ffull.indexOf(ssearch); }
            if (ffst<0) { ssearch=ssub+". .."; ffst=ffull.indexOf(ssearch); }
            if (ffst<0) { ssearch=ssub+" ..."; ffst=ffull.indexOf(ssearch); }
            if (ffst<0) { ssearch=ssub+"..."; ffst=ffull.indexOf(ssearch); }            
            if (ffst<0) { ssearch=ssub+" .."; ffst=ffull.indexOf(ssearch); }
            if (ffst>=0) 
            {
              ffst+=ssearch.length;
              if (llst<0) ssub=ffull.substring(ffst);
              else ssub=ffull.substring(ffst, llst);
              mmove0=GetMove(ssub,0);
              if (mmove0!="")
              {
                if (this.ParseMove(mmove0, true)>0)
                {
                  mmove1=mmove0;
                  this.HistMove[this.MoveCount-this.StartMove]=Math.floor((this.MoveCount+2)/2)+". ... "+mmove1;
                  this.MoveCount++;
                  this.MoveType=1-this.MoveType;
                }  
                else ffst=-1;
              }
            }
          }
          else ffst=-1;
        }
      }
      else ffst=-1;
    }
  }
  if (this.TargetDocument) this.HighlightMove();
  this.RefreshBoard();
  kb_focus = this;
}
PGNGame.prototype.MoveName = function(vv)
{
  return this.VarName+'m'+this.MoveCount+'v'+vv;
}
PGNGame.prototype.ParseMove = function(mm, sstore)
{
  var ii, ffrom="", ccapt=0, ll, yy1i=-1;
  var ttype0=-1, xx0=-1, yy0=-1, ttype1=-1, xx1=-1, yy1=-1;
  if (this.MoveCount>this.StartMove)
  {
    this.CanPass=-1;
    ii=this.HistPiece[0][this.MoveCount-this.StartMove-1];
    if ((this.HistType[0][this.MoveCount-this.StartMove-1]==5)&&(Math.abs(this.HistPosY[0][this.MoveCount-this.StartMove-1]-this.PiecePosY[1-this.MoveType][ii])==2))
      this.CanPass=this.PiecePosX[1-this.MoveType][ii];
  }
  else this.CanPass=this.EnPass;
  ii=1;
  while (ii<mm.length)  
  {
    if (! isNaN(mm.charAt(ii)))
    {
      xx1=mm.charCodeAt(ii-1)-97;
      yy1=mm.charAt(ii)-1;
      yy1i=ii;
      ffrom=mm.substring(0, ii-1);
    }
    ii++;
  }
  if ((xx1<0)||(xx1>7)||(yy1<0)||(yy1>7))
  {
    if ((mm.indexOf("O")>=0)||(mm.indexOf("0")>=0))
    {
      if ((mm.indexOf("O-O-O")>=0)||(mm.indexOf("0-0-0")>=0)||(mm.indexOf("OOO")>=0)||(mm.indexOf("000")>=0)) 
      {
        if (this.EvalMove(ttype0, 6, xx0, yy0, ttype1, xx1, yy1, ccapt, sstore)) return(1);
        return(0);
      }
      if ((mm.indexOf("O-O")>=0)||(mm.indexOf("0-0")>=0)||(mm.indexOf("OO")>=0)||(mm.indexOf("00")>=0))
      {
        if (this.EvalMove(ttype0, 7, xx0, yy0, ttype1, xx1, yy1, ccapt, sstore)) return(1);
        return(0);
      }
      return(0);
    }
    if ((mm.indexOf("---")>=0)||(mm.indexOf("")>=0))
    {
      if (this.EvalMove(ttype0, 8, xx0, yy0, ttype1, xx1, yy1, ccapt, sstore)) return(1);
      return(0);
    }
    return(0);
  }
  ll=ffrom.length;
  ttype0=5;
  if (ll>0)
  {
    for (ii=0; ii<5; ii++)
    {
      if (ffrom.charCodeAt(0)==PieceCode[ii]) ttype0=ii;
    }
    if (ffrom.charAt(ll-1)=="x") ccapt=1;
    else
    {
      if ((ffrom.charAt(ll-1)=="-")||(ffrom.charAt(ll-1)=="")) ll--;
    }
    if (isNaN(mm.charAt(ll-1-ccapt)))
    {
      xx0=ffrom.charCodeAt(ll-1-ccapt)-97;
      if ((xx0<0)||(xx0>7)) xx0=-1;
    }
    else
    {
      yy0=ffrom.charAt(ll-1-ccapt)-1;
      if ((yy0<0)||(yy0>7)) yy0=-1;
    }
    if ((yy0>=0)&&(isNaN(mm.charAt(ll-2-ccapt)))) //Smith Notation
    {
      xx0=ffrom.charCodeAt(ll-2-ccapt)-97;
      if ((xx0<0)||(xx0>7)) xx0=-1;
      else
      {
        ttype0=Math.abs(this.Board[xx0][yy0])-1;
        if ((ttype0==0)&&(xx0-xx1>1))
        {
          if (this.EvalMove(ttype0, 6, xx0, yy0, -1, -1, -1, 0, sstore)) return(1);
          return(0);
        }  
        if ((ttype0==0)&&(xx1-xx0>1))
        {
          if (this.EvalMove(ttype0, 7, xx0, yy0, -1, -1, -1, 0, sstore)) return(1);
          return(0);
        }
      }
    }
  }
  if (this.Board[xx1][yy1]!=0) ccapt=1;
  else
  {
    if ((ttype0==5)&&(xx1==this.CanPass)&&(yy1==5-3*this.MoveType)) ccapt=1;
  }
  ttype1=ttype0;
  ii=mm.indexOf("=");
  if (ii<0) ii=yy1i;
  if ((ii>0)&&(ii<mm.length-1))
  {
    if (ttype0==5)
    {
      ii=mm.charCodeAt(ii+1);
      if (ii==PieceCode[1]) ttype1=1;
      if (ii==PieceCode[2]) ttype1=2;
      if (ii==PieceCode[3]) ttype1=3;
      if (ii==PieceCode[4]) ttype1=4;
    }  
  }
  if (sstore)
  {
    for (ii=0; ii<16; ii++)
    {
      if (this.PieceType[this.MoveType][ii]==ttype0)
      {
        if (this.EvalMove(ii, ttype0, xx0, yy0, ttype1, xx1, yy1, ccapt, true)) return(1);
      }
    }
  }
  else
  {
    ll=0
    for (ii=0; ii<16; ii++)
    {
      if (this.PieceType[this.MoveType][ii]==ttype0)
      {
        if (this.EvalMove(ii, ttype0, xx0, yy0, ttype1, xx1, yy1, ccapt, false)) ll++;
      }
    }
    return(ll);
  }    
  return(0);
}
PGNGame.prototype.RefreshBoard = function()
{
  var ii, jj;
  for (ii=0; ii<8; ii++)
  {
    for (jj=0; jj<8; jj++)
    {
      if (this.Board[ii][jj]==0)
      {
        if (this.isRotated)
          this.SetImg(63-ii-(7-jj)*8,this.BoardPic.src);
        else
          this.SetImg(ii+(7-jj)*8,this.BoardPic.src);
      }
    }
  }
  for (ii=0; ii<2; ii++)
  {
    for (jj=0; jj<16; jj++)
    {
      if (this.PieceType[ii][jj]>=0)
      {
        kk=this.PiecePosX[ii][jj]+8*(7-this.PiecePosY[ii][jj]);
        if (this.isRotated)
          this.SetImg(63-kk,this.PiecePic[ii][this.PieceType[ii][jj]].src);  
        else
          this.SetImg(kk,this.PiecePic[ii][this.PieceType[ii][jj]].src);
      }
    }
  }
}
PGNGame.prototype.RotateBoard = function()
{
  this.isRotated = this.isRotated ? false : true;
  this.RefreshBoard();
  kb_focus = this;
}
PGNGame.prototype.SetImg = function(ii,ss)
{
  if (this.DocImg[ii]==ss) return;
  this.DocImg[ii]=ss;
  if (ii<64) document.images[ii+this.ImageOffset].src=ss;
  else document.images[ii].src=ss;
}
PGNGame.prototype.SetMove = function(mmove, vvariant)
{
  if (isNaN(mmove)) return;
  if (vvariant)
  {
    if (vvariant>=this.ShortPgnMoveText[0].length) return;
    if (this.CurVar!=vvariant) 
    {
      this.SetMove(this.ShortPgnMoveText[2][vvariant], this.ShortPgnMoveText[1][vvariant]);
      this.CurVar=vvariant;
    }  
  }
  else
  {
    while (this.CurVar!=0)
    {
      if (this.MoveCount==this.ShortPgnMoveText[2][this.CurVar])
      {
        this.CurVar=this.ShortPgnMoveText[1][this.CurVar];
      }  
      else this.MoveBack(1);
    }
  }  
  var dd=mmove-this.MoveCount;
  if (dd<=0) this.MoveBack(-dd);
  else this.MoveForward(dd, 1);
}
PGNGame.prototype.SetPgnMoveText = function(ss, vvariant, rroot, sstart)
{
  if (vvariant)
  {
    this.ShortPgnMoveText[0][vvariant]=ss;
    this.ShortPgnMoveText[1][vvariant]=rroot;
    this.ShortPgnMoveText[2][vvariant]=sstart;
  }
  else this.ShortPgnMoveText[0][0]=ss;
}
PGNGame.prototype.StoreMove = function(ii, ttype1, xx1, yy1, jj, ttype3, xx3, yy3, sstore)
{
  var iis_check=0, ll, cc=this.MoveCount-this.StartMove, ff=this.PiecePosX[this.MoveType][0], dd=0;
  if ((ttype1==5)||((jj>=0)&&(ttype3<0)))
    this.HalfMove[cc+1]=0;
  else
    this.HalfMove[cc+1]=this.HalfMove[cc]+1;
  this.HistPiece[0][cc] = ii;
  this.HistType[0][cc] = this.PieceType[this.MoveType][ii];
  this.HistPosX[0][cc] = this.PiecePosX[this.MoveType][ii];
  this.HistPosY[0][cc] = this.PiecePosY[this.MoveType][ii];
  if (jj<0) 
    this.HistPiece[1][cc] = -1;
  else
  {
    if (ttype3>=0)
    {
      this.HistPiece[1][cc] = jj;
      this.HistType[1][cc] = this.PieceType[this.MoveType][jj];
      this.HistPosX[1][cc] = this.PiecePosX[this.MoveType][jj];
      this.HistPosY[1][cc] = this.PiecePosY[this.MoveType][jj];
    }
    else
    {
      this.HistPiece[1][cc] = 16+jj;
      this.HistType[1][cc] = this.PieceType[1-this.MoveType][jj];
      this.HistPosX[1][cc] = this.PiecePosX[1-this.MoveType][jj];
      this.HistPosY[1][cc] = this.PiecePosY[1-this.MoveType][jj];
    }
  }
  
  this.Board[this.PiecePosX[this.MoveType][ii]][this.PiecePosY[this.MoveType][ii]]=0;
  if (jj>=0)
  {
    if (ttype3<0)
      this.Board[this.PiecePosX[1-this.MoveType][jj]][this.PiecePosY[1-this.MoveType][jj]]=0;
    else
      this.Board[this.PiecePosX[this.MoveType][jj]][this.PiecePosY[this.MoveType][jj]]=0;
  }
  this.PieceType[this.MoveType][ii]=ttype1;
  if ((this.PiecePosX[this.MoveType][ii]!=xx1)||(this.PiecePosY[this.MoveType][ii]!=yy1)||(jj>=0))
  {
    this.PieceMoves[this.MoveType][ii]++;
    dd++;
  }
  this.PiecePosX[this.MoveType][ii]=xx1;
  this.PiecePosY[this.MoveType][ii]=yy1;
  if (jj>=0)
  {
    if (ttype3<0)
    {
      this.PieceType[1-this.MoveType][jj]=ttype3;
      this.PieceMoves[1-this.MoveType][jj]++;
    }
    else
    {
      this.PiecePosX[this.MoveType][jj]=xx3;
      this.PiecePosY[this.MoveType][jj]=yy3;
      this.PieceMoves[this.MoveType][jj]++;
    }
  }
  if (jj>=0)
  {
    if (ttype3<0)
      this.Board[this.PiecePosX[1-this.MoveType][jj]][this.PiecePosY[1-this.MoveType][jj]]=0;    
    else
      this.Board[this.PiecePosX[this.MoveType][jj]][this.PiecePosY[this.MoveType][jj]]=(this.PieceType[this.MoveType][jj]+1)*(1-2*this.MoveType);
  }
  this.Board[this.PiecePosX[this.MoveType][ii]][this.PiecePosY[this.MoveType][ii]]=(this.PieceType[this.MoveType][ii]+1)*(1-2*this.MoveType);

  if ((ttype1==0)&&(ttype3==2)) //O-O-O, O-O
  {
    while (ff>xx1) 
    {
      iis_check+=this.IsCheck(ff, this.MoveType*7, this.MoveType);
      ff--;      
    }
    while (ff<xx1) 
    {
      iis_check+=this.IsCheck(ff, this.MoveType*7, this.MoveType);
      ff++;      
    } 
  }
  iis_check+=this.IsCheck(this.PiecePosX[this.MoveType][0], this.PiecePosY[this.MoveType][0], this.MoveType);

  if ((iis_check==0)&&(sstore)) return(true);

  this.Board[this.PiecePosX[this.MoveType][ii]][this.PiecePosY[this.MoveType][ii]]=0;
  this.Board[this.HistPosX[0][cc]][this.HistPosY[0][cc]]=(this.HistType[0][cc]+1)*(1-2*this.MoveType);
  this.PieceType[this.MoveType][ii]=this.HistType[0][cc];
  this.PiecePosX[this.MoveType][ii]=this.HistPosX[0][cc];
  this.PiecePosY[this.MoveType][ii]=this.HistPosY[0][cc];
  this.PieceMoves[this.MoveType][ii]-=dd;
  if (jj>=0)   
  {
    if (ttype3>=0)
    {
      this.Board[this.PiecePosX[this.MoveType][jj]][this.PiecePosY[this.MoveType][jj]]=0;
      this.Board[this.HistPosX[1][cc]][this.HistPosY[1][cc]]=(this.HistType[1][cc]+1)*(1-2*this.MoveType);
      this.PieceType[this.MoveType][jj]=this.HistType[1][cc];
      this.PiecePosX[this.MoveType][jj]=this.HistPosX[1][cc];
      this.PiecePosY[this.MoveType][jj]=this.HistPosY[1][cc];
      this.PieceMoves[this.MoveType][jj]--;
    }
    else
    {
      this.Board[this.HistPosX[1][cc]][this.HistPosY[1][cc]]=(this.HistType[1][cc]+1)*(2*this.MoveType-1);
      this.PieceType[1-this.MoveType][jj]=this.HistType[1][cc];
      this.PiecePosX[1-this.MoveType][jj]=this.HistPosX[1][cc];
      this.PiecePosY[1-this.MoveType][jj]=this.HistPosY[1][cc];
      this.PieceMoves[1-this.MoveType][jj]--;
    }
  }
  if (iis_check==0) return(true);
  return(false); 
}

// Utilities (not class methods).
function sign(nn)
{
  if (nn>0) return(1);
  if (nn<0) return(-1);
  return(0);
}
function GetMove(tt,nn)
{
  var ii=0, jj=0, mm="", ll=-1, cc, ss=tt;
  while (ss.indexOf("<br />")>0) ss=ss.replace("<br />","");
  var kk=ss.length;
  while (ii<kk)
  {
    cc=ss.charCodeAt(ii);
    if ((cc<=32))
    {
      if (ll+1!=ii) jj++;
      ll=ii;
    }
    else
    {
      if (jj==nn) 
      {
        if ((cc==46)&&(!isNaN(mm))) { mm=""; ll=ii; }
      	else mm+=ss.charAt(ii);
      }
    }    
    ii++;
  }
  if ((nn==1)&&(mm=="")&&(ss.charAt(0)=="."))
  {
    ii=0;
    while (ii<kk)
    {
      cc=ss.charAt(ii);
      if ((cc!=".")&&(cc!=" ")) mm+=cc;
      ii++;
    }
  }
  return(mm);
}
function IsInComment(ss, nn)
{
  var ii=-1, bb=0;
  do { ii=ss.indexOf("{",ii+1); bb++; }  
  while ((ii>=0)&&(ii<nn));
  ii=-1;
  do { ii=ss.indexOf("}",ii+1); bb--; }  
  while ((ii>=0)&&(ii<nn));  
  return(bb);
}
function IsOnBoard(ii, jj)
{
  if (ii<0) return(false);
  if (ii>7) return(false);
  if (jj<0) return(false);
  if (jj>7) return(false);
  return(true);
}
function Uncomment(ss)
{
  if (! ss) return(ss);
  var ii, jj, llist=ss.split("{"), ll=llist.length, uu=llist[0], tt, kk;
  for (ii=1; ii<ll; ii++)
  {
    tt=llist[ii];
    jj=tt.indexOf("}")+1;
    if (jj>0) uu+=tt.substring(jj);
  }
  llist=uu.split("$");
  ll=llist.length;
  uu=llist[0];
  for (ii=1; ii<ll; ii++)
  {
    tt=llist[ii];
    kk=tt.length;
    for (jj=0; jj<kk; jj++)
    {
      if (isNaN(parseInt(tt.charAt(jj))))
      {
        uu+=tt.substring(jj);
        jj=kk;
      }
    }    
  }
  return(uu);
}

// An event listerner for keystrokes that
// control the game with the keyboard focus.
function PGNOnKeyDown(evt)
{
  if (!kb_focus) return;
  var e = evt || window.event;
  if (!e) return;
  var keyCode = null;
  if (e.keyCode) keyCode = e.keyCode;
  else if (typeof(e.which) != 'undefined' && e.type.indexOf('key')!=-1) keyCode = e.which;
  switch (keyCode)
  {
    case 39: // right arrow
      kb_focus.MoveForward(1);
      break;
    case 37: // left arrow
      kb_focus.MoveBack(1);
      break;
  }
}

// Register an event listener.
window.onload = function()
{
  if (document.addEventListener)
  {
    // W3C
    document.addEventListener('keydown',PGNOnKeyDown,false);
  }
  else if (document.attachEvent)
  {
    // Microsoft
    document.attachEvent('onkeydown',PGNOnKeyDown);
  }
  else
  {
    // Older
    eval('document.onkeydown=PGNOnKeyDown');
  }
}

