/* *************************************************************
** FORMVAL.JS - JS Form Validation Library
** =======================================
** This library contains code to validate HTML form-field data.
** The bulk of this file was derived from Eric Krock's FormChek.js at
** developer.netscape.com/docs/examples/javascript/formval/overview.html
** (Many thanks, Eric!) Enjoy ... and please maintain this header.
**
** To load this library in an HTML doc, put the following
** line in the doc's HEAD (before any other SCRIPT tags):
**
** <SCRIPT SRC="formval.js" LANGUAGE="JavaScript"></SCRIPT>
**
** Author      Ver  Date     Comments
** ======      ===  ====     ========
** BluePrint   4.1  16/01/05 Form Validation: User Details
**
** (c) 1997 Netscape Communications Corporation
** Copyright 2001, Rick Scott/BluePrint Web Designs
** All rights reserved.
************************************************************* */

/* *************************************************************
** USAGE
** =====
** Functions to Validata Form-Element Data:
**   isEmpty(s) - true if string s is empty
**   isBlank(s) - true if string s is empty or blank (all whitespace chars)
**   isLetter(c) - true if char c is an English letter 
**   isDigit(c) - true if char c is a digit 
**   isInteger(s) - true if string s is a signed/unsigned number
**   isIntegerInRange(s, a, b) - true if string s (integer) is a <= s <= b
**   isFloat(s) - true if string s is a signed/unsigned floating-point number
**   isAlphanumeric(s) - true if s is English letters and numbers only
**   isUSPhoneNumber(s) - true if string s is a valid U.S. phone number
**   isZIPCode(s) - true if string s is a valid U.S. ZIP code
**   isStateCode(s) - true if string s is a valid U.S. (2-letter) state code
**   isLocalPostCode - if string s is a local postcode for delivery
**   isEmail(s) - true if string s is a valid email address
**   isCreditCardNum(s) - true if string s is a validly formatted credit card #
**   getCheckedRadioButton(radioSet) - gets index checked radio button in set
**   getCheckedCheckboxes(checkboxSet) - gets index(es) of checked checkboxes in set
**   getCheckedSelectOptions(select) - gets index(es) of checked select options
**
** Functions to Reformat input=text Form-Field Data:
**   stripCharsInBag(s, bag) - removes all chars in string bag from string s
**   stripCharsNotInBag(s, bag) - removes all chars NOT in string bag from string s
**   stripBlanks(s) - removes all blank chars from s
**   stripLeadingBlanks(s) - removes leading blank chars from s
**   stripTrailingBlanks(s) - removes trailing blank chars from s
**   stripLeadingTrailingBlanks(s) - removes lead+trail blank chars from s
**   reformatString(targetStr, str1, int1 [, str2, int2 [, ..., ...]]) - 
**     inserts formatting chars or delimiters in targetStr (see below)
************************************************************* */


/* ********************************************************** */
/* Global Variables and Constants *************************** */
/* ********************************************************** */

var digits = "0123456789";
var lowercaseLetters = "abcdefghijklmnopqrstuvwxyz"
var uppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
var blanks = " \t\n\r";  // aka whitespace chars

// decimal point character differs by language and culture
var decimalPointDelimiter = "."

// non-digit characters allowed in phone numbers
var phoneNumberDelimiters = "()- ";

// characters allowed in US phone numbers
var validUSPhoneChars = digits + phoneNumberDelimiters;

// U.S. phone numbers have 10 digits, formatted as ### ### #### or (###)###-####
var digitsInUSPhoneNumber = 10;

// non-digit characters which are allowed in ZIP Codes
var ZIPCodeDelimiters = "-";

// our preferred delimiter for reformatting ZIP Codes
var ZIPCodeDelimeter = "-"

// U.S. ZIP codes have 5 or 9 digits, formatted as ##### or #####-####
var digitsInZIPCode1 = 5
var digitsInZIPCode2 = 9

