/*
 * Copyright (c) 2002-2009, 2011-2012 by cisco Systems, Inc.
 * All rights reserved.
 */
 
//Global vars
var ConfigMsg = "WARNING:\nThe settings shown on this page will be updated.\nClick 'OK' to continue.";
var ClearLogMsg = "WARNING:\nThe Event Log will be cleared.\nClick 'OK' to continue.";
var RestoreMsg = "WARNING:\nYou have requested that ALL settings on this page be reverted to their Factory Defaults!\nClick 'OK' to continue.";
var TextDisableMsg = "DISABLED"
var CopyrightYear = "2015";

//display properties of a JS object
function dump_props(obj,obj_name)
{
  var result = ""
  for( var i in obj )
  {
    result += obj_name + "." + i + " = " + obj[i] + "\n"
  }
  return result
}

//Encode the IOS command string(s) in src
function encode(src)
{
 var     dst = "";
 var     c;
 var     i;
 for( i = 0 ; i < src.length ; i += 1 )
 {
  c = src.charAt(i);
  if( c >= 'A' && c <= 'Z' )
     dst += c;
  else if( c >= 'a' && c <= 'z' )
     dst += c;
  else if( c >= '0' && c <= '9' )
     dst += c;
  else if( c == ' ' )
     dst += '+';
  else if( c == '/' )
     dst += "%2f";
  else if( c == '+' )
     dst += "%2b";
  else if( c == '\n' )
     dst += "%0A";
  else
     dst += escape(c);
 }
 return dst;
}

//Determine if a string is blank
function isBlank(testStr)
{
  if (testStr.search(/\S/) == -1)
    return true
  return false
}

//Determine if a string is a number
function isNumber(testStr)
{
  if (testStr.search(/^\s*\d+\s*$/) != -1) {
    //non-zero numbers starting with 0 may be interpreted by IOS as octal.
    //Disallow them to avoid surprises one way or the other.
    if (testStr.search(/^\s*0+[1-9]/) != -1)
      return false
    else
      return true
  }
  return false
}

//Determins if a string contains only digits (0-9)
function isDigit(testStr)
{
   if (testStr.search(/^\s*\d+\s*$/) != -1) {
      return true
   }
   return false
}

function isHexaDecimal(testStr)
{
   if (testStr.search(/[0-9a-fA-F]/) != -1) {
      return true
   }
   return false
}

//Determine if a string is an oct number
function isOct(testStr)
{
  if (testStr.search(/[^0-7]/) == -1)
    return true
  return false
}

//Determine if a string is a hex number
function isHex(testStr)
{
  if (testStr.search(/[^0-9a-fA-F]/) == -1)
    return true
  return false
}

