﻿var __launchNetElementRegex = /^([^\[\]\{\}\_]*)(?:\[([^\(\)]*)(?:\((.*)\))?\])?(?:\{([^\/]*)(?:\/(.*))?\})?(?:\_(.*))?$/;
var __launchNetElements = null;

function JustStopAlready(event)
{
  event.returnValue = false;
  event.preventDefault();
  event.stopPropagation();
  return false;
}

function inherit(subclass, superclass)
{
  var c = function() {};
  c.prototype = superclass.prototype;
  subclass.prototype = new c();
}

function CallFunction(functionName, parameters, defaultReturnValue, scope)
{
  if (typeof(scope) == "undefined")
  {
    if (eval('typeof(' + functionName + ')') != 'undefined') 
    {
        if (typeof(parameters) != "undefined") 
        {
            return eval(functionName + '(' + parameters + ')');
        }
        else 
        {
            return eval(functionName + '()');
        }
    }
    else
    {
      if (typeof(defaultReturnValue) == "undefined")
      {
        return false;
      }
      else
      {
        return defaultReturnValue;
      }
    }
  }
  else
  {
    if (eval('typeof(scope.' + functionName + ')') != 'undefined') 
    {
        if (typeof(parameters) != "undefined") 
        {
            return eval('scope.' + functionName + '(' + parameters + ')');
        }
        else 
        {
            return eval('scope.' + functionName + '()');
        }
    }
    else
    {
      if (typeof(defaultReturnValue) == "undefined")
      {
        return false;
      }
      else
      {
        return defaultReturnValue;
      }
    }
  }
}

function GetLaunchNetElementById(launchNetElementId)
{
  var launchNetElements = GetLaunchNetElements();
  for(var i=0; i < launchNetElements.length; i++) 
  {
    if (launchNetElements[i].Id == launchNetElementId)
    {
      return launchNetElements[i];
    }
  }
  return null;
}

function GetLaunchNetElementsByValidationType(validationType)
{
  var matchingLaunchNetElements = new Array();
  var count = 0;
  var launchNetElements = GetLaunchNetElements();
  for(var i=0; i < launchNetElements.length; i++) 
  {
    if (launchNetElements[i].ValidationType == validationType)
    {
      matchingLaunchNetElements[count++] = launchNetElements[i];
    }
  }
  return matchingLaunchNetElements;
}

function GetLaunchNetElements()
{
  if (__launchNetElements == null)
  {
    __launchNetElements = [];
    var theForm = document.forms[0];
    var fieldCount = 0;
    for(var i=0; i < theForm.length; i++) 
    {
      __launchNetElements[fieldCount++] = new LaunchNetElement(theForm.elements[i]);
    }
  }
  
  return __launchNetElements;
}

function GetValidatableLaunchNetElements()
{
  var launchNetElements = GetLaunchNetElements();
  var elementsToValidate = [];
  var count = 0;
  for(var i=0; i < launchNetElements.length; i++) 
  {
    if (launchNetElements[i].HasValidationType)
    {
      elementsToValidate[count++] = launchNetElements[i];
    }
  }

  return elementsToValidate;
}

function IsLaunchNetElement(element)
{
  return element != null && element.constructor == (new LaunchNetElement).constructor;
}