// Valid U.S. Postal Codes for states, territories, armed forces, etc.
// See http://www.usps.gov/ncsc/lookups/abbr_state.txt
var USStateCodeDelimiter = "|";
var AUSStateCodes = "NSW|VIC|TAS|QLD|ACT|SA |WA |NT |nsw|vic|tas|qld|act|sa |wa |nt "
var localPostCodes = "2340 "
var phoneLength = 14;


/* ********************************************************** */
/* Functions ************************************************ */
/* ********************************************************** */


// Returns true if string s is empty

function isEmpty(s)
  {
  return ((s == null) || (s.length == 0));
  }


// Returns true if string s is empty or all blank chars

function isBlank(s)
  {
  var i;

  // Is s empty?
  if (isEmpty(s))
    return true;

  // Search through string's chars one by one until we find first
  // non-blank char, then return false; if we don't, return true
  for (i=0; i<s.length; i++)
    {   
    // Check that current character isn't blank
    var c = s.charAt(i);
    if (blanks.indexOf(c) == -1) 
      return false;
    }
  // All characters are blank
  return true;
  }


// Removes all characters which appear in string bag from string s

function stripCharsInBag (s, bag)
  {
  var i;
  var returnString = "";

  // Search through string's characters one by one;
  // if character is not in bag, append to returnString
  for (i = 0; i < s.length; i++)
    {   
    // Check that current character isn't blank
    var c = s.charAt(i);
    if (bag.indexOf(c) == -1) 
      returnString += c;
    }
  return returnString;
  }


// Removes all blank chars (as defined by blanks) from s

function stripBlanks(s)
  {
  return stripCharsInBag(s, blanks)
  }


// Removes leading blank chars (as defined by blanks) from s

function stripLeadingBlanks(s)
  { 
  var i = 0;
  while ((i < s.length) && (blanks.indexOf(s.charAt(i)) != -1))
     i++;
  return s.substring(i, s.length);
  }


// Removes trailing blank chars (as defined by blanks) from s

function stripTrailingBlanks(s)
  { 
  var i = s.length - 1;
  while ((i >= 0) && (blanks.indexOf(s.charAt(i)) != -1))
     i--;
  return s.substring(0, i+1);
  }


// Removes leading+trailing blank chars (as defined by blanks) from s

function stripLeadingTrailingBlanks(s)
  { 
  s = stripLeadingBlanks(s);
  s = stripTrailingBlanks(s);
  return s;
  }


// Returns true if character c is an English letter (A .. Z, a..z)

function isLetter(c)
  {
  return (((c >= "a") && (c <= "z")) || ((c >= "A") && (c <= "Z")));
  }


// Returns true if character c is a digit (0 .. 9)

function isDigit(c)
  {
  return ((c >= "0") && (c <= "9"));
  }


// Returns true if all chars in string s are numbers;
// first character is allowed to be + or -; does not 
// accept floating point, exponential notation, etc.

function isInteger(s)
  {
  if (isBlank(s))
    return false;

  // skip leading + or -
  if ((s.charAt(0) == "-") || (s.charAt(0) == "+"))
    var i = 1;
  else
    var i = 0;

  // Search through string's chars one by one until we find a 
  // non-numeric char, then return false; if we don't, return true
  for (i; i<s.length; i++)
    {   
    // Check that current character is number
    var c = s.charAt(i);
    if (!isDigit(c)) 
      return false;
    }
  // All characters are numbers
  return true;
  }


// True if string s is an unsigned floating point (real) number; 
// first character is allowed to be + or -; no exponential notation.

function isFloat(s)
  { 
  var seenDecimalPoint = false;

  if (isBlank(s)) 
    return false;
  if (s == decimalPointDelimiter) 
    return false;

  // skip leading + or -
  if ((s.charAt(0) == "-") || (s.charAt(0) == "+"))
    var i = 1;
  else
    var i = 0;

  // Search through string's chars one by one until we find a 
  // non-numeric char, then return false; if we don't, return true

  for (i; i<s.length; i++)
    {   
    // Check that current character is number
    var c = s.charAt(i);

    if ((c == decimalPointDelimiter) && !seenDecimalPoint) 
      seenDecimalPoint = true;
    else if (!isDigit(c)) 
      return false;
    }
  // All characters are numbers
  return seenDecimalPoint;
  }


