// ----------------------------------------------------------------------------
// NAME         : gen.js
// VERSION      : 1.0
// DESCRIPTION  : Utility library of general functions
// DEPENDENCIES : date.js   1.0
// ----------------------------------------------------------------------------

// ----------------------------- Function List --------------------------------
//
// void   gen_updateDays (object monthlist, string days, int year = null,
//                        int startDay = null,
//                        int endDay = null);
// void   gen_makeItemSelected (object list, string item);
// string gen_makeOrdinal (int number);
// string get_toString (int number);
// bool   isblank(string s)
// bool   isemail(string s)
// bool   isphone(string s)
// string trim(string s)
// string trim_right(string s)
// string trim_left(string s)
// string trim_all(string s)         //Removes spaces within string
// string isValidCreditNum(string s)
// int    numOccursChar(char sub, string full) //Num occurs of sub in full
// string browserSniff(document theDoc)
//
// ----------------------------------------------------------------------------

//--------------------------- gen_updateDays ----------------------------------
// NAME       : gen_updateDays
// PARAMETERS : object monthlist
//              string daylist
//              int    year
//              int    startDay
//              int    endDay
// RETURNS    : undefined
// BEHAVIOUR  : Restricts the number of days available based upon selected
//              month plus specified start and end values.
//-----------------------------------------------------------------------------
function gen_updateDays (monthlist, days, year, startDay, endDay)
{
  var dd = eval ("monthlist.form." + days);
  var y, m, d;  // year, month, day

  m = parseInt (monthlist.options[monthlist.options.selectedIndex].value) - 1;

  var curDay = dd.options[dd.options.selectedIndex].value;
  if (m<0) return;

  if (year) {
    var yeardd = eval ("monthlist.form." + year);
    y = yeardd.options[yeardd.options.selectedIndex].value;
    if(y == '') {
      y = date_getCurrentYear();
      if (date_isItNextYear (m))
      y++;
    } else if (y < 50 ) {
      y = (y*1) + 2000;
    } else if (y<100) {
      y = (y*1) + 1900;
    }
  } else {
    y = date_getCurrentYear ();
    if (date_isItNextYear (m))
      y++;
  }

  // Set up start and end days of month
  if (startDay) {
    start = startDay;
  }
  else { 
    start = 1;
  }

  if (endDay) {
    end = endDay;
  }
  else {
    end = date_howManyDays (m, y);
  }

  var i = 0;

  while (start <= end) {
    var text = gen_makeOrdinal (start);
    var val = start;
    if (val < 10)
      val = "0" + val;

    if (i < dd.options.length) {      
      dd.options[i].text = text;
      dd.options[i].value = val;
    }
    else {
      dd.options[dd.length] = new Option (text, val, false, false);
    }

    start++;
    i++;
  }

  if (i < dd.length) {
    dd.length = i;
  }
  dd.selectedIndex = 0; // Default to first in list
  gen_makeItemSelected(dd,curDay);
}

//---------------------------- gen_makeItemSelected ---------------------------
// NAME       : gen_makeItemSelected
// PARAMETERS : object list
//              string item
// RETURNS    : undefined
// BEHAVIOUR  : Selects the option in the list with value equal to item
//-----------------------------------------------------------------------------
function gen_makeItemSelected(list, item) 
{
  for (var i=0; i<list.length; i++)
  {
    if (list.options[i].value == item)
    {
      list.selectedIndex = i;
      return;
    }
  }
}

//--------------------------- gen_makeOrdinal ---------------------------------
// NAME       : gen_makeOrdinal
// PARAMETERS : int number
// RETURNS    : string ordinalNumber
// BEHAVIOUR  : Adds appropriate suffix to the number given
//-----------------------------------------------------------------------------
function gen_makeOrdinal (number)
{
  var modten = number % 10;  // number modulo 10
  var modhun = number % 100; // number modulo 100
  var suffix = "th";

  if (modten == 1 && modhun != 11)
  {
    suffix = "st";
  }
  else if (modten == 2 && modhun != 12)
  {
    suffix = "nd";
  }
  else if (modten == 3 && modhun != 13)
  {
    suffix = "rd";
  }

  return (number + suffix);
}

//--------------------------- gen_toString ------------------------------------
// NAME       : gen_toString
// PARAMETERS : int number
// RETURNS    : string number
// BEHAVIOUR  : Converts int to string
//-----------------------------------------------------------------------------
function gen_toString (number)
{
  return number + "";
}