function LaunchNetElement(element)
{
  ///html element with id of the form "Id[Command(Arguments)]{ValidationType/ValidationClientId}_ObservationCode"

  this.Init = Init(element);

  var _element;
  var _id;
  var _command;
  var _commandArguments;
  var _validationType;
  var _validationClientId;
  var _observationCode;
  
  this.Element = _element;
  this.Id = _id;
  this.Command = _command;
  this.CommandArguments = _commandArguments;
  this.ValidationType = _validationType;
  this.ValidationClientId = _validationClientId;
  this.ObservationCode = _observationCode;
  this.GetValue = function() { return GetElementValue(_element); };
  
  this.HasCommand = _command.length > 0;
  this.HasValidationType = _validationType.length > 0;
  this.HasValidationClientId = _validationClientId.length > 0;
  this.IsAutoInjectValidation = _validationClientId.toLowerCase() == "autoinject" || _validationClientId.toLowerCase() == "autoinjectwithhide";
  this.IsAutoInjectValidationWithHide = _validationClientId.toLowerCase() == "autoinjectwithhide";
  this.AutoInjectValidationClientId = _id + "Error";
  this.HasObservationCode = _observationCode.length > 0;
  
  function Init(element)
  {
    if (typeof element == "undefined")
    {
      //totally invalid!  bail
      _element = null;
      _id = "";
      _command = "";
      _commandArguments = "";
      _validationType = "";
      _validationClientId = "";
      _observationCode = "";
      return;
    }
    
    if (typeof element == "string")
    {
      //if the provided "element" is the client id string, lookup the actual element
      _element = document.getElementById(element);
    }
    else
    {
      _element = element;
    }
    
    var result = __launchNetElementRegex.exec(_element.id);
    if (typeof result[1] == "undefined")
    {
      _id = "";
    }
    else
    {
      _id = result[1];
    }
    if (typeof result[2] == "undefined")
    {
      _command = "";
    }
    else
    {
      _command = result[2];
    }
    if (typeof result[3] == "undefined") {
      _commandArguments = "";
    }
    else {
      _commandArguments = result[3];
    }
    if (typeof result[4] == "undefined")
    {
      _validationType = "";
    }
    else
    {
      _validationType = result[4];
    }
    if (typeof result[5] == "undefined")
    {
      _validationClientId = "";
    }
    else
    {
      _validationClientId = result[5];
    }
    if (typeof result[6] == "undefined")
    {
      _observationCode = "";
    }
    else
    {
      //ensure the observation code is numeric  
      if(isNaN(result[6]))
      {
        //no observation code imbedded
        _observationCode = "";
      }
      else
      {
        //TEMPORARY HACK account to prevent asp net controls in the form from being turned into observation codes..
        //"ctl00_ContentPlaceHolderMaster_field_3_0"
        if(result[6] < 100)
        {
          //no observation code imbedded
          _observationCode = "";
        }
        else
        {
          _observationCode = result[6];
        }
      }
    }
  }
}

function GetElementValue(element)
{
  if (element == null)
  {
    return '';
  }
  
  if (IsLaunchNetElement(element))
  {
    //if we are working with a LaunchNetElement, get the real element it represents
    element = element.Element;
  }

  var value = '';

  switch(element.type)
  {
	  case "button" :
		  value = element.value;
		  break;
	  case "checkbox" :
		  if (element.checked)
		  {
			  value = element.value;
		  }
		  break;
	  case "file" :
		  value = element.value;
		  break;
	  case "hidden" :
		  value = element.value;
		  break;
	  case "password" :
		  value = element.value;
		  break;
	  case "radio" :
		  if (element.checked)
		  {
			  value = element.value;
		  }
		  break;
	  case "reset" :
		  value = element.value;
		  break;
	  case "select-one" :
		  var index = element.selectedIndex;
		  if (index >= 0)
		  {
			  value = element.options[index].value;
		  }
		  break;
	  case "select-multiple" :
		  value = element.value;
		  break;
	  case "text" :
		  value = element.value;
		  break;
	  case "textarea" :
		  value = element.value;
		  break;
	  default : 
		  value = element.value;
		  break;
  }
  return value;
}