//Determine if a string valid for CLI; 
//CLI doesn't like \t or ? or beginning ! # ;
//JS doesn't like " (messes up strings) (allow ' since more common)
//HTTP server doesn't like $ (signifies var substitution) or + (signifies space)
//            or [ (signifies a mode)
function isCLIString(testStr)
{
  if (isBlank(testStr))
    return false
  if (testStr.search(/^!/) != -1)
    return false
  if (testStr.search(/^#/) != -1)
    return false
  if (testStr.search(/^;/) != -1)
    return false
  if (testStr.search(/[\t?"$+\[]/) != -1)
    return false
  return true
}

//Determine if a password valid for CLI; like isCLIString, except 
//beginning ! # ; ARE allowed
//and " is also allowed because we never expose a passwd as a plan text.
function isCLIPasswd(testStr)
{
  if (isBlank(testStr))
    return false
  if (testStr.search(/[\t?$+\[]/) != -1)
    return false
  return true
}

//Determine if a string is only one word
function isWord(testStr)
{
  if (isBlank(testStr))
    return false
  if (testStr.search(/\s/) == -1)
    return true
  return false
}

//Determine if characters make up good SSID.
//need to ensure no ] since HTTP server interprets it differently in cmd vs. mode
//need to ensure no / since confuses http_get_uri_token
//prevent trailing spaces

//Overall disallowed char: + / ] \t " trailing_space
function isSSID(testStr)
{
  if (testStr.search(/[\t"+]/) != -1)
    return false;
  //netscape doesn't work properly with search(/[\\\]]/)
  if (testStr.indexOf("]") != -1)
    return false;
  if (testStr.indexOf("/") != -1)
    return false;
  if (isBlank(testStr.substring(testStr.length-1)))
    return false;
  return true;
}

// encode special char which are allowed now
// Allowed char which are converted in octal: $, [, \
// Allowed but not required to be converted: # ; !
function encode_schar(src) {
  var dst = ""
  var i;
  var c;
  for( i = 0 ; i < src.length ; i += 1 )
  {
   c = src.charAt(i);
   if ( c == '[' )
      dst += "\\133";
   else if (c == ' ')
      dst += "\\040";
   else if (c == '$')
      dst += "\\044";
   else if (c == '\\')
      dst += "\\134";
   else if (c == '+')
      dst += "\\053";
   else
      dst += c
  }
  return dst;
}

//Determine if a year is a leap year
function isLeapYear(year)
{
  return (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) ? true : false;
}

//Determine if a string is a date in format YYYY/MM/DD
function isDate(testStr)
{
  var monthToDays = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
  var slashes = 0;
  for (var i=0; i<testStr.length; i++)
  {
    if (testStr.charAt(i) >= '0' && testStr.charAt(i) <= '9') {
      continue;
    } else if (testStr.charAt(i) == '/') {
      ++slashes;
      continue;
    } else {
      break;
    }
  }
  if (i==0 || i != testStr.length || slashes != 2)
    return false;

  var fieldArray = testStr.split("/")
  var year = parseInt(fieldArray[0], 10)
  var month = parseInt(fieldArray[1], 10)
  var day = parseInt(fieldArray[2], 10)
  //make sure no blank fields
  if (isNaN(year) || isNaN(month) || isNaN(day))
    return false
  if (year < 1993 || year > 2035)
    return false
  if (month < 1 || month > 12)
    return false
  var maxDays
  if (month == 2 && isLeapYear(year))
    maxDays = 29
  else
    maxDays = monthToDays[month-1]
  if (day < 1 || day > maxDays)
    return false
  return true
}

//Determine if a string is a time in format HH:MM:SS
function isTime(testStr)
{
  var colons = 0;
  for (var i=0; i<testStr.length; i++)
  {
    if (testStr.charAt(i) >= '0' && testStr.charAt(i) <= '9') {
      continue;
    } else if (testStr.charAt(i) == ':') {
      ++colons;
      continue;
    } else {
      break;
    }
  }
  if (i==0 || i != testStr.length || colons != 2)
    return false;

  var fieldArray = testStr.split(":")
  var hours = parseInt(fieldArray[0], 10)
  var minutes = parseInt(fieldArray[1], 10)
  var seconds = parseInt(fieldArray[2], 10)
  //make sure no blank fields
  if (isNaN(hours) || isNaN(minutes) || isNaN(seconds))
    return false
  if (hours < 0 || hours > 23)
    return false
  if (minutes < 0 || minutes > 59)
    return false
  if (seconds < 0 || seconds > 59)
    return false
  return true
}

//Determine if a string is a valid MAC address
function isMAC(testStr)
{
  var     dots = 0;
  if (isBlank(testStr))
    return false
  if (testStr.search(/[^.0-9abcdefABCDEF]/) != -1)
    return false
  var fieldArray = testStr.split(".")
  if (fieldArray.length != 3)
    return false

  var triplet1 = parseInt(fieldArray[0], 16)
  var triplet2 = parseInt(fieldArray[1], 16)
  var triplet3 = parseInt(fieldArray[2], 16)
  //make sure no blank fields
  if (isNaN(triplet1) || isNaN(triplet2) || isNaN(triplet3))
    return false
  if (triplet1 > 0xffff)
    return false;
  //prevent multicast MAC
  if (triplet1 & 0x0100)
    return false;
  if (triplet2 > 0xffff)
    return false;
  if (triplet3 > 0xffff)
    return false;
  return true;
}

//Determine if a string is a MAC address w/o periods
function isMACName(testStr)
{
  if (isBlank(testStr))
    return false
  if (testStr.search(/[^.0-9abcdefABCDEF]/) != -1)
    return false
  if (testStr.length != 12)
    return false
  return true
}

//Determine if a string is a valid IP address
function isIP(testStr)
{
  var     dots = 0;
  for( var i = 0 ; i < testStr.length ; ++i )
  {
    if( testStr.charAt(i) >= '0' && testStr.charAt(i) <= '9') {
       continue;
    } else if( testStr.charAt(i) == '.' ) {
       ++dots;
       continue;
    } else {
       break;
    }
  }
  if (i==0 || i!=testStr.length || dots != 3)
    return false;
  
  var fieldArray = testStr.split(".")
  var octet1 = parseInt(fieldArray[0], 10)
  var octet2 = parseInt(fieldArray[1], 10)
  var octet3 = parseInt(fieldArray[2], 10)
  var octet4 = parseInt(fieldArray[3], 10)
  //make sure no blank fields
  if (isNaN(octet1) || isNaN(octet2) || isNaN(octet3) || isNaN(octet4))
    return false
  if (octet1 < 0 || octet1 > 255)
    return false;
  if (octet2 < 0 || octet2 > 255)
    return false;
  if (octet3 < 0 || octet3 > 255)
    return false;
  if (octet4 < 0 || octet4 > 255)
    return false;
  return true;
}

//Determine if string is a valid IP mask; i.e. left contiguous
function isIPMask(testStr)
{
  if (!isIP(testStr))
    return false;
  var fieldArray = testStr.split(".")
  var octet1 = parseInt(fieldArray[0], 10)
  var octet2 = parseInt(fieldArray[1], 10)
  var octet3 = parseInt(fieldArray[2], 10)
  var octet4 = parseInt(fieldArray[3], 10)
  var lastOctet = octet1;
  var curOctet;
  for (var i=2; i<5; i++) {
    curOctet = eval("octet"+i);
    if (lastOctet == 255)
      lastOctet = curOctet;
    else if (curOctet != 0)
      return false;
  }
  while (lastOctet & 0x80)
    lastOctet <<= 1;
  if (lastOctet & 0xff)
    return false;
  return true;
}

//Compare two IP address (assume they are valid)
//return <0 if ip1<ip2, 0 if ip1==ip2, >0 if ip1>ip2
function IPCompare(ip1, ip2)
{
  octets1 = ip1.split(".")
  octets2 = ip2.split(".")

  for (i=0; i<4; i++)
  {
    diff = octets1[i] - octets2[i]
    if (diff != 0)
      return diff
  }
  return 0
}

function isValidCLIString(testStr) {
 var i; 

  if (isBlank(testStr)) {
    return false
  }
  for (i=0; i < testStr.length; i ++) {
    if ((testStr.charCodeAt(i) > 126) || (testStr.charCodeAt(i)  < 32)) {
     return false;
    }
  }

  return true;
}

function isValidFilterName(name)
{
  var  i;
  if (isSSID(name) && isWord(name))  {
    for (i=0; i < name.length; i ++) {
     if ((name.charCodeAt(i) > 126) || (name.charCodeAt(i)  < 33)) {
       return false;
     }
    }
  } else {
    return false;
  }
  
  return true;
}

//Determine if form object is at default value. Returns false if newly selected or de-selected.
function def(obj)
{
    if( obj.type == "text" || obj.type == "password")
    {
        //don't treat a blank field as unchanged, since page may interpret blank as delete
        if( obj.value == obj.defaultValue)
            return true;
    }
    else if( obj.type == "checkbox" || obj.type == "radio")
    {
        if( obj.checked == obj.defaultChecked )
            return true;
    }
    else if( obj.type == "select-one" )
    {
        var noSelectDefault = true;   //IE may have no select default at startup
        if (obj.selectedIndex < 0)
            return true
        for (i=0; i<obj.length; i++) {
            if (obj.options[i].defaultSelected == true)
                noSelectDefault = false
        }
        if( obj.options[obj.selectedIndex].selected == 
            obj.options[obj.selectedIndex].defaultSelected )
            return true;
        if (noSelectDefault)
            return true;
    }
    else if( obj.type == "select-multiple" )
    {
        for( i = 0 ; i < obj.length ; i += 1 )
            if( obj.options[i].selected != obj.options[i].defaultSelected )
                return false;
        return true;
    }
//    else
//        alert("def() does not know object type\n" + dump_props(obj,"obj"));
    return false;
}

//Determine if form object is modified. Returns true if newly selected.
function modified(obj)
{
    if( obj.type == "text" || obj.type == "password" )
    {
        //don't treat a blank field as unchanged, since page may interpret blank as delete
        if( obj.value != obj.defaultValue)
            return true;
    }
    else if( obj.type == "checkbox" )
    {
        if( obj.checked == true )
            if( obj.defaultChecked == false )
                return true;
    }
    else if( obj.type == "select-one")
    {
        if ( obj.selectedIndex >= 0 )
            if( obj.options[obj.selectedIndex].selected != obj.options[obj.selectedIndex].defaultSelected)
                return true;
    }
    else if( obj.type == "radio")
    {
        if ( obj.checked == true )
            if( obj.defaultChecked == false )
                return true;
    }
//    else
//        alert("modified() does not know object type=" + obj.type + "\n" + dump_props(obj,"obj"));
    return false;
}

//disable any form element  
//For IE4/5 and NS6, could disable the element.
//But for general case, set the OnFocus() to blur so that at least the field is not editable
function disableFormElement (element, warningMsg)
{
  if (document.addEventListener && //NS6+
      (element.type == "checkbox" || element.type == "radio" || 
       element.type == "button")) {
    if (!element.off) {
      element.off = true;
      element.oldOnClick = element.onclick;
      element.onclick = function() {return false;}; 
    }
  } 
  element.onfocus = function() {this.blur(); if (warningMsg) alert(warningMsg);};
}

//enable any form element
function enableFormElement (element) 
{
  if (document.addEventListener && //NS6+
      (element.type == "checkbox" || element.type == "radio" ||
       element.type == "button")) {
    if (element.off) {
      element.off = false;
      element.onclick = element.oldOnClick; 
      element.oldOnClick = null;   
    }
  }
  element.onfocus = null;
}

//disable a textfield.  
//For IE4/5 and NS6, could disable the field.
//But for general case, set the OnFocus() to blur so that at least the field is not editable
//Arguments:
//  field: name of the textfield
//  warningMsg: (optional) alert msg popped up when user tried so set focus on the field
//  replacementText: (optional) new value for textfield.  Default is "DISABLED" (TextDisableMsg)
function disableTextField (field, warningMsg, replacementText)
{
  var tmpMax = 0;
  if( (0 < field.maxLength ) && (field.maxLength < 8)) {
    tmpMax = field.maxLength;
    field.maxLength = 8;
  }
  if (replacementText != null)
    field.value = replacementText
  else
    field.value = TextDisableMsg
  field.onfocus = function() {this.blur(); if (warningMsg) alert(warningMsg)};
  if(tmpMax != 0) {
    field.maxLength = tmpMax;
  }
}

//enable a textfield
//Arguments:
//  field: name of the textfield
//  replacementText: (optional) new value for textfield.  Default is ""
function enableTextField (field, replacementText) 
{
  if (replacementText != null)
    field.value = replacementText
  else
    field.value = ""
  field.onfocus = null;
}
// Initialize Radio Buttons upon page load
function initRadioButton(radio_object, result)
{
   for (i=0; i<radio_object.length; i++) {
      if (result == radio_object[i].value) {
         radio_object[i].checked = true;
         radio_object[i].defaultChecked = true;
      }
   }
}
// Set Radio Buttons within onClick routines
function setRadioButton(radio_object, result)
{
   for (i=0; i<radio_object.length; i++) {
      if (result == radio_object[i].value) {
         radio_object[i].checked = true;
      }
   }
}
// Set Radio Buttons within onClick routines
function setRadioButtonDefault(radio_object)
{
   for (i=0; i<radio_object.length; i++) {
      if (radio_object[i].defaultChecked == true) {
         radio_object[i].checked = true;
      }
   }
}
// Disable Radio Button - index using value field
//   it is safe to disable a non-existant button.
function disableRadioButtonByValue(radio_object, target_value_str, warningMsg)
{
   for (i=0; i<radio_object.length; i++) {
      if (target_value_str == radio_object[i].value) {
         disableFormElement(radio_object[i], warningMsg);
         return;
      }
   }
}
// Check Radio Buttons within onClick routines
function isRadioButtonChecked(radio_object, result)
{
   for (i=0; i<radio_object.length; i++) {
      if (result == radio_object[i].value) {
         return radio_object[i].checked;
      }
   }
}
// Check Radio Buttons modified and selected
function isRadioButtonModified(radio_object, result)
{
   for (i=0; i<radio_object.length; i++) {
      if (result == radio_object[i].value) {
         return modified(radio_object[i]);
      }
   }
//   alert("Unknown value ="+result);
   return false;
}
// Build commands from Text fields
function createTextCmd(leadstr, obj, trailstr)
{
   var str ="";
   if (modified(obj)) {
      if (obj.value != "") {
         str += leadstr;
         str += obj.value;
         str += trailstr;
      } else {
         str += "no ";
         str += leadstr;
         str += obj.defaultValue;
         str += trailstr;
      }
   }
   return str;
}
// Build commands from Radio Buttons - Use for [choice1/choice2] types of CLI commands
function createRadioCmd(leadstr, obj, trailstr)
{
   var str ="";
   for (i=0; i<obj.length; i++) {
      if (modified(obj[i])) {
         str += leadstr;
         str += obj[i].value;
         str += trailstr;
      }
   }
   return str;
}
// Build commands from Radio Buttons - Use for [no] types of CLI commands
function createRadioCmd_no(tgtstr, obj, prestr, trailstr)
{
   var str ="";
   for (i=0; i<obj.length; i++) {
      if (modified(obj[i])) {
         if (obj[i].value == tgtstr) {
            str += prestr;
         }
         str += trailstr;
      }
   }
   return str;
}


// This function is mainly used to escape ssid which may contain
// javascript regexp/match special or meta char. 
// Excluding - char because has no meaning outside []

function esc_js_regexp(exp) {

    var dst = ""
    var i;
    var c;
    var     found = -1;

    var meta_char = "$[]?.^()*+{}|,\\";
    if (exp == undefined) {
        return dst;
    }
    for( i = 0 ; i < exp.length ; i += 1 )
    {
        c = exp.charAt(i);
        found = meta_char.indexOf(c);
        if (found < 0) {
            dst += c;
        } else {
            dst += ("\\" + meta_char.charAt(found)); 
        }
    }
    return dst;
}

//Determine if a string is a valid IPV6 address

function isIPV6(teststr)
{ 
        var perlipv6regex = "^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))\s*$";
        var aeronipv6regex = "^\s*((?=.*::.*)(::)?([0-9A-F]{1,4}(:(?=[0-9A-F])|(?!\2)(?!\5)(::)|\z)){0,7}|((?=.*::.*)(::)?([0-9A-F]{1,4}(:(?=[0-9A-F])|(?!\7)(?!\10)(::))){0,5}|([0-9A-F]{1,4}:){6})((25[0-5]|(2[0-4]|1[0-9]|[1-9]?)[0-9])(\.(?=.)|\z)){4}|([0-9A-F]{1,4}:){7}[0-9A-F]{1,4})\s*$";

        var regex = "/"+perlipv6regex+"/";
        return (/^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))\s*$/.test(teststr));
}