//--------------------------- isblank -----------------------------------------
// NAME       : isblank
// PARAMETERS : string s
//
// RETURNS    : bool
// BEHAVIOUR  : returns whether a string is entirely whitespace or not
//-----------------------------------------------------------------------------
function isblank(s) {
  for (var i = 0; i < s.length; i++) {
    var c = s.charAt(i);
    //Check for space/newline/tab and determine bool value
    if ((c != ' ') && (c != '\n') && (c != '\t')) return false;
  }
  return true;
}

//--------------------------- isemail -----------------------------------------
// NAME       : isemail
// PARAMETERS : string s
// 
// RETURNS    : bool
// BEHAVIOUR  : returns whether a string contains '@' character (valid email)
//-----------------------------------------------------------------------------
function isemail(s) {
  s = trim(s);
  for (var i = 0; i < s.length; i++) {
    var c = s.charAt(i);
    //Check for @ character and determine bool value
    if (c == '@') return true;
    if (c == ' ') return false;
  }
  if (s.lastIndexOf(".") < s.indexOf("@")) return false; // Must be a '.' after the '@'
  return false;
}

//---------------------------- isphone ----------------------------------------
// NAME       : isphone
// PARAMETERS : string s
// 
// RETURNS    : bool
// BEHAVIOUR  : returns whether a string is a valid phone number
//-----------------------------------------------------------------------------
function isphone(s) {
  var validchars = "0123456789()+- ";
  for (var i = 0; i < s.length; i++) {
    var c = s.charAt(i);
    //Now is the character in the list of valid characters
    if (c != ' ') {
      if (validchars.indexOf(c.toString()) == -1) return false
    }
  }
  return true; 
}


//-------------------------- isANumber ----------------------------------------
// NAME 	: isANumber
// PARAMETERS	: string 
// RETURNS	: bool
// BEHAVIOUR	: returns a bool value if the string given are all numbers
//-----------------------------------------------------------------------------

function isANumber (datastring){
  var msg ="";
  if (parseInt(datastring)!=datastring){
   for (var t=0;t<datastring.length;t++){
    var check = datastring.charAt(t);
    if (parseInt(check) != check){
    msg += check;
    }
   }
  }
  if (msg!="")
    return false;
  else
	return true;
}

//-------------------------- isAlpha ------------------------------------------
// NAME 	: isAlpha  
// PARAMETERS	: string 
// RETURNS	: bool
// BEHAVIOUR	: returns a bool value if the string given is all letters
//-----------------------------------------------------------------------------

function isAlpha (datastring){
  if (isblank(datastring)) return true;
  else return isValidChars(datastring, 'A-Za-z ');
}
//-------------------------- isAcceptedLetters --------------------------------
// NAME 	: isAcceptedLetters  
// PARAMETERS	: string 
// RETURNS	: bool
// BEHAVIOUR	: returns a bool value if the string given is all accepted
//-----------------------------------------------------------------------------

function isAcceptedLetters (datastring){
  if (isblank(datastring)) return true;
  else return isValidChars(datastring, '-A-Za-z\' ');
}

function isValidChars(datastring, validChars) {
  var re = eval('/['+validChars+']*/');
  return (re.exec(datastring) == datastring);
}
  

//-------------------------- isAPassword --------------------------------------
// NAME 	: isAPassword
// PARAMETERS	: string 
// RETURNS	: bool
// BEHAVIOUR	: returns a bool value if the string given is alphanumeric or
//                if X
//-----------------------------------------------------------------------------

function isAPassword (datastring){
  // to check all numbers
  var msg ="";
  if (parseInt(datastring)!=datastring){
   for (var t=0;t<datastring.length;t++){
    var check = datastring.charAt(t);
    if (parseInt(check) != check){
    msg += check;
    }
   }
  }
   else{
    msg = parseInt(datastring);
  }
  
  if (msg == datastring){
    return false;
   }
  else{
  
  return true;  
  }
}

//---------------------------- trim -------------------------------------------
// NAME       : trim
// PARAMETERS : string s
// 
// RETURNS    : string
// BEHAVIOUR  : trim(string)  - returns string with no spaces to left or right
//             
//              trim_left     - returns string with no spaces to left
//              trim_right    - returns string with no spaces to right
//              trim_all      - removes spaces within string
//-----------------------------------------------------------------------------
function trim(s) {
  return trim_right(trim_left(s));
}

//Associated with trim function
function trim_right(s) {
  if (s == null) return '';
  for (var i = 0; i < s.length; i++ ) {
    if  (s.charCodeAt(s.length - 1) < 33) { 
      if (s.length == 1) { s = ''; break; }
      else s = s.slice(0,s.length - 1);
    }
    else break;
  }
  return s;
}