// Returns true if string s is English letters (A .. Z, a..z) only

function isAlphabetic(s)
  {
  var i;

  if (isBlank(s)) 
     return false;

  // Search through string's chars one by one until we find a 
  // non-alphabetic char, then return false; if we don't, return true

  for (i = 0; i < s.length; i++)
  {   
  // Check that current character is letter
  var c = s.charAt(i);

  if (!isLetter(c))
    return false;
  }

  // All characters are letters
  return true;
  }


// Returns true if string s is English letters (A .. Z, a..z) and numbers only

function isAlphanumeric(s)
  {
  var i;

  if (isBlank(s)) 
     return false;

  // Search through string's chars one by one until we find a 
  // non-alphanumeric char, then return false; if we don't, return true

  for (i = 0; i < s.length; i++)
    {   
    // Check that current character is number or letter
    var c = s.charAt(i);

    if (! (isLetter(c) || isDigit(c) ) )
    return false;
    }

  // All characters are numbers or letters
  return true;
  }


// reformatString(targetStr [, str1, int1, str2, int2, ... strN, intN])       
//
// Handy function for arbitrarily inserting formatting characters
// or delimiters of various kinds within targetString.
//
// reformatString() takes one required string argument, targetStr, 
// and 0-N optional string/integer-pair arguments. These optional 
// arguments specify how targetStr is to be reformatted and how/where 
// other strings are to be inserted in it.
//
// reformatString() processes the optional args in order one by one.
// * If the argument is an integer, reformatString() appends that number 
//   of sequential characters from targetStr to the resultString.
// * If the argument is a string, reformatString() appends the string
//   to the resultString.
//
// NOTE: The first argument after targetString must be a string.
// (It can be empty.)  The second argument must be an integer.
// Thereafter, integers and strings must alternate.  This is to
// provide backward compatibility to Navigator 2.0.2 JavaScript
// by avoiding use of the typeof operator.
//
// It is the caller's responsibility to make sure that we do not
// try to copy more characters from s than s.length.
//
// EXAMPLES:
//
// * To reformat a 10-digit U.S. phone number from "1234567890"
//   to "(123)456-7890" make this function call:
//   reformatString("1234567890", "(", 3, ")", 3, "-", 4)
//
// HINT:
//
// If you have a string which is already delimited in one way
// (example: a phone number delimited with spaces as "123 456 7890")
// and you want to delimit it in another way using function reformat,
// call stripCharsNotInBag() or stripBlanks() to remove unwanted 
// characters, THEN call function reformatString to delimit as desired.
//
// EXAMPLE:
//
// reformatString(stripCharsNotInBag ("123 456 7890", digits),
//           "(", 3, ") ", 3, "-", 4)

function reformatString(targetString)
  { 
  var arg;
  var sPos = 0;
  var resultString = "";

  for (var i=1; i<reformatString.arguments.length; i++)
    {
    arg = reformatString.arguments[i];
    if (i%2 == 1) 
      {
      resultString += arg;
      }
    else
      {
      resultString += targetString.substring(sPos, sPos + arg);
      sPos += arg;
      }
    }
  return resultString;
  }


// Returns true if s is valid U.S. phone number (with area code): 10 digits

function isUSPhoneNumber(s)
  { 
  if (isBlank(s)) 
    return false;
  s = stripCharsNotInBag(s, digits);
  return (isInteger(s) && (s.length == digitsInUSPhoneNumber));
  }

// Returns true if s is valid 2-letter U.S. state abbreviation

function isStateCode(s)
  { 
  if (isBlank(s)) 
    return false;
  return ((AUSStateCodes.indexOf(s) != -1) &&
          (s.indexOf(USStateCodeDelimiter) == -1))
  }

// Returns true if s is one of the local postcode values

