// -------------------------
// Form Handling Routines

// This stretches out the list box for Navigator reloads
function StretchList()
{
  lastword = new Option( "******************************************************" );

  with( document.sl_form.sl_list )
  {
    options[length] = lastword;
  }
}

// Adds a word to the list
function AddWord()
{
  if( document.sl_form.sl_edit.value.length <= 0 )
    return;
  lastword = new Option( document.sl_form.sl_edit.value );

  with( document.sl_form.sl_list )
  {
    options[length] = lastword;
    options[length-1].selected = true;
  }
  document.sl_form.sl_edit.value = "";
  document.sl_form.sl_edit.focus();
}

// Removes the selected word from the list
function RemoveWord()
{
  with( document.sl_form.sl_list )
  {
    if( selectedIndex >= 0 )
      options[selectedIndex] = null;
    if( length > 0 )
      options[0].selected = true;
  }
}

// Resets the list
function ResetList()
{
  with( document.sl_form )
  {
    for(; sl_list.length > 0; )
    {
        sl_list.options[0] = null;
    }
    sl_title.value = "";
    sl_width.value = "5";
  }
}

// -------------------------
// Cloak Routines

// randomizes integers in array pointed to by aNumbers
// that is nSize numbers long
function RandArray( aNumbers , nSize )
{
    var i, nTemp;

    for( i = 0; i < ( nSize - 1 ); i++ )
    {
        nPlace = i + Math.floor( Math.random() * ( nSize - i ) );
        nTemp = aNumbers[i];
        aNumbers[i] = aNumbers[nPlace];
        aNumbers[nPlace] = nTemp;
    }
}

// displays the title on the new page
function DisplayTitle()
{
  return strDisplayTitle;
}

// displays the image on the new page
function DisplayImage()
{
  return strDisplayImage;
}

// displays the word list on the new page
function DisplayList()
{
  return strDisplayList;
}

// displays an 2-dimensional array of characters in a table on the new page
function DisplayCanvas()
{
  return strDisplayCanvas;
}

// displays a new window with the whole puzzle
function DisplayPage( nWidth, nHeight )
{
  var i,j;
  var s = "";

  // Title
  strDisplayTitle = document.sl_form.sl_title.value;

  // Image
  with( document.sl_form.sl_image )
  {
    strDisplayImage = '<img src="images/' + options[selectedIndex].text + '.gif" width="400" height="400">';
  }

  // List
  for( i = 0, strDisplayList="<tr>"; i < g_strShownList.length; i++ )
  {
    strDisplayList += '<td>' + g_strShownList[i] + '</td>';
    if( ( i % 2 ) == 1 )
      strDisplayList += '</tr>\n<tr>';
    else
      strDisplayList += '<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>';
  }
  strDisplayList += '</tr>\n';

  // Canvas
  for( i = 0, strDisplayCanvas = ""; i < nHeight; i++ )
  {
    strDisplayCanvas+= '<tr>\n';
    for( j = 0; j < nWidth; j++ )
    {
      strDisplayCanvas += '<td align="center">' + g_strCanvas[i][j] + '</td>\n';
    }
  }

  // Update window
  newWindow = window.open("mystery.htm", "mystery", "width=640,height=480,scrollbars=yes,resizable=yes,menubar=yes,toolbar=yes", true );

}

// initializes the canvas
function InitCanvas( nWidth, nHeight )
{
  var i, j;

  g_strCanvas.length = 0;
  for( i = 0; i < nHeight; i++ )
  {
    g_strCanvas[i] = new Array();
    for( j = 0; j < nWidth; j++ )
    {
      g_strCanvas[i][j] = ' ';
    }
  }
}

// backfills the spaces in the canvas with random characters
function BackFill( nWidth, nHeight )
{
  var i, j;

  var strAscii = new Array( "A","B","C","D","E","F","G","H","I","J","K","L","M",
                           "N","O","P","Q","R","S","T","U","V","W","X","Y","Z" );

  for( i = 0; i < nHeight; i++ )
    for( j = 0; j < nWidth; j++ )
    {
      if( ' ' == g_strCanvas[i][j] )
        g_strCanvas[i][j] = strAscii[ Math.floor( Math.random() * 26 ) ];
    }
}

// Prepares the word list to be hidden
function PreProcessList()
{
  var i, j;
  var nTo;
  var strTemp;

  // initialize list
  g_strHiddenList.length = 0;
  with( document.sl_form.sl_list )
  {
    for( i = 0; i < length; i++ )
    {
      g_strHiddenList[i] = options[i].text;
      g_strShownList[i] = options[i].text;
    }
  }

  for( i = 0; i < g_strHiddenList.length; i++ )
  {
    // strip off spaces
    for( nTo = 0; nTo >= 0; )
    {
      nTo = g_strHiddenList[i].indexOf( " " );
      if( nTo >= 0 )
      {
        strTemp = g_strHiddenList[i].substring( 0, nTo );
        if( nTo < ( g_strHiddenList[i].length - 1 ) )
          strTemp += g_strHiddenList[i].substring( nTo + 1, g_strHiddenList[i].length );
        g_strHiddenList[i] = strTemp;
      }
    }
    // capitalize
    g_strHiddenList[i] = g_strHiddenList[i].toUpperCase();
  }

  // sort list longest to shortest
  for( i = 0; i < g_strHiddenList.length; i++ )
    for( j = i + 1; j < g_strHiddenList.length; j++ )
      if( g_strHiddenList[j].length > g_strHiddenList[i].length )
      {
        strTemp = g_strHiddenList[i];
        g_strHiddenList[i] = g_strHiddenList[j];
        g_strHiddenList[j] = strTemp;
      }
}