//Associated with trim function
function trim_left(s) {
  if (s == null) return '';
  for (var i = 0; i < s.length; i++) {
    if (s.charCodeAt(0) < 33) {
      if (s.length == 1) { s = ''; break; }
      else s = s.slice(1,s.length);
    }
    else break;
  }
  return s;
}

//Removes spaces within string
function trim_all(s) {
  var newstring = "";
  for (var i = 0; i < s.length; i++) {
    if (s.substr(i, 1) != ' ')  newstring += s.substr(i, 1);
  }

  return newstring;
}

//------------------------------ isValidCreditNum -----------------------------
// NAME       : isValidCreditNum
// PARAMETERS : string s (credit card number)
// 
// RETURNS    : string
// BEHAVIOUR  : returns blank string if validation OK else list of err msgs
//-----------------------------------------------------------------------------
function isValidCreditNum(s) {
  var err = 0;     //The error flag initialised to no error
  var errmsg = ""; //The error message string

  if (!isANumber(s)) {
    errmsg = "Please enter a number in the credit card number input\n";
    err = 1;
  }

  if (err == 1) return errmsg

  if ((s.length < 13) || (s.length > 19)) {
    errmsg += "Please enter a card number of valid length\n";
    err = 1;
  }
 
  if (err == 1) return errmsg;

  //Now perform Luhn algorithm on the card number
  //Step 1 : double value of alternating digits, begin 2nd digit from right
  //Step 2 : add separate digits from products of step 1 (10 yields 1 & 0)
  //         along with digits not used in step 1
  //Step 3 : if total obtained is not divisible by 10 (end in 0) not valid num

  var fstofpair = "";         //First of each pair of digits
  var doubleup = new Array(); //Value of double second digit of pair
  var counter = 0;            //How many pair to loop through
  var fstchar = "";           //If num not divisible by 2 keep 1st digit

  //Is number divisible by 2
  if (s.length % 2 == 0) 
    counter = s.length / 2;
  else {
    counter = (s.length - 1) / 2;
    fstchar = s.substr(0,1);
    s = s.substr(1, s.length);
  }

  //Grab second of each pair, and double first of each pair
  for (var i = counter - 1; i > -1; i--) {
    fstofpair += s.substr(1 + 2 * i, 1);
    doubleup[i] = 2 * (s.substr(0 + 2 * i, 1));   
  }

  fstofpair += fstchar; //If number was not divisible by 2 add 1st digit back

  //Now add all doubleup values per digit
  var dblelem = "";
  var dsize = 0;
  var sumofdbl = 0; //The doubled elements total
  var sumoffst = 0; //The sum of all unaffected digits
  var dbltotal = 0; //Final total of all doubled values per digit
  for (var i = 0; i < counter; i++) {
    dblelem = "" + doubleup[i];
    dsize = dblelem.length;
    sumoffst += parseInt(fstofpair.substr(i, 1));
    for (var j = 0; j < dsize; j++) {
      sumofdbl += parseInt(dblelem.substr(j, 1));
    }
    dbltotal += sumofdbl;
    sumofdbl = 0;
  }

  //If string contained odd num digits add first digit back to unaffected total
  if (!isblank(trim_all(fstchar))) sumoffst += parseInt(fstchar);
  
  //Final check is grand total divisible by 10
  var finaltotal = 0;
  finaltotal = dbltotal + sumoffst;
  if (finaltotal % 10 != 0) {
    errmsg = "The credit card number entered has failed validation\n";
    err = 1;
  }
  
  return errmsg;
}

//------------------------------- numOccursChar -------------------------------
// NAME       : numOccursChar
// PARAMETERS : char sub, string full string (full)
// RETURNS    : integer
// 
// BEHAVIOUR  : returns number of occurances of subchar in string
//-----------------------------------------------------------------------------
function numOccursChar(sub, full) {
  var result = 0;
  for (var i = 0; i < full.length; i++) {
    if (full.substr(i,1).indexOf(sub) != -1)
      result++;
  }
  return result;
}

// --------------------------- browserSniff -----------------------------------
// NAME       : browserSniff
// PARAMETERS : document
// RETURNS    : string
//
// BEHAVIOUR  : returns browser type and version in string ie Netscape 4.7...
// ----------------------------------------------------------------------------
function browserSniff(theDoc) {
  var navInfo=navigator.appName + navigator.appVersion;
  
  return navInfo;
}

function ord (n) {
  if ((n != 11) && (n%10 == 1)) return n+"st"; 
  if ((n != 12) && (n%10 == 2)) return n+"nd"; 
  if ((n != 13) && (n%10 == 3)) return n+"rd";
  return n+"th"; 
}