function isLocalPostCode(s)
  { 
  if (isBlank(s)) 
    return false;
  return ((localPostCodes.indexOf(s) != -1) &&
          (s.indexOf(USStateCodeDelimiter) == -1))
  }

// Returns true if string is a valid email address: @ and . required,
// at least one char before @, at least one char before and after .

function isEmail(s)
  { 
  if (isBlank(s)) 
    return false;
  
  // there must be >= 1 character before @, so we start
  // start looking at character position 1 (i.e. second character)
  var i = 1;
  var sLength = s.length;

  // look for @
  while ((i < sLength) && (s.charAt(i) != "@"))
    i++

  if ((i >= sLength) || (s.charAt(i) != "@")) 
    return false;
  else 
    i += 2;

  // look for .
  while ((i < sLength) && (s.charAt(i) != "."))
    i++

  // there must be at least one character after the .
  if ((i >= sLength - 1) || (s.charAt(i) != ".")) 
    return false;
  else 
    return true;
  }


// Returns true if string s is an integer such that a <= s <= b

function isIntegerInRange (s, a, b)
  { 
  if (isBlank(s)) 
    return false;
  if (!isInteger(s)) 
    return false;
  var num = parseInt(s);
  return ((num >= a) && (num <= b));
  }

function isCreditCardNum(s)
  {
  if (s.length == 16)  // test for ################ format
    {
    for (var i=0; i<16; i++)
      if (!isDigit(s.charAt(i)))
        return false;
    return true;
    }
  else if (s.length == 19)  // test for ####-####-####-####
    {                       // or #### #### #### #### formats
    for (var i=0; i<19; i++)
      {
      if (i % 5 == 4)
        {
        if (s.charAt(i) != "-" && s.charAt(i) != " ")  // should be a - or space
          return false;
        }
      else if (!isDigit(s.charAt(i)))  // should be a # 
        {
        return false;
        }
      }
    return true;
    }
  return false;  // s was none of legal formats listed above
  }


// Returns index of checked radio button in radio set,
// or -1 if no radio buttons are checked

//function getCheckedRadioButton(radioSet)
//  { 
//  for (var i=0; i<radioSet.length; i++)
//    if (radioSet[i].checked)
//      return i;
//  return -1;
//  }


// Returns array containing index(es) of checked checkbox(es) 
// in checkbox set, or -1 if no checkboxes are checked

//function getCheckedCheckboxes(checkboxSet)
//  {
//  var arr = new Array();
//  for (var i=0,j=0; i<checkboxSet.length; i++)
//    if (checkboxSet[i].checked)
//      arr[j++] = i;
//  if (arr.length > 0)
//    return arr;
//  else
//    return -1;
//  }