function LaunchNetServiceCommands()
{
  var totalCommands = 0;
  var commands = new Array();
  
  this.Add = Add;
  this.Contains = Contains;
  this.HandlePageClick = HandlePageClick;
  this.HandleValidationRequiredCheck = HandleValidationRequiredCheck;
  
  function Add(command)
  {
    commands[totalCommands++] = command;
  }
  function Contains(command)
  {
    return commands.contains(command);
  }
  function HandlePageClick(scope, launchNetElementClicked, pageValid)
  {
    if (pageValid 
      && launchNetElementClicked.HasCommand 
      && commands.contains(launchNetElementClicked.Command))
    {
        if (CallFunction(launchNetElementClicked.Command, launchNetElementClicked.CommandArguments, false, scope))
      {
        CallFunction(launchNetElementClicked.Command + '_Success');
      }
    }
  }
  function HandleValidationRequiredCheck(launchNetElementClicked)
  {
    return (launchNetElementClicked.HasCommand && commands.contains(launchNetElementClicked.Command));
  }
}

function GenerateErrorContainer(element, errorMessage)
{
  var errorContainer = null;
  if (errorMessage && errorMessage.length > 0)
  {
    var errorContainer = document.createElement("span");
    errorContainer.setAttribute("id", "error_" + element.id);
    errorContainer.className = "errorContainer";
    errorContainer.appendChild(document.createTextNode(errorMessage));
  }
  return errorContainer;
}

function InjectErrorContainer(element, errorMessage)
{
  if (IsLaunchNetElement(element))
  {
    //if we are working with a LaunchNetElement, get the real element it represents
    element = element.Element;
  }
  
  var errorContainer = null ;
  RemoveErrorContainer(element);

  var errorContainer = GenerateErrorContainer(element, errorMessage);
  if (errorContainer != null)
  {
    element.appendChild(errorContainer);
  }
}

function CreateErrorContainer(element, errorMessage)
{
  if (IsLaunchNetElement(element))
  {
    //if we are working with a LaunchNetElement, get the real element it represents
    element = element.Element;
  }

  var errorContainer = null ;
  RemoveErrorContainer(element);

  var errorContainer = GenerateErrorContainer(element, errorMessage);
  if (errorContainer != null)
  {
    if (element.type == "radio" || element.type == "checkbox")
    {
      //to avoid breakage of radio/checkbox text by error insert
      element.parentNode.insertBefore(errorContainer, element.nextSibling.nextSibling);
    }
    else
    {
      element.parentNode.insertBefore(errorContainer, element.nextSibling);
    }
  }
}

function RemoveErrorContainer(element)
{
  if (IsLaunchNetElement(element))
  {
    //if we are working with a LaunchNetElement, get the real element it represents
    element = element.Element;
  }
  
  if (document.getElementById("error_" + element.id))
  {
    var elementToRemove = document.getElementById("error_" + element.id);
    elementToRemove.parentNode.removeChild(elementToRemove);
  }
}

function ShowError(elementId)
{
  var element = document.getElementById(elementId);
  element.style.display = "inline";
}

function HideError(elementId)
{
  var element = document.getElementById(elementId);
  element.style.display = "none";
}

function ValidationResult(launchNetElement)
{
  var _valid = true;
  var _errorPrefix = null;
  var _errorSuffix = null;
  var _launchNetElement = launchNetElement;
  
  this.GetValid = function() { return _valid; };
  this.SetValid = function(value) { _valid = value; };
  this.GetErrorPrefix = function() { return _errorPrefix; };
  this.SetErrorPrefix = function(value) { _errorPrefix = value; };
  this.GetErrorSuffix = function() { return _errorSuffix; };
  this.SetErrorSuffix = function(value) { _errorSuffix = value; };
  this.GetLaunchNetElement = function() { return _launchNetElement; };
  this.SetLaunchNetElement = function(value) { _launchNetElement = value; };
  this.GetErrorMessage = function()
  {
    var errorMessage = "";
    
    if (_errorPrefix == null)
    {
      errorMessage = " * " + _errorSuffix.charAt(0).toUpperCase() + _errorSuffix.substring(1, _errorSuffix.length);
    }
    else
    {
      errorMessage = " * " + _errorPrefix + " " + _errorSuffix;
    }
    
    return errorMessage;
  }

  this.UpdateDisplay = UpdateDisplay;

  function UpdateDisplay()
  {
    if (_valid)
    {
      if (_launchNetElement.HasValidationClientId)
      {
        if (_launchNetElement.IsAutoInjectValidation)
        {
          var injectTargetElement = document.getElementById(_launchNetElement.AutoInjectValidationClientId);
          RemoveErrorContainer(injectTargetElement);
          if (_launchNetElement.IsAutoInjectValidationWithHide)
          {
            HideError(_launchNetElement.AutoInjectValidationClientId);
          }
        }
        else
        {
          HideError(_launchNetElement.ValidationClientId);
        }
      }
      else
      {
        RemoveErrorContainer(_launchNetElement);
      }
    }
    else
    {
      if (_launchNetElement.HasValidationClientId)
      {
        if (_launchNetElement.IsAutoInjectValidation)
        {
          var injectTargetElement = document.getElementById(_launchNetElement.AutoInjectValidationClientId);
          InjectErrorContainer(injectTargetElement, this.GetErrorMessage());
          if (_launchNetElement.IsAutoInjectValidationWithHide)
          {
            ShowError(_launchNetElement.AutoInjectValidationClientId);
          }
        }
        else
        {
          ShowError(_launchNetElement.ValidationClientId);
        }
      }
      else
      {
        CreateErrorContainer(_launchNetElement, this.GetErrorMessage());
      }
    }
  }
}

