// addressScrambler.js version 0.2
// copyright 2001, Josiah Q. Hamilton

// This software is provided under the Artistic license of the Open 
//  Source Initiative, as it exists on 2001-12-19, including the optional
//  provision regarding aggregation with a commercial distribution.
// This notice must be included with any distribution.

// The offset determines what the ascii values of the scrambled
// text will be shifted to.  It may be that, in the future, more
// sophisticated scrambling algorithms will be needed -- for now,
// a simple ascii offset is used.  If you are using a server side
// component to scramble the addresses on their way out of the server, 
// you must be using the same algorithm as this javascript uses to 
// unscramble them, and for this one, you must have the same offset value

var scrambleOffset = 5;


// This array holds the visible ascii character set
// it may be that Unicode would be better, but this version
// uses ascii.  Characters outside this range are basically
// ignored.

var asciicode = new Array();
asciicode[32] = " ";
asciicode[33] = "!";
asciicode[34] = "\"";
asciicode[35] = "#";
asciicode[36] = "$";
asciicode[37] = "%";
asciicode[38] = "&";
asciicode[39] = "'";
asciicode[40] = "(";
asciicode[41] = ")";
asciicode[42] = "*";
asciicode[43] = "+";
asciicode[44] = ",";
asciicode[45] = "-";
asciicode[46] = ".";
asciicode[47] = "/";
asciicode[48] = "0";
asciicode[49] = "1";
asciicode[50] = "2";
asciicode[51] = "3";
asciicode[52] = "4";
asciicode[53] = "5";
asciicode[54] = "6";
asciicode[55] = "7";
asciicode[56] = "8";
asciicode[57] = "9";
asciicode[58] = ":";
asciicode[59] = ";";
asciicode[60] = "<";
asciicode[61] = "=";
asciicode[62] = ">";
asciicode[63] = "?";
asciicode[64] = "@";
asciicode[65] = "A";
asciicode[66] = "B";
asciicode[67] = "C";
asciicode[68] = "D";
asciicode[69] = "E";
asciicode[70] = "F";
asciicode[71] = "G";
asciicode[72] = "H";
asciicode[73] = "I";
asciicode[74] = "J";
asciicode[75] = "K";
asciicode[76] = "L";
asciicode[77] = "M";
asciicode[78] = "N";
asciicode[79] = "O";
asciicode[80] = "P";
asciicode[81] = "Q";
asciicode[82] = "R";
asciicode[83] = "S";
asciicode[84] = "T";
asciicode[85] = "U";
asciicode[86] = "V";
asciicode[87] = "W";
asciicode[88] = "X";
asciicode[89] = "Y";
asciicode[90] = "Z";
asciicode[91] = "[";
asciicode[92] = "\\";
asciicode[93] = "]";
asciicode[94] = "^";
asciicode[95] = "_";
asciicode[96] = "`";
asciicode[97] = "a";
asciicode[98] = "b";
asciicode[99] = "c";
asciicode[100] = "d";
asciicode[101] = "e";
asciicode[102] = "f";
asciicode[103] = "g";
asciicode[104] = "h";
asciicode[105] = "i";
asciicode[106] = "j";
asciicode[107] = "k";
asciicode[108] = "l";
asciicode[109] = "m";
asciicode[110] = "n";
asciicode[111] = "o";
asciicode[112] = "p";
asciicode[113] = "q";
asciicode[114] = "r";
asciicode[115] = "s";
asciicode[116] = "t";
asciicode[117] = "u";
asciicode[118] = "v";
asciicode[119] = "w";
asciicode[120] = "x";
asciicode[121] = "y";
asciicode[122] = "z";
asciicode[123] = "{";
asciicode[124] = "|";
asciicode[125] = "}";
asciicode[126] = "~";


// this function returns the ascii code for a given character
// or "0" if the character is not in the set represented by
// the array.
function getAsciiCode(theChar) {
  var i = 32;
  var ret = 0;
  var match = false;
  while (i < 127 && match != true) {
    if (asciicode[i] == theChar) { 
      ret = i;
    }
    i ++;
  }
  return ret;
}

// this function returns the character associated with a given
// ascii code, or an empty string if the code is not in the range
// of 32 through 126
function getCharacter(theCode) {
  var ret = "";
  if (theCode > 31 && theCode < 127) {
    ret = asciicode[theCode];
  }
  return ret;
}