/* ******** DETAILS FORM VALIDATION ... ******** */
function validate(form)  // validate form fields + strip lead/trail blanks
  {
  // shipping name
  form.name.value = stripLeadingTrailingBlanks(form.name.value);
  if (isEmpty(form.name.value))
    {
    alert("Please enter a name.");
    form.name.focus(); form.name.select();
    return;
    }

  // contact email
  form.email.value = stripLeadingTrailingBlanks(form.email.value);
  if (isEmpty(form.email.value))
    {
    alert("Please enter an email address.");
    form.email.focus(); form.email.select();
    return;
    }

  if (!isEmail(form.email.value))
    {
    alert("Please enter a valid email address.");
    form.email.focus(); form.email.select();
    return;
    }

  // contact telephone
  var tempPhone = form.telephone.value ; //restore to this after checking
  var maxPhoneLen = 11;
  var minPhoneLen = 10;
  var osPhonePref = 5;
  form.telephone.value = stripLeadingTrailingBlanks(form.telephone.value);
  form.telephone.value = stripBlanks(form.telephone.value);

  if (isEmpty(form.telephone.value))
    {
    alert("Please enter a telephone number using only numbers and one space, including STD Code or mobile prefix.");
    form.telephone.focus(); form.telephone.select();
    return;
    }

  if (!isInteger(form.telephone.value))
    {
    alert("Please enter only numbers and one space for the telephone including STD Code or mobile prefix.");
    form.telephone.value = tempPhone ; //restore to original value and format ...
    form.telephone.focus(); form.telephone.select();
    return;
    }

  form.suburb.value =  form.suburb.value.toUpperCase();
  form.state.value =  form.state.value.toUpperCase();
  form.country.value = form.country.value.toUpperCase();

  if (form.country.value == '' || form.country.value == 'AUSTRALIA')
    {
    if (tempPhone.length > maxPhoneLen)
      {
      alert("Please restrict the telephone number to ten digits using only numbers and one space, including STD Code or mobile prefix.");
      form.telephone.value = tempPhone ; //restore to original value and format ...
      form.telephone.focus(); form.telephone.select();
      return;
      }
    if (tempPhone.length < maxPhoneLen)
      {
      alert("Please ensure the telephone number contains ten digits using only numbers and one space, including STD Code or mobile prefix.");
      form.telephone.value = tempPhone ; //restore to original value and format ...
      form.telephone.focus(); form.telephone.select();
      return;
      }
    }
  else 
    {
    maxPhoneLen = maxPhoneLen+ osPhonePref;
    if (tempPhone.length > maxPhoneLen)
      {
      alert("Please restrict the telephone number to " + maxPhoneLen + " digits using only numbers and one space, including STD Code or mobile prefix.");
      form.telephone.value = tempPhone ; //restore to original value and format ...
      form.telephone.focus(); form.telephone.select();
      return;
      }
    if (tempPhone.length < minPhoneLen)
      {
      alert("Please ensure the telephone number is a minimum of " + minPhoneLen + " digits using only numbers and one space, including STD Code or mobile prefix. If your phone number is valid but not accepted please send us an email ...");
      form.telephone.value = tempPhone ; //restore to original value and format ...
      form.telephone.focus(); form.telephone.select();
      return;
      }
    }

  form.telephone.value = tempPhone ; //restore to original value and format ...

  // shipping address
  form.address.value = stripLeadingTrailingBlanks(form.address.value);
  if (isEmpty(form.address.value))
    {
    alert("Please enter a delivery address.");
    form.address.focus(); form.address.select();
    return;
    }

  // shipping city
  form.suburb.value = stripLeadingTrailingBlanks(form.suburb.value);
  if (isEmpty(form.suburb.value))
    {
    alert("Please enter a delivery city or town.");
    form.suburb.focus(); form.suburb.select();
    return;
    }

  /* AUSTRALIAN State and Postcode validation */
  form.state.value = stripLeadingTrailingBlanks(form.state.value);
  if (form.state.value == '')
    {
    alert("Please enter a delivery state.");
    form.state.focus(); form.state.select();
    return;
    }
  if (form.country.value == '' || form.country.value == 'AUSTRALIA')
    {
    form.state.value = stripLeadingTrailingBlanks(form.state.value);
//    alert('State: "' + form.state.value + '"  Country: "' + form.country.value + '"');
//    alert('isState: "' + !isStateCode(form.state.value) + '"');
    if (!isStateCode(form.state.value))
      {
      alert("Please enter a valid 2 or 3 letter delivery state.");
      form.state.focus(); form.state.select();
      return;
      }
    }

  // shipping postcode
  if (form.postcode.value.length < 4)
    {
    alert("Please enter a minimum of 4 numbers for the postcode (eg: 0800).");
    form.postcode.focus(); form.postcode.select();
    return;
    }

  form.postcode.value = stripLeadingTrailingBlanks(form.postcode.value);

  if (form.postcode.value == 0)
    {
    alert("Please enter a valid postcode.");
    form.postcode.focus(); form.postcode.select();
    return;
    }

//*** SET REGION CODE FOR AUSTRALIA POST & CHECK VALID **
//** Set frame variables for 'checkout.html' **
function setRegion(thisPostCode){
 var k=0;
 var startZones=0;
 for (k=0; k<top.totalZones; k++)
     if (zones[k].end > form.postcode.value-1 && zones[k].start < form.postcode.value+1){ 
   top.deliveryZone=zones[k].region; 
   break;
   return k;
     }
  return k;
  }


var tempPostCode=0;
tempPostCode=parseInt(form.postcode.value);


//** CHECK VARIABLES: Start Code in Form to Update ... **
//** Status: OFF **
//setRegion(tempPostCode);
//form.tempzoneDetails.value = zones[top.deliveryZone].end + '|' + zones[top.deliveryZone].start + '|' + zones[top.deliveryZone].region + '|' + zones[top.deliveryZone].status + '|' + top.totalZones + '|' + k + '|' + top.deliveryZone + '|';

  form.country.value = stripLeadingTrailingBlanks(form.country.value);
  if (form.country.value == ''|| form.country.value == 'australia' || form.country.value == 'Australia') {
    form.country.value = 'AUSTRALIA';}

  if (form.country.value == 'AUSTRALIA')
    {
     if (zones[setRegion(tempPostCode)].region == "XX")
     {
    j=0;
    alert("Please enter a valid Australian postcode.");
    form.postcode.focus(); form.postcode.select();
    return;
     }

     if (zones[setRegion(tempPostCode)].region == "XS")
     {
    j=0;
    alert("Our delivery services are not setup for this postcode.\n         Our apologies for any inconvenience.");
    form.postcode.focus(); form.postcode.select();
    return;
     }
  }

  // delivery method
/*
  if (!form.deliveryMethod[0].checked &&   // AUSPOST
      !form.deliveryMethod[1].checked)     // COURIER
    {
    alert("Please select a delivery method.");
    form.deliveryMethod[0].focus();
    form.deliveryMethod[0].select();
    return;
    }

  if (form.deliveryMethod[0].checked &&
      form.country.value != 'AUSTRALIA')  
    {
    alert("This delivery method is not appropriate for countries outside Australia.");
    form.deliveryMethod[0].focus();
    form.deliveryMethod[0].select();
    return;
    }

  if (form.deliveryMethod[0].checked)  // AusPost
    {
    if (!form.thisSpeed[0].checked && !form.thisSpeed[1].checked)  // none selected
      {
      alert("Please select an Australia Post Delivery method.");
      form.thisSpeed[0].focus();
      return;
      }
    }    

  if (form.deliveryMethod[1].checked)  // AusPost
    {
    if (!form.thisSpeed[2].checked && !form.thisSpeed[3].checked)  // none selected
      {
      alert("Please select a Courier Delivery method.");
      form.thisSpeed[2].focus();
      return;
      }
    }    
*/

// payment method
  if (!form.paymentMethod[0].checked && 
      !form.paymentMethod[1].checked && 
      !form.paymentMethod[2].checked && 
      !form.paymentMethod[3].checked)
    {
    alert("Please select a payment method.");
    form.paymentMethod[0].focus();
    form.paymentMethod[0].select();
    return;
    }

    if (form.paymentMethod[0].checked && form.country.value != 'AUSTRALIA')  // no COD permitted
      {
      alert("You can not select COD if outside Australia.  Please select another payment option.");
      form.paymentMethod[2].focus();form.paymentMethod[2].select();
      return;
      }

/* all is valid, so save the details */
//  visitordata.load();
//alert('Order: ' + thisOrder);
//  visitordata.order = thisOrder;
saveDetails(form);
//  saveDeliveryMethod(form);
//  savePaymentMethod(form);
  location = formAction;  // settings and load up the 'order.php' page
  }



