﻿var VALIDATION_TYPES = { NONE: 0, CRITICAL_ONLY: 1, ALL: 2 };

function ValidationSetup(formSelector)
{
    if($('div.validationContainer').length < 1) return;
    
    var container = $('div.validationContainer')[0];
    
    if(container === undefined) return false;
    
    var isAccordian = false;
    setup = function() {
        $('body').prepend(container);
        $('#validationFooterMenu').show();
        $(formSelector).bind('submit', Form_OnSubmit);
        $(formSelector + ' input[type=submit]').bind('click', Submit_Clicked);
        
        $('#validationClose',container).click(Close_Validation);
        $('#validationDock',container).click(Dock_Undock);

        if ($('div.accordian').length > 0) isAccordian = true;

        $("input[type='submit']").click(function() {
            setTimeout(function() {
                $("input[type='submit']").attr("disabled", "true");
                return true;
            }, 10);
        });
    };
    
    
    
    var buttonClassPressed = null;

   Submit_Clicked = function(e)
   {
       buttonClassPressed = e.target.className;
   };
   
   Close_Validation = function(e) {
   $("input[type='submit']").removeAttr("disabled");
        $(container).hide();
        $('#pnlContent').removeClass('HasValidation');
   };
   
   
   Dock_Undock = function(e)
   {
        var currentPosition = $(container).css('position');
        var newPosition,linkTxt,linkTitle;
        if(currentPosition == 'fixed')
        {
            newPosition = 'absolute';
            linkTxt = 'Undock';
        }
        else
        {
            newPosition = 'fixed'
            linkTxt = 'Dock';
        }
        
        $(container).css('position',newPosition);
        $(this).text(linkTxt);
   };
   
   Show_ValidationPanel = function() 
   {
       $(container).show();
       $('#pnlContent').addClass('HasValidation');
       $(container).css('position','fixed');
       $('#validationDock',container).text('Dock');
    };

   Form_OnSubmit = function(e) {
       var mode = GetValidationMode();
       if(mode == VALIDATION_TYPES.NONE) return true;
         
       var validator = new FormValidator(formSelector, mode);
       validator.Run();

       if (validator.HasErrors()) 
       {
           Show_ValidationPanel();
           errors = validator.GetErrors();

           $('#validationContent',container).html('').html(validator.GetErrorsHTML());
           $('#validationInner label',container).click(ScrollToInput);
           
           setTimeout(function() {
                $("input[type='submit']").removeAttr("disabled");
                return true;
            }, 10);
            
           
            
           MarkInvalidFields(errors);

           delete validator;
           return false;
       }
       else 
       {
           return checkXSS();
       }
   };

   GetValidationMode = function() {
       var mode
       if (buttonClassPressed.isNullOrEmpty() || buttonClassPressed.contains('ValidationCriticalOnly')) mode = VALIDATION_TYPES.CRITICAL_ONLY;
       else if (buttonClassPressed.contains('ValidationAll')) mode = VALIDATION_TYPES.ALL;
       else if (buttonClassPressed.contains('NoValidation')) mode = VALIDATION_TYPES.NONE;

       buttonClassPressed = null;
       return mode;
   };

   ScrollToInput = function(e) {
       e.preventDefault();
       var elementID = $(e.target).attr('for');
       var e = $('#' + elementID)[0];
       var t = $(e).position().top - 275;
       var l = $('#frmMain label[for=' + elementID + ']').not('.errmsg')[0];

       $(l).addClass('HighlightedField');
       $(e).addClass('HighlightedField');

       if (isAccordian) ExpandAccordian(e);

       if (e.nodeName != 'SELECT' || !(/radio|checkbox|/i.test(e.type))) e.focus();

       if (!isAccordian) {
           $.scrollTo(t, 800, function() {
               setTimeout(function() {
                   $(e).removeClass('HighlightedField');
                   $(l).removeClass('HighlightedField');
               }, 800);
           });
       }
   };

   ExpandAccordian = function(element) {
       var accordianParts = $('div.accordian #groupe');
       var selectedPart = $(element).parents('#groupe')[0];
       var index = jQuery.inArray(selectedPart, accordianParts);

       var currentIndex = -1;

       if ($('div.accordian #groupe.ui-accordion-content-active').length > 0) {
           var currentlyActiveHeader = $('div.accordian h3.ui-state-active')[0];
           var accordianHeaderParts = $('.ui-accordion-header');
           currentIndex = jQuery.inArray(currentlyActiveHeader, accordianHeaderParts);
       }
       if (index != currentIndex) {
           $('div.accordian').accordion('activate', index);
       }
   };



  
    setup();
};