// X Increment
function XInc( nDir )
{
  // To the right
  if( ( DIR_RIGHT == nDir ) ||
      ( DIR_RIGHT_UP == nDir ) ||
      ( DIR_RIGHT_DOWN == nDir ) )
    return 1;

  // To the left
  if( ( DIR_LEFT == nDir ) ||
      ( DIR_LEFT_UP == nDir ) ||
      ( DIR_LEFT_DOWN == nDir ) )
    return -1;

  // Up or down
  return 0;
}

// Y Increment
function YInc( nDir )
{
  // Down
  if( ( DIR_DOWN == nDir ) ||
      ( DIR_RIGHT_DOWN == nDir ) ||
      ( DIR_LEFT_DOWN == nDir ) )
    return 1;

  // Up
  if( ( DIR_UP == nDir ) ||
      ( DIR_RIGHT_UP == nDir ) ||
      ( DIR_LEFT_UP == nDir ) )
    return -1;

  // Left or right
  return 0;
}

// Does word fit starting at nX, nY
// in direction nDir (0 = left to right, rotate ccw)?
function WordFit( nWord, nX, nY, nWidth, nHeight, nDir )
{
  var i;
  var iX;
  var iY;
  var ch;
  var nWordSize = g_strHiddenList[nWord].length;

  // Check range
  if( ( nWordSize < 1 ) || ( nWordSize > nHeight ) )
    return false;
  if( ( nX < 0 ) || ( nX >= nWidth ) || ( nY < 0 ) || ( nY >= nHeight ) )
    return false;

  // Check horizontal space
  if( XInc( nDir ) == 1 )
  {
    if( ( nX + nWordSize ) > nWidth )
      return false;
  }
  else if( XInc( nDir ) == -1 )
  {
    if( ( nX - nWordSize ) < 0 )
      return false;
  }

  // Check vertical space
  if( YInc( nDir ) == -1 )
  {
    if( ( nY - nWordSize ) < 0 )
      return false;
  }
  else if( YInc( nDir ) == 1 )
  {
    if( ( nY + nWordSize ) > nHeight )
      return false;
  }

  // Check character overlap
  for( i = 0; i < nWordSize; i++ )
  {
    ch = g_strHiddenList[nWord].charAt(i);

    iX = nX + i * XInc( nDir );
    iY = nY + i * YInc( nDir );

    // Debug only
    if( ( iX < 0 ) || ( iX >= nWidth  ) ) alert( "X Index Error" );
    if( ( iY < 0 ) || ( iY >= nHeight ) ) alert( "Y Index Error" );
    if( typeof( g_strCanvas[iY] ) != "object" )
      alert( "g_strCanvas[] error: " + typeof( g_strCanvas[iY] ) + "@ " + iY );
    if( typeof( g_strCanvas[iY][iX] ) != "string" )
      alert( "g_strCanvas[][] error: " + typeof( g_strCanvas[iY][iX] ) + "@ " + iY + ", " + iX );

    if( ( g_strCanvas[iY][iX] != ' ' ) && ( g_strCanvas[iY][iX] != ch ) )
      return false;
  }

  // Stuff word
  for( i = 0; i < nWordSize; i++ )
  {
    iX = nX + i * XInc( nDir );
    iY = nY + i * YInc( nDir );
    g_strCanvas[iY][iX] = g_strHiddenList[nWord].charAt(i);
  }
  return true;
}

// hide list in canvas
function HideList( nWidth, nHeight )
{
  var i, j, k, n, bDone;
  var AnX = new Array();
  var AnY = new Array();
  var AnZ = new Array();

  // init random search arrays
  for( i = 0; i < nWidth; i++ )
    AnX[i] = i;
  for( i = 0; i < nHeight; i++ )
    AnY[i] = i;
  for( i = 0; i < DIR_MAX; i++ )
    AnZ[i] = i;
  RandArray( AnX, nWidth );
  RandArray( AnY, nHeight );
  RandArray( AnZ, DIR_MAX );

  // search
  for( n = 0; n < g_strHiddenList.length; n++ )
  {
    bDone = false;
    for( i = 0; ( i < nWidth ) && !bDone; i++ )
      for( j = 0; ( j < nHeight ) && !bDone; j++ )
        for( k = 0; ( k < DIR_MAX ) && !bDone; k++ )
          bDone = WordFit( n, AnX[i], AnY[j], nWidth, nHeight, AnZ[k] );
    if( !bDone )
      return false;
  }

  return true;
}

function Cloak()
{
  var i, nHeight, nWidth, nMinHeight;

  // Process list
  PreProcessList();

  // Determine initial height
  nMinHeight = Math.floor( document.sl_form.sl_width.value );
  nHeight = g_strHiddenList[0].length;
  if( nMinHeight > nHeight )
    nHeight = nMinHeight;
  else
    document.sl_form.sl_width.value = nHeight.toString();
    
  // Hide words
  for(; nHeight < MAX_HEIGHT; nHeight++ )
  {
    nWidth = Math.floor( nHeight * 1.25 );
    for( i = 0; i < 10; i++ )
    {
      InitCanvas( nWidth, nHeight );
      if( HideList( nWidth, nHeight ) )
      {
        BackFill( nWidth, nHeight );
        DisplayPage( nWidth, nHeight );
        return true;
      }
    }
  }

  // Couldn't create a puzzle even at MAX_HEIGHT
  alert( "Too many words!, Try again with less." );
  return false;
}