// ******** ARRAY DETAILS: POSTCODES ... ********
// * Copy of MASTER details held in postcode.js *
// **********************************************
// All postcode array loaded from this script.
// Results not available to other pages/scripts.

var currReg = "Q4";
var firstReg = "N1";          //do not reset
var lastReg = "W5";           //do not reset
var currZoneID = currReg;    // ID of current content page

//** REGIONS **
var N1 = "New South Wales: Urban";
var N2 = "New South Wales: Rural";
var NF = "New South Wales: Norfolk Island";
var NT = "Northern Territory";
var Q1 = "Queensland South";
var Q2 = "Queensland Central";
var Q3 = "Queensland North";
var Q4 = "Queensland West";
var S1 = "South Australia: Urban";
var S2 = "South Australia: Rural";
var T1 = "Tasmania";
var V1 = "Victoria: Urban";
var V2 = "Victoria: Rural";
var W1 = "Western Australia: South";
var W2 = "Western Australia: Central";
var W3 = "Western Australia: North";
var XX = "Invalid Postcodes";


//** ERROR MESSAGES **
var noPostcodeMsg = "No postcode provided for processing ...";
var invalidPostcodeMsg = "Postcode entered not found on our Postcode Tables ...";

//** ITEM OBJECT CONSTRUCTOR FUNCTION **
// You use this to create your online-store inventory list (instructions // below).