var validationItems = {};
function AddValidationItem(controlID, validationType, message) 
{
    validationItems[controlID + '_' + validationType] = message;
};

function MarkInvalidFields(errors)
{
    $('.HasError').removeClass('HasError');
    jQuery.each(errors,function(i,error)
    {
        $(error.element).addClass('HasError');
    });
};
    
function FormValidator()
{
    var me = this;
    var errors = new Array();
    
    var formSelector = arguments[0];
    var validationMode = (arguments[1] === undefined) ? VALIDATION_TYPES.ALL : arguments[1];
    
    var matchRegExp;
    if (validationMode == VALIDATION_TYPES.ALL) matchRegExp = /(GWV_(?:[^ ]|$)+)/gi;
    else matchRegExp = /(!GWV_(?:[^ ]|$)+)/gi;
    
    this.Run = function()
    {
        $(formSelector + ' .Validation').each(RunValidationsOnElement);
    };

    this.GetErrors = function()
    {
        return errors;  
    };
    
    this.HasErrors = function()
    {
        return (errors.length > 0);
    };
    
    this.GetErrorsHTML = function()
    {
        var html = "<ul>";
        jQuery.each(errors,function(i,error)
        {   
            html += String.format("\t<li class='validationError'><label class='errmsg' for='{0}'>{1}</label></li>\n",error.element.id, error.message);
        });
        
        html += "</ul>";
        
        return html;     
    };
    
    // Runs validations on a single element.
    RunValidationsOnElement = function(index, element) {
        var classes = element.className;
        var matches = classes.match(matchRegExp);
        if (matches === null) return;
        if(elementType(element) == 'span') element = element.firstChild;
        var continueValidating = true;
        
        jQuery.each(matches, function(i, c) 
        {
            if(!continueValidating) return;
            
            var m = c.match(/GWV_([a-z]+)(?:\[.+\])?/i);
            var validationType = m[0];
            var validationTrigger = m[1];
            
            var validation = validations[validationTrigger];
            if (validation === undefined) return true;

            var param = null;
            if (validation.hasParam === true) {
                var m = c.match(/\[(.+)\]/);
                if (m !== null && m[1] !== undefined) param = m[1];
            }

            if (validation.method(element, param) == false) {
                var error = { element: element, message: getErrorMessage(validationType, element) };
                errors.push(error);
                if(validation.critical) continueValidating = false;
            }
        });

        return;
    };

    getErrorMessage = function(trigger, element) {
        var fieldID = element.id;
        if (fieldID.indexOf('_') > 0) fieldID = fieldID.split('_')[0];
        var msg = validationItems[fieldID + '_' + trigger];
        return msg;
    };

    checkable = function(element)
    {
        return /radio|checkbox/i.test(element.type);
    };

    elementType = function(element)
    {
        return element.nodeName.toLowerCase();
    };
    
    var dateFormats =
	{
		'dd/MM/yyyy':	{ regexp: /^([0-9]{2})\/([0-9]{2})\/([0-9]{4})$/, dateParts: {d:1, m: 2, y: 3} },
		'dd/MM/yy': 	{ regexp: /^([0-9]{2})\/([0-9]{2})\/([0-9]{2})$/, dateParts: {d:1, m: 2, y: 3} },
		'MM/dd/yyyy': 	{ regexp: /^([0-9]{2})\/([0-9]{2})\/([0-9]{4})$/, dateParts: {d:2, m: 1, y: 3} }
	};
    

	var methods =
    {
        required: function(element, param) {
            var val = element.value;
            
            if(elementType(element) == 'select')
            {
                val = $(element).val();
                return val && val.length > 0;
            }
            else
            {
                return $.trim(val).length > 0;
            }
        },

        compareValue: function(element, param) {
            return ($(element).val() == param);
        },

        integer: function(element, param) {
            var v = element.value;
            return (isNaN(parseInt(v, 10)) || (v.indexOf('.') >= 0)) ? false : true;
        },

        decimalNumber: function(element, param) {
            var v = element.value;
            return (isNaN(parseFloat(v))) ? false : true;
        },

        date: function(element, param) {
            var date = element.value;
            if(date == '') return true;
            
            var dateFormat = dateFormats[param];
            if (dateFormat === undefined) return false;

            var matches = date.match(dateFormat.regexp);
            if (matches === null) return false;

            var dateParts = { day: matches[dateFormat.dateParts.d], month: matches[dateFormat.dateParts.m], year: matches[dateFormat.dateParts.y] };

            // create string of date in US format for checking.
            var dateStr = dateParts.month + '/' + dateParts.day + '/' + dateParts.year;
            if (isNaN(Date.parse(dateStr))) return false;

            return true;
        },

        wordCount: function(element, param) 
        {
            var v = element.value;
            var maxWords = parseInt(param, 10);
            var m = v.match(/[^ ]( |$)/g);
            var words = (m === null) ? 0 : m.length;
            return (words <= maxWords);
        },
        
        email : function(element, param)
        {        
            var value = element.value;            
            if(value == null || value == '') return true;
            var r = ( value.match(/\w+(?:[-+.']\w+)*@\w+(?:[-.]\w+)*\.\w+(?:[-.]\w+)*/) !== null) ;
            return r;
        }
    };
    
    var validations =
    {
        Required:       { method: methods.required, critical : true },
        Decimal:        { method: methods.decimalNumber, critical : true },
        Integer:        { method: methods.integer, critical : true},
        CompareValue:   { method: methods.compareValue, hasParam: true, critical : false },
        Date:			{ method: methods.date, hasParam: true, critical : true },
        Email:          { method: methods.email, critical : false },
        WordCount:      { method: methods.wordCount, hasParam: true, critical : false }
    };
};


String.prototype.isNullOrEmpty = function() { return (this === null || this === undefined || (jQuery.trim(this) == '')); };

String.prototype.contains = function(str) { return (this.indexOf(str) == -1) ? false : true; };

String.format = function() {
  var s = arguments[0];
  for (var i = 0; i < arguments.length - 1; i++) 
  { var reg = new RegExp("\\{" + i + "\\}", "gm"); s = s.replace(reg, arguments[i + 1]); }
  return s;
};




// XSS Stuff - removes script text from form input type text and textarea.

function stringReplaceAll(target, find, replace)
{
	while(target.indexOf(find) > -1)
	{			    
		target = target.replace(find, replace);
	}			
	 
	return target;
}


function checkXSS()
{
	var xssValid = true;
		
	$('input:text').each(function(i)
	{	
		if(xssValid)
		{
			var regex = new RegExp("<[^>]*>");
			var containsHtml = regex.test($('input:text')[i].value);
			
			if(containsHtml)
			{
				$('input:text')[i].focus();
				xssValid = false;
			}
		}
	});
	
	if(xssValid)
	{
		$('textarea').each(function(i)
		{	
			if(xssValid)
			{
				var regex = new RegExp("<[^>]*>");						
				var containsHtml = regex.test($('textarea')[i].innerText);
				
				if(containsHtml)
				{
					$('textarea')[i].focus();
					xssValid = false;
				}
			}
		});
	}
	
	if(!xssValid)
	{
		var autoCleanUp = confirm('One of your items contains contains invalid content (this is mainly down to using brackets i.e. < and or >, if you would like this cleaned up automatically, please press OK, otherwise press cancel to remove these elements yourself');
		
		if(autoCleanUp)
		{
		    
			$('input:text').each(function(i)
			{	
				$('input:text')[i].value = stringReplaceAll($('input:text')[i].value, '<', '(');
				$('input:text')[i].value = stringReplaceAll($('input:text')[i].value, '>', ')');
				
			});
			
			$('textarea').each(function(i)
			{	
				$('textarea')[i].innerText = stringReplaceAll($('textarea')[i].innerText, '<', '(');
				$('textarea')[i].innerText = stringReplaceAll($('textarea')[i].innerText, '>', ')');
				
			});
			
			xssValid = true;
		}
	}
	
	return xssValid;
}