function SetValidationResultSuffix(validationResult, validationErrorSuffix)
{
  if (typeof(validationResult) != "undefined")
  {
    validationResult.SetValid(false);
    validationResult.SetErrorSuffix(validationErrorSuffix);
  }
}

/// <reference path="LaunchNetClientBase.js"/>

function CommonValidation()
{
  this.IsValidRegex = IsValidRegex;
  this.IsValidDate = IsValidDate;
  this.IsValidEmailAddress = IsValidEmailAddress;
  this.IsValidEmailAddress_NotRequired = IsValidEmailAddress_NotRequired;
  this.IsNotNull = IsNotNull;
  this.IsSelectionMade = IsSelectionMade;
  this.IsNumeric = IsNumeric;
  this.IsAlpha = IsAlpha;
  this.IsAlphaNumeric = IsAlphaNumeric;
  this.HasNoDigits = HasNoDigits;
  this.HasNoSpaces = HasNoSpaces;
  this.HasNoCrLf = HasNoCrLf;
  this.IsMaxLength = IsMaxLength;
  this.IsMinLength = IsMinLength;
  
  var regexValidEmail = /^([0-9a-zA-Z]+[-._+&amp;])*[0-9a-zA-Z]+@([-0-9a-zA-Z]+[.])+[a-zA-Z]{2,6}$/;
  var regexValidEmail_NotRequired = /(^$)|(^([0-9a-zA-Z]+[-._+&amp;])*[0-9a-zA-Z]+@([-0-9a-zA-Z]+[.])+[a-zA-Z]{2,6}$)/;
  var regexValidDate = /^([0-1])?[0-9](\/|-)([0-3])?[0-9](\/|-)(([1-2][0-9][0-9][0-9])|([0-9][0-9]))$/;
  var regexValidDate_NotRequired = /(^$)|(^[0-1])?[0-9](\/|-)([0-3])?[0-9](\/|-)(([1-2][0-9][0-9][0-9])|([0-9][0-9])$)/;
  var regexNotNumeric = /[^0-9]/;
  var regexNotAlpha = /[^A-Za-z]/;
  var regexNotAlphaNumeric = /[^A-Za-z0-9]/;
  var regexHasDigits = /[0-9]/;
  var regexHasSpaces = /\s/;
  var regexHasCrLf = /[\r\n]/;
  
  /***** ERROR MESSAGE CONSTANTS *****/
  var ISVALIDDATE = "value for date is invalid."
  var ISVALIDEMAIL = "value for email is invalid.";

  var ISREQUIRED = "is required.";
  var ISREQUIREDLIST = "please select an option.";
  var ISNUMERIC = "must be a number.";
  var ISALPHA = "cannot contain non-alpha characters.";
  var ISALPHANUMERIC = "must be alphanumeric.";
  var HASNOCRLF = "cannot contain carriage returns.";
  var HASNODIGITS = "cannot contain digits.";
  var HASNOSPACES = "cannot contain spaces.";  
  /***** END ERROR MESSAGE CONSTANTS *****/

  function IsValidRegex(value, validationResult, regex, bangRegex, errorSuffix)
  {
    var result;
    
    if (bangRegex)
    {
      result = !regex.test(value);
    }
    else
    {
      result = regex.test(value);
    }
    
    if (result)
    {
      return true;
    }
    else
    {
      SetValidationResultSuffix(validationResult, errorSuffix);
      return false;
    }
  }

  function IsValidDate(value, validationResult)
  {
    return IsValidRegex(value, validationResult, regexValidDate, false, ISVALIDDATE);
  }

  function IsValidDate_NotRequired(value, validationResult)
  {
    return IsValidRegex(value, validationResult, regexValidDate_NotRequired, false, ISVALIDDATE);
  }

  function IsValidEmailAddress(value, validationResult)
  {
    return IsValidRegex(value, validationResult, regexValidEmail, false, ISVALIDEMAIL);
  }
  
  function IsValidEmailAddress_NotRequired(value, validationResult)
  {
    return IsValidRegex(value, validationResult, regexValidEmail_NotRequired, false, ISVALIDEMAIL);
  }
  
  function IsNotNull(value, validationResult)
  {
	  if ((value.length > 0) && (value.trim().length > 0))
	  {
	    return true;
	  }
	  else
	  {
	    SetValidationResultSuffix(validationResult, ISREQUIRED);
      return false;
	  }
  }

	function IsSelectionMade(list, validationResult)
	{
    var listName = list.name;
    var selectCount = 0;
    for(var i=0; i<eval("document.forms[0]." + listName + ".length"); i++)
    {
      if(eval("document.forms[0]." + listName + "[i].checked"))
      {
        selectCount++;
      }
    }	    
    if (selectCount > 0)
    {
      return true;
    }
    else
    {
      SetValidationResultSuffix(validationResult, ISREQUIREDLIST);
      return false;
    }
	}

  function IsNumeric(value, validationResult)
  {
    return IsValidRegex(value, validationResult, regexNotNumeric, true, ISNUMERIC);
  }

  function IsAlpha(value, validationResult)
  {
    return IsValidRegex(value, validationResult, regexNotAlpha, true, ISALPHA);
  }

  function IsAlphaNumeric(value, validationResult)
  {
    return IsValidRegex(value, validationResult, regexNotAlphaNumeric, true, ISALPHANUMERIC);
  }

  function HasNoDigits(value, validationResult)
  {
    return IsValidRegex(value, validationResult, regexHasDigits, true, HASNODIGITS);
  }

  function HasNoSpaces(value, validationResult)
  {
    return IsValidRegex(value, validationResult, regexHasSpaces, true, HASNOSPACES);
  }

	function HasNoCrLf(value, validationResult)
	{
    return IsValidRegex(value, validationResult, regexHasCrLf, true, HASNOCRLF);
	}

  function IsMaxLength(value, maxLength, validationResult)
  {
	  if (value.length <= maxLength)
    {
      return true;
    }
    else
    {
      if (maxLength == 1)
      {
        SetValidationResultSuffix(validationResult, 'cannot exceed ' + maxLength + ' character in length.');
      }
      else
      {
        SetValidationResultSuffix(validationResult, 'cannot exceed ' + maxLength + ' characters in length.');
      }
      return false;
    }
  }

  function IsMinLength(value, minLength, validationResult)
  {
	  if (value.length >= minLength)
    {
      return true;
    }
    else
    {
      if (minLength == 1)
      {
        SetValidationResultSuffix(validationResult, 'must be at least ' + minLength + ' character in length.');
      }
      else
      {
        SetValidationResultSuffix(validationResult, 'must be at least ' + minLength + ' characters in length.');
      }
      return false;
    }
  }
}

