/// <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");
  commands.Add("TypingToolSubmit");
  
  this.OnPageLoad = OnPageLoad;
  this.OnPageClick = OnPageClick;
  this.OnValidationRequiredCheck = OnValidationRequiredCheck;
  this.OnValidateLaunchNetElements = OnValidateLaunchNetElements;
  
  this.ParticipantSubmit = ParticipantSubmit;
  this.ParticipantUnsubscribeSubmit = ParticipantUnsubscribeSubmit;
  this.ParticipantAnswerSubmit = ParticipantAnswerSubmit;
  this.TypingToolSubmit = TypingToolSubmit;
  
  this.FicoServicesValidator = FicoServicesValidator;
  
  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}$)/;
    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|DR\.|FR|LT|MISS|MS|MS\.|MRS|MRS\.|MR|MR\.|MJR|REV|REV\.|SIST|AGENCY)$/i;
    var regexTestWord = /^(TEST|TESTING|FIRST)$/i;
    var regexLastWord = /^(LAST)$/i;
    var regexBeginSpace = /^[\s]/;

    //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;
    this.HasNoBeginSpace = HasNoBeginSpace;
    
    /***** ERROR MESSAGE CONSTANTS *****/
    var ISNOTTESTWORD = "cannot start with test, testing, or first.";
    var ISNOTTITLE = "cannot be a title.";
    var ISNOTTRIPLEREPEAT = "cannot triple repeat characters.";
    var HASNOFICODELIMITER = "cannot contain the character {.";
    var HASNOFICOCHARS = "cannot contain invalid characters.";
    var ISVALIDSTATE = "is invalid.";
    var ISVALIDZIP = "is invalid.";
    var ISVALIDSSN = "is invalid."
    var ISVALIDPHONE = "is invalid."
    var ISANSWERTEXT = "has invalid characters.";
    var HASNOBEGINSSPACE = "cannot start with space(s).";
    /***** END ERROR MESSAGE CONSTANTS *****/

    function ValidatePrefix(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "HasNoDigits"
          , "HasNoSpaces"
          , "HasNoFicoDelimiter"
          , "HasNoCrLf"
          , "IsMaxLength 4"
          ]
        , "Value for prefix"
        );
    }
      
    function ValidateFirstName(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "IsNotNull"
          , "HasNoBeginSpace"
          , "HasNoDigits"
          , "HasNoCrLf"
          , "HasNoFicoChars"
          , "HasNoFicoDelimiter"
          , "IsNotTitle"
          , "IsNotTripleRepeat"
          , "IsNotTestWord"
          , "IsMinLength 2"
          , "IsMaxLength 15"
          ]
        , "Value for first name"
        );
    }

    function ValidateMiddleInitial(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "HasNoDigits"
          , "IsAlpha"
          , "HasNoSpaces"
          , "HasNoFicoDelimiter"
          , "HasNoCrLf"
          , "IsMaxLength 1"
          ]
        , "Value for middle initial"
        );
    }

    function ValidateLastName(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "IsNotNull"
          , "HasNoBeginSpace"
          , "HasNoCrLf"
          , "HasNoDigits"
          , "HasNoFicoChars"
          , "HasNoFicoDelimiter"
          , "IsNotTripleRepeat"
          , "IsMaxLength 20"
          , "IsMinLength 2"          
          ]
        , "Value for last name"
        );
    }

    function ValidateSuffix(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "HasNoCrLf"
          , "HasNoFicoDelimiter"
          , "IsMaxLength 7"
          ]
        , "Value for suffix"
        );
    }

    function ValidateAddress1(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "IsNotNull"
          , "HasNoCrLf"
          , "HasNoFicoDelimiter"
          , "IsMaxLength 50"
          ]
        , "Value for address"
        );
    }

    function ValidateAddress2(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "HasNoCrLf"
          , "HasNoFicoDelimiter"
          , "IsMaxLength 50"
          ]
        , "Value for address2"
        );
    }

    function ValidateCity(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "IsNotNull"
          , "HasNoDigits"
          , "HasNoCrLf"
          , "HasNoFicoDelimiter"
          , "IsMinLength 1"
          , "IsMaxLength 20"
          ]
        , "Value for city"
        );
    }

    function ValidateState(launchNetElement)
    {
      return this.StandardValidation(launchNetElement, "IsValidState", "Value for state abbreviation");
    }

    function ValidateZip(launchNetElement)
    {
      return this.StandardValidation(launchNetElement, "IsValidZip", "Value for zip code");
    }

    function ValidateSSN(launchNetElement)
    {
      return this.StandardValidation(launchNetElement, "IsValidSSN", "Value for social security number");
    }

    function ValidatePhone(launchNetElement)
    {
      return this.StandardValidation(launchNetElement, "IsValidPhone", "Value for phone number");
    }

    function ValidateAnswerText(launchNetElement)
    {
      return this.StandardValidation
        (
        launchNetElement
        ,
          [
          "IsNotNull"
          , "HasNoCrLf"
          , "HasNoFicoDelimiter"
          , "IsValidAnswerText"
          , "IsMaxLength 50"
          ]
        );
    }

    function IsNotTestWord(value, validationResult)
    {
      value = value.trim();
      return this.IsValidRegex(value, validationResult, regexTestWord, true, ISNOTTESTWORD);
    }

    function IsNotTitle(value, validationResult)
    {
      value = value.trim();
      return this.IsValidRegex(value, validationResult, regexTitle, true, ISNOTTITLE);
    }

    function IsNotTripleRepeat(value, validationResult)
    {
      value = value.trim();
      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);
    }   
    
    function HasNoBeginSpace(value, validationResult)
    {
        return this.IsValidRegex(value, validationResult, regexBeginSpace , true, HASNOBEGINSSPACE);
    }
  }
  
  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(treatmentCode)
  {
    //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();
    
    var treatmentCode = (typeof treatmentCode == "undefined") ? "" : treatmentCode;

    //submit participant
    var response = __context.GetServiceClientProxy('FicoServices').AddParticipant
      (
      prefix
      , firstName
      , middleInitial
      , lastName
      , suffix
      , address1
      , address2
      , city
      , state
      , zip
      , treatmentCode
      );
    
    if (response.error != null || response.value == null)
    {
      __context.RedirectToErrorPage();
      return false;
    }
    
    //also submit any participant answers on the page
    return ParticipantAnswerSubmit();
  }
  
  function ParticipantUnsubscribeSubmit(treatmentCode)
  {
    //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();

    //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 treatmentCode = (typeof treatmentCode == "undefined") ? "" : treatmentCode;

    var response = __context.GetServiceClientProxy('FicoServices').AddParticipantUnsubscribe
      (
      prefix
      , firstName
      , middleInitial
      , lastName
      , suffix
      , address1
      , address2
      , city
      , state
      , zip
      , treatmentCode
      );
    
    if (response.error != null || response.value == null)
    {
      __context.RedirectToErrorPage();
      return false;
    }
    
    //also submit any participant answers on the page
    return ParticipantAnswerSubmit();
  }
  
  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.Answer = GetElementValue(participantAnswerElements[i].LaunchNetElement);
      
      if (participantAnswerElements[i].LaunchNetElement.Element.type == "checkbox" &&
          (participantAnswer.Answer.length < 1 || participantAnswer.Answer.trim().length < 1))
      {
        //if a checkbox and no answer was provided, use the "unanswered" answer from client id
        //ie, "field<question,answer>", answer would be used for a checkbox that was unchecked
        participantAnswer.Answer = participantAnswerElements[i].Answer;
      }

      if (participantAnswer.Answer.length > 0 && participantAnswer.Answer.trim().length > 0)
      {
        participantAnswer.QuestionId = participantAnswerElements[i].Question;
      
        //only visible and enabled elements are submitted
        if (participantAnswerElements[i].LaunchNetElement.Element.style.visibility != 'hidden'
          && participantAnswerElements[i].LaunchNetElement.Element.style.display != 'none'
          && !participantAnswerElements[i].LaunchNetElement.Element.disabled)
        {
          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;
  }
  
function TypingToolSubmit()
  {
    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.Answer = GetElementValue(participantAnswerElements[i].LaunchNetElement);
      
      if (participantAnswerElements[i].LaunchNetElement.Element.type == "checkbox" &&
          (participantAnswer.Answer.length < 1 || participantAnswer.Answer.trim().length < 1))
      {
        //if a checkbox and no answer was provided, use the "unanswered" answer from client id
        //ie, "field<question,answer>", answer would be used for a checkbox that was unchecked
        participantAnswer.Answer = participantAnswerElements[i].Answer;
      }

      if (participantAnswer.Answer.length > 0 && participantAnswer.Answer.trim().length > 0)
      {
        participantAnswer.QuestionId = participantAnswerElements[i].Question;
      
        //only visible and enabled elements are submitted
        if (participantAnswerElements[i].LaunchNetElement.Element.style.visibility != 'hidden'
          && participantAnswerElements[i].LaunchNetElement.Element.style.display != 'none'
          && !participantAnswerElements[i].LaunchNetElement.Element.disabled)
        {
          if (participantAnswerElements[i].IsOpenEnded)
          {
            openEnded[openEndedCount++] = participantAnswer;
          }
          else
          {
            idBased[idBasedCount++] = participantAnswer;
          }
        }
      }
    }

    if (idBased != null && idBased.length > 0) {
        
        var qvaQId = idBased[0].QuestionId;
        var qvaAId = idBased[0].Answer;
        var response = OrenciaClientProxy.SubmitTypingToolParticipantAnswer(qvaQId, qvaAId);
          
          if (response.error != null || response.value == false)
          {
            __context.RedirectToErrorPage();
            return false;
          }
          
      
		window.location = response.value;
    }
    
    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;
  }
}