function Zone(start, end, country, region, daysPP, daysEXP, daysCOUR)
  {
  this.start = start;              // start of range (string)
  this.end = end;                  // end of range (string)
  this.country = country;          // country code (string: AUS)
  this.region = region;            // AusPost Zone for Postcode (string)
  this.daysPP = daysPP;            // Days by Parcel Post (number)
  this.daysEXP = daysEXP;          // Days by Express Post (number)
  this.daysCOUR = daysCOUR;        // Days by Courier  (number)
  }

var zones = new Array();      // holds all Postcode objects in list
var count = -1;               // enables Zone objs to be added/deleted

/* INVENTORY LIST *************************************** */
// Most of the functionality derives from this inventory list.
// CAUTION:
// DO NOT modify the first and last lines of the entries:
//   zones[++count] = new Item(
//   );
// Make sure each argument (except last!) is followed by a , (comma).

zones[++count] = new Zone("9960","9999","AUS","Q4",3,1,0);
zones[++count] = new Zone("9920","9959","AUS","Q3",3,1,0);
zones[++count] = new Zone("9880","9919","AUS","Q2",3,1,0);
zones[++count] = new Zone("9800","9879","AUS","XX",0,0,0);
zones[++count] = new Zone("9700","9799","AUS","Q1",2,1,0);
zones[++count] = new Zone("9600","9699","AUS","XX",0,0,0);
zones[++count] = new Zone("9597","9599","AUS","Q2",3,2,0);
zones[++count] = new Zone("9400","9596","AUS","Q1",2,1,0);
zones[++count] = new Zone("9300","9399","AUS","XX",0,0,0);
zones[++count] = new Zone("9000","9299","AUS","Q1",2,1,0);
zones[++count] = new Zone("8000","8999","AUS","V1",2,1,0);

zones[++count] = new Zone("7152","7999","AUS","T1",4,2,0);
zones[++count] = new Zone("7151","7151","AUS","XS",0,0,0);
zones[++count] = new Zone("7000","7150","AUS","T1",3,1,0);

zones[++count] = new Zone("6800","6999","AUS","W1",5,2,0);
zones[++count] = new Zone("6798","6799","AUS","XS",0,0,0);
zones[++count] = new Zone("6700","6797","AUS","W3",6,2,0);
zones[++count] = new Zone("6206","6699","AUS","W2",6,2,0);
zones[++count] = new Zone("6000","6205","AUS","W1",5,1,0);

zones[++count] = new Zone("5800","5999","AUS","S1",3,1,0);
zones[++count] = new Zone("5750","5799","AUS","XX",0,0,0);
zones[++count] = new Zone("5200","5749","AUS","S2",4,2,0);
zones[++count] = new Zone("5000","5199","AUS","S1",3,1,0);

zones[++count] = new Zone("4900","4999","AUS","XX",0,0,0);
zones[++count] = new Zone("4806","4899","AUS","Q4",5,2,0);
zones[++count] = new Zone("4700","4805","AUS","Q3",4,2,0);
zones[++count] = new Zone("4550","4699","AUS","Q2",3,2,0);
zones[++count] = new Zone("4500","4549","AUS","Q1",2,2,0);
zones[++count] = new Zone("4450","4499","AUS","Q3",4,2,0);
zones[++count] = new Zone("4300","4449","AUS","Q2",3,2,0);
zones[++count] = new Zone("4256","4299","AUS","Q1",2,1,0);
zones[++count] = new Zone("4255","4255","AUS","N2",2,2,0);
zones[++count] = new Zone("4000","4254","AUS","Q1",2,1,0);