function ValidatorBase(handledValidationTypes)
{
  var _commonValidator = new CommonValidation();
  
  var _totalHandledValidationTypes = 0;
  var _handledValidationTypes = handledValidationTypes;
  
  this.Validate = Validate;
  this.CommonValidator = _commonValidator;
  this.AddHandledValidationType = AddHandledValidationType;
  this.HandlesValidationType = HandlesValidationType;
  this.IsValidRegex = _commonValidator.IsValidRegex;
  this.StandardValidation = StandardValidation;
  this.FormatMethodCall = FormatMethodCall;
  
  function AddHandledValidationType(handledValidationType)
  {
    _handledValidationTypes[_totalHandledValidationTypes++] = handledValidationType;
  }
  function HandlesValidationType(validationType)
  {
    return _handledValidationTypes.contains(validationType);
  }
    
  function FormatMethodCall(methodName)
  {
    //methodNames was just a single string
    var banged = false;
    if (methodName.charAt(0) == "!")
    {
      //if methodName is banged, make note of it and pull it out
      banged = true;
      methodName = methodName.substring(1, methodName.length);
    }

    var parameters;
    
    if (methodName.indexOf("IsMaxLength", 0) > -1)
    {
      //looks like "IsMaxLength 10"
      //pull out the 10 and use it as a parameter
      var index = methodName.lastIndexOf("IsMaxLength") + "IsMaxLength".length + 1;
      parameters = "(value, " + methodName.substring(index, methodName.length) + ", validationResult)";
      methodName = methodName.substring(0, index - 1);
    }
    else if (methodName.indexOf("IsMinLength", 0) > -1)
    {
      //looks like "IsMinLength 10"
      //pull out the 10 and use it as a parameter
      var index = methodName.lastIndexOf("IsMinLength") + "IsMinLength".length + 1;
      parameters = "(value, " + methodName.substring(index, methodName.length) + ", validationResult)";
      methodName = methodName.substring(0, index - 1);
    }
    else
    {
      //standard parameters
      parameters = "(value, validationResult)";
    }

    if (eval("typeof(this." + methodName + ")") == "undefined")
    {
      //if method name should have included CommonValidator prefix, be nice and add it
      methodName = "CommonValidator." + methodName;
    }

    if (banged)
    {
      return "!this." + methodName + parameters;
    }
    else
    {
      return "this." + methodName + parameters;
    }
  }
  
  function StandardValidation(launchNetElement, methodNames, errorPrefix)
  {
    //get value the element represents
    var value = launchNetElement.GetValue();
    //build validation result
    var validationResult = new ValidationResult(launchNetElement);
    if (typeof(errorPrefix) != "undefined")
    {
      //add prefix if defined
      validationResult.SetErrorPrefix(errorPrefix);
    }
    
    if (typeof(methodNames) == "string")
    {
      methodCall = this.FormatMethodCall(methodNames);
      eval(methodCall);
    }
    else
    {
      var methodChain = "";
      //create the chain of methods to call from methodNames array
      //the fact that they are "anded" will prevent needless execution as normal if any one fails
      for (var i = 0; i < methodNames.length; i++)
      {
        var methodCall = this.FormatMethodCall(methodNames[i]);
        methodChain = methodChain + methodCall;
        methodChain = methodChain + " && ";
      }
      
      //remove trailing " && "
      methodChain = methodChain.substring(0, methodChain.length - 4);
      //evaluate chain
      eval("(" + methodChain + ")");
    }
    //update the display as appropriate
    validationResult.UpdateDisplay();
    //return result
    return validationResult.GetValid();
  }
  function Validate(launchNetElement)
  {
    if (HandlesValidationType(launchNetElement.ValidationType))
    {
      if(!eval("this.Validate" + launchNetElement.ValidationType + "(launchNetElement)"))
      {
        return false;
      }
    }
    
    return true;
  }
}
