/// <reference path="LaunchNetClientBase.js"/>
/// <reference path="BrowserServices.js"/>
/// <reference path="ErrorServices.js"/>
/// <reference path="ClientProxyServices.js"/>
/// <reference path="LaunchNetClientContext.js"/>
/// <reference path="PlatformServices.js"/>


//the following are variables for which values are injected
//var __yourVariable;


function FicoServices()
{
  var participantAnswerElementRegex = /^([^<>]*)(?:<([^<>]+),([^<>]+)>)$/;
  var commands = new LaunchNetServiceCommands();
  commands.Add("ParticipantSubmit");
  commands.Add("ParticipantUnsubscribeSubmit");
  commands.Add("ParticipantAnswerSubmit");
  
  this.OnPageLoad = OnPageLoad;
  this.OnPageClick = OnPageClick;
  this.OnValidationRequiredCheck = OnValidationRequiredCheck;
  this.OnValidateLaunchNetElements = OnValidateLaunchNetElements;
  
  this.ParticipantSubmit = ParticipantSubmit;
  this.ParticipantUnsubscribeSubmit = ParticipantUnsubscribeSubmit;
  this.ParticipantAnswerSubmit = ParticipantAnswerSubmit;
  
  function FicoServicesValidator()
  {
    //setup handled validation types
    var _handledValidationTypes = new Array();
    var _count = 0;
    _handledValidationTypes[_count++] = "Prefix";
    _handledValidationTypes[_count++] = "FirstName";
    _handledValidationTypes[_count++] = "MiddleInitial";
    _handledValidationTypes[_count++] = "LastName";
    _handledValidationTypes[_count++] = "Suffix";
    _handledValidationTypes[_count++] = "Address1";
    _handledValidationTypes[_count++] = "Address2";
    _handledValidationTypes[_count++] = "City";
    _handledValidationTypes[_count++] = "State";
    _handledValidationTypes[_count++] = "Zip";
    _handledValidationTypes[_count++] = "Phone";
    _handledValidationTypes[_count++] = "SSN";
    _handledValidationTypes[_count++] = "AnswerText";

    //call base class constructor with handled validation types
    ValidatorBase.call(this, _handledValidationTypes);

    var regexValidSSN = /^\d{3}\-?\d{2}\-?\d{4}$/;
    var regexValidPhone = /^\(?\d{3}\)?\s|-\d{3}-\d{4}$/;
    var regexNotAnswerText = /[^A-Za-z\d\s!#\$%&'\(\)\*\+,-\./:;<=>\?@\\_~]/;
    var regexValidZip = /(^\d{5}$)|(^\d{5}-\d{4}$)/;
    var regexValidState = /^(AK|AL|AR|AZ|CA|CO|CT|DC|DE|FL|GA|HI|IA|ID|IL|IN|KS|KY|LA|MA|MD|ME|MI|MN|MO|MS|MT|NE|NC|ND|NH|NJ|NM|NV|NY|OH|OK|OR|PA|RI|SC|SD|TN|TX|UT|VA|VT|WA|WI|WV|WY|AA|AE|AP|AS|FM|GU|MH|MP|PR|PW|VI)$/i;
    var regexFicoChars = /@|#|\$|%|\*|\^|!|{|}|\[|\]|\?|\+|-|=|\\|\/|,|\"/;
    var regexFicoDelimiter = /{/;
    var regexTripleRepeat = /^([0-9a-zA-Z])\1\1/i;
    var regexTitle = /^(CAPT|COL|DR|FR|LT|MISS|MS|MRS|MR|MJR|REV|SIST|AGENCY)$/i;
    var regexTestWord = /^(TEST|TESTING|FIRST)$/i;

    //expose validation methods
    this.ValidatePrefix = ValidatePrefix;
    this.ValidateFirstName = ValidateFirstName;
    this.ValidateMiddleInitial = ValidateMiddleInitial;
    this.ValidateLastName = ValidateLastName;
    this.ValidateSuffix = ValidateSuffix;
    this.ValidateAddress1 = ValidateAddress1;
    this.ValidateAddress2 = ValidateAddress2;
    this.ValidateCity = ValidateCity;
    this.ValidateState = ValidateState;
    this.ValidateZip = ValidateZip;
    this.ValidateSSN = ValidateSSN;
    this.ValidatePhone = ValidatePhone;
    this.ValidateAnswerText = ValidateAnswerText;

    this.IsNotTestWord = IsNotTestWord;
    this.IsNotTitle = IsNotTitle;
    this.IsNotTripleRepeat = IsNotTripleRepeat;
    this.HasNoFicoDelimiter = HasNoFicoDelimiter;
    this.HasNoFicoChars = HasNoFicoChars;
    this.IsValidState = IsValidState;
    this.IsValidZip = IsValidZip;
    this.IsValidSSN = IsValidSSN;
    this.IsValidPhone = IsValidPhone;
    this.IsValidAnswerText = IsValidAnswerText;

    /***** ERROR MESSAGE CONSTANTS *****/
    var ISNOTTESTWORD = "cannot start with test, testing, or first";
    var ISNOTTITLE = "cannot be a title";
    var ISNOTTRIPLEREPEAT = "cannot start with a triply repeated character";
    var HASNOFICODELIMITER = "cannot contain the '{' character";
    var HASNOFICOCHARS = "has invalid characters";
    var ISVALIDSTATE = "must be a valid state";
    var ISVALIDZIP = "must be a valid zip code";
    var ISVALIDSSN = "must be a valid SSN"
    var ISVALIDPHONE = "must be a valid phone numer"
    var ISANSWERTEXT = "has invalid characters";
    /***** END ERROR MESSAGE CONSTANTS *****/

    function ValidatePrefix(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "HasNoDigits"
          , "HasNoSpaces"
          , "HasNoFicoDelimiter"
          , "HasNoCrLf"
          , "IsMaxLength 4"
          ]
        , "Prefix"
        );
    }
      
    function ValidateFirstName(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "IsNotNull"
          , "HasNoDigits"
          , "HasNoCrLf"
          , "HasNoFicoChars"
          , "HasNoFicoDelimiter"
          , "IsNotTitle"
          , "IsNotTripleRepeat"
          , "IsNotTestWord"
          , "IsMinLength 2"
          , "IsMaxLength 15"
          ]
        , "First Name"
        );
    }

    function ValidateMiddleInitial(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "HasNoDigits"
          , "IsAlpha"
          , "HasNoSpaces"
          , "HasNoFicoDelimiter"
          , "HasNoCrLf"
          , "IsMaxLength 1"
          ]
        , "Middle Initial"
        );
    }

    function ValidateLastName(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "IsNotNull"
          , "HasNoCrLf"
          , "HasNoDigits"
          , "HasNoFicoChars"
          , "HasNoFicoDelimiter"
          , "IsNotTripleRepeat"
          , "IsMaxLength 20"
          , "IsMinLength 2"
          ]
        , "Last Name"
        );
    }

    function ValidateSuffix(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "HasNoCrLf"
          , "HasNoFicoDelimiter"
          , "IsMaxLength 4"
          ]
        , "Suffix"
        );
    }

    function ValidateAddress1(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "IsNotNull"
          , "HasNoCrLf"
          , "HasNoFicoDelimiter"
          , "IsMaxLength 50"
          ]
        , "Address"
        );
    }

    function ValidateAddress2(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "HasNoCrLf"
          , "HasNoFicoDelimiter"
          , "IsMaxLength 50"
          ]
        , "Address2"
        );
    }

    function ValidateCity(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "IsNotNull"
          , "HasNoDigits"
          , "HasNoCrLf"
          , "HasNoFicoDelimiter"
          , "IsMinLength 1"
          , "IsMaxLength 20"
          ]
        , "City"
        );
    }

    function ValidateState(launchNetElement)
    {
      return this.StandardValidation(launchNetElement, "IsValidState");
    }

    function ValidateZip(launchNetElement)
    {
      return this.StandardValidation(launchNetElement, "IsValidZip");
    }

    function ValidateSSN(launchNetElement)
    {
      return this.StandardValidation(launchNetElement, "IsValidSSN");
    }

    function ValidatePhone(launchNetElement)
    {
      return this.StandardValidation(launchNetElement, "IsValidPhone");
    }

    function ValidateAnswerText(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "IsNotNull"
          , "HasNoCrLf"
          , "HasNoFicoDelimiter"
          , "IsValidAnswerText"
          , "IsMaxLength 50"
          ]
        );
    }

    function IsNotTestWord(value, validationResult)
    {
      return this.IsValidRegex(value, validationResult, regexTestWord, true, ISNOTTESTWORD);
    }

    function IsNotTitle(value, validationResult)
    {
      return this.IsValidRegex(value, validationResult, regexTitle, true, ISNOTTITLE);
    }

    function IsNotTripleRepeat(value, validationResult)
    {
      return this.IsValidRegex(value, validationResult, regexTripleRepeat, true, ISNOTTRIPLEREPEAT);
    }

    function HasNoFicoDelimiter(value, validationResult)
    {
      return this.IsValidRegex(value, validationResult, regexFicoDelimiter, true, HASNOFICODELIMITER);
    }

    function HasNoFicoChars(value, validationResult)
    {
      return this.IsValidRegex(value, validationResult, regexFicoChars, true, HASNOFICOCHARS);
    }

    function IsValidState(value, validationResult)
    {
      return this.IsValidRegex(value, validationResult, regexValidState, false, ISVALIDSTATE);
    }	

    function IsValidZip(value, validationResult)
    {
      return this.IsValidRegex(value, validationResult, regexValidZip, false, ISVALIDZIP);
    }

    function IsValidSSN(value, validationResult)
    {
      return this.IsValidRegex(value, validationResult, regexValidSSN, false, ISVALIDSSN);
    }

    function IsValidPhone(value, validationResult)
    {
      return this.IsValidRegex(value, validationResult, regexValidPhone, false, ISVALIDPHONE);
    }

    function IsValidAnswerText(value, validationResult)
    {
      return this.IsValidRegex(value, validationResult, regexNotAnswerText, true, ISANSWERTEXT);
    }
  }
  
  inherit(FicoServicesValidator, ValidatorBase);


  function ParticipantAnswerElement(launchNetElement)
  {
    this.Init = Init(launchNetElement);
    
    var _launchNetElement;
    var _question;
    var _answer;
    
    this.LaunchNetElement = _launchNetElement;
    this.Question = _question;
    this.Answer = _answer;
    this.IsOpenEnded = _answer == "OPEN" || _answer.length < 1;
    
    function Init(launchNetElement)
    {
      var result = participantAnswerElementRegex.exec(launchNetElement.Id);
      if (result == null)
      {
        _launchNetElement = null;
        _question = null;
        _answer = null;
      }
      else
      {
        _launchNetElement = launchNetElement;
        _question = result[2];
        _answer = result[3];
      }
    }
  }
  
  function LaunchNetElementToParticipantAnswerElement(launchNetElement)
  {
    var result = participantAnswerElementRegex.test(launchNetElement.Id);
    if (!result)
    {
      return null;
    }
    else
    {
      return new ParticipantAnswerElement(launchNetElement);
    }
  }
  
  function GetParticipantAnswerLaunchNetElements()
  {
    var launchNetElements = GetLaunchNetElements();
    var participantAnswerElements = [];
    var count = 0;
    for(var i = 0; i < launchNetElements.length; i++) 
    {
      var participantAnswerElement = LaunchNetElementToParticipantAnswerElement(launchNetElements[i]);
      if (participantAnswerElement != null)
      {
        participantAnswerElements[count++] = participantAnswerElement;
      }
    }

    return participantAnswerElements;
  }

