// used for some simple form validation for the BACKEND! 
// If you want to use on the front end, well, thats ok - just make sure to validate on the backend too.

/**
 * Validator
 * plank_validator.js
 * 
 * Meant to be example App. Template.
 * 
 * @package YAHOO.Plank
 * @author  Mitchell Amihod 2008-08-14
 */

(function(){

  YAHOO.namespace('Plank.util.validator');
  
  var Dom = YAHOO.util.Dom,
      Lang = YAHOO.lang,
      Event = YAHOO.util.Event,
      putils = YAHOO.Plank.util,
      containerFactory = YAHOO.Plank.util.container,
      bb =  YAHOO.namespace('Plank.bb');
  
  var names = {
    ERROR_PANEL_ID        : 'plank-errorpanel',
    FORM_VALIDATE_CLASS   : 'plank-validator',
    FIELD_REQUIRED_CLASS  : 'required',
    FIELD_EMAIL_CLASS     : 'email',
    FIELD_CAKEMAIL_CLASS  : 'cakemail',
    FIELD_MAKE_LIVE_NAME  : 'is_visible',
    ERROR_CLASS           : 'error',
    LABEL_ID_PREFIX       : 'label-',
    ERROR_UL_ID           : 'ul-errors',
    EMAIL_REGEX           : /\w{1,}[@][\w\-]{1,}([.]([\w\-]{1,})){1,3}$/
  };

  //Used to check if EMAIL is already on list. 
  var CAKEMAIL_VALIDATION_URL = 'account/check_cakemail/';

  var errors = []; //Error collector


  /**
   * figure out error msg to display based on inputs label
   *
   * @param string name. Should be in form of name_en or name_fr
   * @param string eType Type of error, which we will use to lookup the error message (if it exists). 
   * @return string
   **/
  var fieldError = function (elObj) {

    var fname = elObj.el.name,
        eType = elObj.type;
      
    //check if its a language based field
    //using indexOf, though I suppose I could go one further 
    //and just explcitily check for _en and _fr, but i'd rather have it infer. 
    //we know _en or _fr is ALWAYS in the last 3 chars, so we check from there
    var langIndex = fname.indexOf('_', (fname.length-3));

    var key = fname, //To lookup the label
        lang = false, //field language - used in Admin Error Messaging
        eMessage = ''; //Container to build error message
    
    if(langIndex > -1) {
      key = fname.substring(0,langIndex);
      lang = fname.substring(langIndex+1);      
    }
    
    var label = Dom.get(names.LABEL_ID_PREFIX+key);
    
    eMessage = (Lang.isValue(label)) ? label.innerHTML : fname ;
    
    if(lang) {
        eMessage += ':' + lang;
    }

    //And, check if we have a full string message
    if(bb && bb.langtokens && bb.langtokens[eType]) {
        eMessage += bb.langtokens[eType];
    }
    return eMessage;
    
  };

  /**
   * Build the errors ul to display in the panel. 
   * 
   * @param HTMLCollection errorEls an array of form controls in error.
   **/
  var displayErrors = function(errorEls) {

    //Destroy the old error ul. This is probably not best way? Some tell me please?! probably causes a mem leak or something.
    var oldErrors = Dom.get(names.ERROR_UL_ID);
    if(oldErrors) {
      oldErrors.parentNode.removeChild(oldErrors);
      oldErrors.id = '';
    }

    var ul = document.createElement('ul');
    ul.id = names.ERROR_UL_ID; 

    Dom.batch(errorEls, function(elObj) {     
        var li = document.createElement('li');
        li.innerHTML = fieldError(elObj);
        ul.appendChild(li);
    });
    

    Dom.removeClass(Dom.get(names.ERROR_PANEL_ID), 'hide');    
    //Get the display error panel
     var errorCon = containerFactory(names.ERROR_PANEL_ID, 
        {
          'conType' : 'Panel',
          'modal'   : true,
          'fixedcenter':true,
          //'width' : '660px',
          'visible' : true
        }
      );

    errorCon.appendToBody(ul);    
    errorCon.render();
    
  };

  var processForm = function(e) {
    
    //Reset errors, error collector
    if(errors.length > 0) {
      //Clear out old error styles
      Dom.batch(errors, function(el) {
        Dom.removeClass(Dom.getAncestorByTagName(el,'td'), names.ERROR_CLASS);
      });
    }
    errors = [];

    var form = Event.getTarget(e);

    //Check if its a submit to make live?
    //Assuming if there's no check box, that it needs validating no matter what
    if(!Lang.isUndefined(form[names.FIELD_MAKE_LIVE_NAME]) && (false === form[names.FIELD_MAKE_LIVE_NAME].checked) ) {
      form.submit();
      return true;
    }
    
    //Ok, so we making it live. lets chck all the required fileds.
    Dom.getElementsByClassName(names.FIELD_REQUIRED_CLASS, '', form, function(el) {
      
      if(Lang.trim(el.value) == '') {
        errors.push({'type': names.FIELD_REQUIRED_CLASS, 'el': el});
        Dom.addClass(Dom.getAncestorByTagName(el,'td'), names.ERROR_CLASS);
      }
    });

    //Ok, so we making it live. lets all the emails.
    var checkingCakeMail = false;
    Dom.getElementsByClassName(names.FIELD_EMAIL_CLASS, '', form, function(el) {
      
      //If its not filled in, dont bother
      if(Lang.trim(el.value) != '' && !(names.EMAIL_REGEX.test(el.value) ) ) {
        errors.push({'type': names.FIELD_EMAIL_CLASS, 'el': el});
        Dom.addClass(Dom.getAncestorByTagName(el,'td'), names.ERROR_CLASS);
      }
      
      //We aren't going to do a cakemail check unless its a valid email, so we nest the cakemail check here.
      if( (0 === errors.length) && Dom.hasClass(el, names.FIELD_CAKEMAIL_CLASS)) {
          
          YAHOO.util.Connect.asyncRequest('GET', CAKEMAIL_VALIDATION_URL + el.value, {
              argument: {
                  "form": form,
                  "el" : el
              },
              success: function(o) {
                  if(1 == o.responseText) {
                    errors.push({'type': names.FIELD_CAKEMAIL_CLASS, 'el': o.argument.el});
                    Dom.addClass(Dom.getAncestorByTagName(el,'td'), names.ERROR_CLASS);
                    displayErrors(errors);
                  } else if(0 == o.responseText) {
                    
                    o.argument.form.submit();
                  }
              },
              failure: function(o) {
                  //Let cakemail worry about it if we can't check for some reason.   
                 o.argument.form.submit();
              }
          });

          checkingCakeMail = true;
      }

    });
    
    //Cancel the submit, since the checking cakemail callbacks will handleit.
    if(true === checkingCakeMail) {
        return false;        
    }

    if(errors.length === 0) {
      return true;
    } else {
      putils.scroll([0,0]);
      displayErrors(errors);
		return false;
    }

  };
	YAHOO.Plank.util.validator.processForm = processForm;
   
  	var submitHandler = function(e) {
		
	    Event.stopEvent(e);		
		var result = processForm(e);

		if(result === true) {
			Event.getTarget(e).submit();
		}

	};

  var init = function() {

    //YAHOO.log('validator:init');  

    //Find all forms needing validation
    Dom.getElementsByClassName(names.FORM_VALIDATE_CLASS, 'form', '', function(el) {
      Event.on(el, 'submit', submitHandler, this, true);
    });

  };
  
  YAHOO.Plank.util.validator.init = init;
  
  //Let loader know.
  YAHOO.register("plank_validator", YAHOO.Plank.util, {version: "1", build: "1"}); 

})();