zones[++count] = new Zone("3984","3999","AUS","V2",3,1,0);
zones[++count] = new Zone("3980","3983","AUS","V1",2,1,0);
zones[++count] = new Zone("3979","3979","AUS","V2",3,1,0);
zones[++count] = new Zone("3978","3972","AUS","V1",2,1,0);
zones[++count] = new Zone("3945","3971","AUS","V2",3,1,0);
zones[++count] = new Zone("3926","3944","AUS","V1",2,1,0);
zones[++count] = new Zone("3921","3925","AUS","V2",3,1,0);
zones[++count] = new Zone("3910","3920","AUS","V1",2,1,0);
zones[++count] = new Zone("3812","3909","AUS","V2",3,1,0);
zones[++count] = new Zone("3750","3811","AUS","V1",2,1,0);
zones[++count] = new Zone("3691","3749","AUS","V2",3,2,0);
zones[++count] = new Zone("3689","3690","AUS","N2",3,2,0);
zones[++count] = new Zone("3444","3688","AUS","V2",3,2,0);
zones[++count] = new Zone("3425","3443","AUS","V1",2,1,0);
zones[++count] = new Zone("3342","3424","AUS","V2",3,1,0);
zones[++count] = new Zone("3335","3341","AUS","V1",2,1,0);
zones[++count] = new Zone("3221","3334","AUS","V2",3,1,0);
zones[++count] = new Zone("3000","3220","AUS","V1",2,1,0);

zones[++count] = new Zone("2900","2999","AUS","N2",2,2,0);
zones[++count] = new Zone("2899","2899","AUS","NF",3,2,0);
zones[++count] = new Zone("2891","2898","AUS","N2",2,2,0);
zones[++count] = new Zone("2890","2890","AUS","N1",1,1,0);
zones[++count] = new Zone("2881","2889","AUS","N2",2,2,0);
zones[++count] = new Zone("2880","2880","AUS","S2",4,2,0);
zones[++count] = new Zone("2787","2879","AUS","N2",2,2,0);
zones[++count] = new Zone("2740","2786","AUS","N1",1,1,0);
zones[++count] = new Zone("2731","2739","AUS","V2",3,2,0);
zones[++count] = new Zone("2720","2730","AUS","N2",2,2,0);
zones[++count] = new Zone("2717","2719","AUS","V2",3,2,0);
zones[++count] = new Zone("2716","2716","AUS","N2",2,2,0);
zones[++count] = new Zone("2715","2715","AUS","V2",3,2,0);
zones[++count] = new Zone("2649","2714","AUS","N2",2,1,0);
zones[++count] = new Zone("2648","2648","AUS","V2",3,1,0);
zones[++count] = new Zone("2575","2647","AUS","N2",2,1,0);
zones[++count] = new Zone("2555","2574","AUS","N1",1,1,0);
zones[++count] = new Zone("2531","2554","AUS","N2",2,1,0);
zones[++count] = new Zone("2500","2530","AUS","N1",1,1,0);
zones[++count] = new Zone("2487","2499","AUS","N2",2,1,0);
zones[++count] = new Zone("2485","2486","AUS","N2",2,1,0);
zones[++count] = new Zone("2264","2484","AUS","N2",2,1,0);
zones[++count] = new Zone("1000","2263","AUS","N1",1,1,0);

zones[++count] = new Zone("0800","0999","AUS","NT",6,2,0);
zones[++count] = new Zone("0300","0799","AUS","XX",0,0,0);
zones[++count] = new Zone("0200","0299","AUS","N2",1,1,0);
zones[++count] = new Zone("0000","0199","AUS","XX",0,0,0);