/* ***********************************************************************************
-  Page Load Event
************************************************************************************ */

  function OnPageLoad()
  {
  }


/* ***********************************************************************************
-  Page Click Event
************************************************************************************ */

  function OnPageClick(launchNetElementClicked, pageValid)
  {
    commands.HandlePageClick(this, launchNetElementClicked, pageValid);
  }
  
  function ParticipantSubmit()
  {
    //obtain data for participant
    var firstName = GetLaunchNetElementById("FirstName").GetValue();
    var lastName = GetLaunchNetElementById("LastName").GetValue();
    var address1 = GetLaunchNetElementById("Address1").GetValue();
    var city = GetLaunchNetElementById("City").GetValue();
    var state = GetLaunchNetElementById("State").GetValue();
    var zip = GetLaunchNetElementById("Zip").GetValue();

    //as some elements are optional, we'll provide an empty string if the apropriate element cannot be found
    var prefixElement = GetLaunchNetElementById("Prefix");
    var suffixElement = GetLaunchNetElementById("Suffix");
    var middleInitialElement = GetLaunchNetElementById("MiddleInitial");
    var address2Element = GetLaunchNetElementById("Address2");
    
    var prefix = prefixElement == null ? "" : prefixElement.GetValue();
    var middleInitial = middleInitialElement == null ? "" : middleInitialElement.GetValue();
    var suffix = suffixElement == null ? "" : suffixElement.GetValue();
    var address2 = address2Element == null ? "" : address2Element.GetValue();

    //submit participant
    var response = __context.GetServiceClientProxy('FicoServices').AddParticipant
      (
      prefix
      , firstName
      , middleInitial
      , lastName
      , suffix
      , address1
      , address2
      , city
      , state
      , zip
      );
    
    if (response.error != null || response.value == null)
    {
      __context.RedirectToErrorPage();
      return false;
    }
    
    //also submit any participant answers on the page
    return ParticipantAnswerSubmit();
  }
  
  function ParticipantUnsubscribeSubmit()
  {
    //obtain data for participant unsubscribe
    var firstName = GetLaunchNetElementById("FirstName").GetValue();
    var lastName = GetLaunchNetElementById("LastName").GetValue();
    var address1 = GetLaunchNetElementById("Address1").GetValue();
    var city = GetLaunchNetElementById("City").GetValue();
    var state = GetLaunchNetElementById("State").GetValue();
    var zip = GetLaunchNetElementById("Zip").GetValue();
    var email = GetLaunchNetElementById("Email").GetValue();

    //as some elements are optional, we'll provide an empty string if the apropriate element cannot be found
    var prefixElement = GetLaunchNetElementById("Prefix");
    var suffixElement = GetLaunchNetElementById("Suffix");
    var middleInitialElement = GetLaunchNetElementById("MiddleInitial");
    var address2Element = GetLaunchNetElementById("Address2");
    
    var prefix = prefixElement == null ? "" : prefixElement.GetValue();
    var middleInitial = middleInitialElement == null ? "" : middleInitialElement.GetValue();
    var suffix = suffixElement == null ? "" : suffixElement.GetValue();
    var address2 = address2Element == null ? "" : address2Element.GetValue();

    var response = __context.GetServiceClientProxy('FicoServices').AddParticipantUnsubscribe
      (
      prefix
      , firstName
      , middleInitial
      , lastName
      , suffix
      , address1
      , address2
      , city
      , state
      , zip
      , email
      );
    
    if (response.error != null || response.value == null)
    {
      __context.RedirectToErrorPage();
      return false;
    }
    
    return true;
  }
  
  function ParticipantAnswerSubmit()
  {
    var participantAnswerElements = GetParticipantAnswerLaunchNetElements();
    
    var idBased = new Array();
    var idBasedCount = 0;
    var openEnded = new Array();
    var openEndedCount = 0;
    
    for (var i = 0; i < participantAnswerElements.length; i++)
    {
      var participantAnswer = new Object();
      
      participantAnswer.QuestionId = participantAnswerElements[i].Question;
      participantAnswer.Answer = GetElementValue(participantAnswerElements[i].LaunchNetElement);
      
      if (participantAnswerElements[i].IsOpenEnded)
      {
        openEnded[openEndedCount++] = participantAnswer;
      }
      else
      {
        idBased[idBasedCount++] = participantAnswer;
      }
    }
    
    var response;
    if (idBasedCount > 0)
    {
      response = __context.GetFicoServicesClientProxy().AddParticipantAnswers(idBased, false);
      if (response.error != null || response.value == false)
      {
        __context.RedirectToErrorPage();
        return false;
      }
    }
    
    if (openEndedCount > 0)
    {
      response = __context.GetFicoServicesClientProxy().AddParticipantAnswers(openEnded, true);
      if (response.error != null || response.value == false)
      {
        __context.RedirectToErrorPage();
        return false;
      }
    }
    
    return true;
  }
  

/* ***********************************************************************************
-  Page Validation
************************************************************************************ */

  function OnValidationRequiredCheck(launchNetElementClicked)
  {
    return commands.HandleValidationRequiredCheck(launchNetElementClicked);
  }

  function OnValidateLaunchNetElements(validatableLaunchNetElements)
  {
    var launchNetElementsValid = true;
    var validator = new FicoServicesValidator();

    //validate any special elements here
    for (var i = 0; i < validatableLaunchNetElements.length; i++)
    {
      if (!validator.Validate(validatableLaunchNetElements[i]))
      {
        launchNetElementsValid = false;
      }
    }

    return launchNetElementsValid;
  }
}