// This "private" function holds the scrambling
// algorithm -- it uses the global variable scrambleOffset
// to determine the shift in ascii value
// The first argument is the text to be scrambled or unscrambled
// The second argument is boolean -- false if the text is to be
// scrambled or true if it is to be unscrambled 
function _scramble(inText,inverse) {
  var i = 0;
  var outText = "";
  var currentCode = 0;
  var newCode = 0;
  var offset = scrambleOffset;
  if (inverse == true) {
    offset = offset * -1;
  }
  while (i < inText.length) {
    currentCode = getAsciiCode(inText.charAt(i));
    if (currentCode != 0) {
      newCode = currentCode + offset;
      if (newCode > 126) {
        newCode = (newCode - 126) + 31;
      }
      if (newCode < 32) {
        newCode = 127 - (32 - newCode);
      }
    } else {
      newCode = 0;
    }
    outText += getCharacter(newCode);
    i++;
  }
  return outText;
}

// This function returns unscrambled text
// It takes scrambled text as an input
function descrambleText(inText) {
  var outText = _scramble(inText,true);
  return outText;
}


// This function returns scrambled text
// It takes unscrambled text as an input
function scrambleText(inText) {
  var outText = _scramble(inText,false);
  return outText;
}

function writeDescrambledAddress(scrambledAddress) {
  document.open();
  document.write(descrambleText(scrambledAddress));
  document.close();
}

// This "public" function takes a scrambled address 
// and a not-scrambled display text string
// and writes a mailto tag with them.  
// Note that the display text is not scrambled when you 
// use this function, so if the display text *is* 
// also the address, you should use the function
// writeMailTo instead, 
// and just use the scrambled address for the argument.
function writeMailToWithClearDisplayText(scrambledAddress, text) {
  document.open();
  document.write("<a href=\"mailto:" + descrambleText(scrambledAddress) + "\">" + text + "</a>");
  document.close();
}

// This "public" function takes a scrambled address *and* 
// scrambled display text, descrambles them both, and writes
// a mailto tag.  This is useful when you want to hide the display
// text from harvesters for some reason.  If you're simply using the
// address again as display text, it'll be easier to use the
// writeMailToUsingAddress function, which takes just one argument - the address 
function writeMailToWithScrambledDisplayText(scrambledAddress, scrambledText) {
  document.open();
  document.write("<a href=\"mailto:" + descrambleText(scrambledAddress) + "\">" + descrambleText(scrambledText) + "</a>");
  document.close();
}

// This "public" function writes a mailto tag using the
// address itself as the display value
function writeMailTo(scrambledAddress) {
  document.open();
  document.write("<a href=\"mailto:" + descrambleText(scrambledAddress) + "\">" + descrambleText(scrambledAddress) + "</a>");
  document.close();

}

// the following methods are only used by the helper pages

function getMailToWithClearDisplayText(scrambledAddress, text) {
  return("<a href=\\\"mailto:" + descrambleText(scrambledAddress) + "\\\">" + text + "</a>");
}

function getMailTo(scrambledAddress) {
  return("<a href=\\\"mailto:" + descrambleText(scrambledAddress) + "\\\">" + descrambleText(scrambledAddress) + "</a>");
}

function getMailToCode(scrambledAddress) {
  return ("<script language=\"JavaScript\">writeMailTo('" + scrambledAddress + "');</script>");
}

function getEscapedMailToCode(scrambledAddress) {
  return ("&lt;script language=&quot;JavaScript&quot&gt;writeMailTo('" + scrambledAddress + "');&lt;/script&gt;");
}

function getMailToCodeWithClearDisplayText(scrambledAddress, text) {
  return ("<script language=\"JavaScript\">writeMailToWithClearDisplayText('" + scrambledAddress + ",'" + text + "');</script>");
}

function getEscapedMailToCodeWithClearDisplayText(scrambledAddress, text) {
  return ("&lt;script language=&quot;JavaScript&quot&gt;writeMailToWithClearDisplayText('" + scrambledAddress + "','"+ text + "');&lt;/script&gt;");
}



function writeScrambledAddress(address) {
  document.open();
  document.write(scrambleText(address));
  document.close();
}

