// Класс проверки заполнения формы

function checkForm(formId)
{
    this.error_messages = {
        'empty_input_fields': 'Заполнены не все поля формы!'
    }
    
    // Сcылка на объект тега form, 
    // ссылаемся по id.
    this.formObj = document.getElementById(formId);
    
    // Поля, которые нужно будет проверять JavaScript-ом на клиенте.
    this.checkedFields = new Array();
    
    /**
    * Метод сканирует поля формы и помещает в массив ссылки на текстовые
    * области типа text, password и textarea.
    * @param void
    * @return array массив со ссылками на текстовые поля
    * ИСПОЛЬЗУЕТСЯ В ФУНКЦИЯХ: put_num_chars, is_empty_input, put_focus
    */
    this.get_input = function()
    {
        var my_array = new Array();
        var j=0;
    
        for (var i=0; i < this.formObj.elements.length; i++)
        {
            var type = this.formObj.elements[i].type;
            
            if (type)
            {
                if (type.toLowerCase()=="text" || type.toLowerCase()=="password" || type.toLowerCase()=="textarea") {
                    my_array[j++] = this.formObj.elements[i];
                }
            }
        }
        
        return my_array;
    }
    
    // Массив имён всех текстовых областей формы (input= text, password, textarea).
    this.arrayTextInputs = this.get_input();
    
    // Проверка, ссылаемся ли мы на форму.
    if (!this.formObj || this.formObj == null || this.formObj.tagName.toUpperCase() != "FORM") {
        return false;
    }

    /**
    * Метод устанавливает фокус на незаполненные 
    * текстовые поля формы. 
    */
    this.put_focus = function(flag)
    {
        //    АЛГОРИТМ:
        //    Если поле заполнено, то мы переходим к следующему полю, указанному в массиве
        //        Если оно пусто, то ставим фокус и выходим.
        //        Иначе продолжаем цикл с помощью continue.
        //    Если поле не заполнено, ставим фокус, выходим.   
        for (var i=0; i<this.arrayTextInputs.length; i++)
        {
            if (this.arrayTextInputs[i].value != "")
            {
                if (this.arrayTextInputs[i+1] && this.arrayTextInputs[i+1].value != "") {
                    continue;
                }
                else if(this.arrayTextInputs[i+1]){
                    //if(document.getElementById(form_id).elements[i+1].offsetHeight != 0){
                    this.arrayTextInputs[i+1].focus();
                    //}
                    break;
                }
            }
            else
            {
                //if(document.getElementById(form_id).elements[i].offsetHeight != 0){
                this.arrayTextInputs[i].focus();
                //wasFocus = true;
                //}
                break;
            }
        }
    }
    
    
    /**
    * Метод проходит по форме.
    * Если хотя бы одно поле пустое (не содержит данных или содержит проблы и пр. не word-символы),
    * то функция возвращает false.
    * В качестве аргументов метода можно указать список имён полей,
    * на которых действие функции не должны распростроняться.
    * ВЗАИМОДЕЙСТВУЮЩИЙ МЕТОД: noempty, in_array
    */
    this.is_empty_input = function()
    {
        var arglen = arguments.length;
        var args = new Array();
        
        // Зачем это делаем - сам не понимаю. Но так работает.
        // Выражение arguments.in_array не работает.
        for (var i=0; i<arglen; i++) {
            args[i] = arguments[i];
        }
        
        for (i=0; i<this.arrayTextInputs.length; i++)
        {
            // Если аргументы метода имеются и имя данного текстового
            // поля присутствует в массиве аргументов, то значит
            // это поле проверять не нужно. Пропускаем. 
            if (arglen && args.in_array(this.arrayTextInputs[i].name) != -1) {
                continue;
            }
                
            var str = this.arrayTextInputs[i].value;
            var len = str.length;
            var err = null;
        
            if (len == 0) {
                err = i;
                break;
            } else {
                if (!str.noempty()) {
                    err = i;
                    break;
                }
            }
        }
    
        if (err != null)
        {
            alert(this.error_messages['empty_input_fields']);
            this.arrayTextInputs[err].focus();
            return false;
        }
    
        return true;
    }

    /*
    * Метод идёт по массиву this.checkedFields и проверяет значения полей, указанных в этом массиве.
    * Массив объявляется в шаблоне, в следующем виде:
    
    objectForm.checkedFields = new Array(
            ["текст ошибки", "user_name",      "text"],
            ...
            ["текст ошибки", "user_age_day",   "select-one", [0, "0", ""] ],
            ...
            ["текст ошибки", "user_sex",       "radio"]
        );
    
    * где Первое поле подмассива - текст ошибки, которую необходимо вывести.
    *     Второе поле - имя элемента формы, которое проверяется.
    *     Третье поле - тип поля.
    *     Четвёртое поле - массив, присутствует у элементов формы типа select-one.
    *     В этом массиве перечислены значения, при совпадении которых со значениями select-ов 
    *     проверка будет возвращать false, т.е. признак не выбранного списка.
    */
    this.isEmptyThisFields = function()
    {
        for (var i=0; i<this.checkedFields.length; i++) 
        {
            var str_err = '';
            
			var f_err = this.checkedFields[i][0];
			var f_name = this.checkedFields[i][1];
			var f_type = this.checkedFields[i][2];
			var f_val = this.checkedFields[i][3];
			
			if (!this.formObj[f_name])
			{
                continue;
            }
			
            // на всякий случай обращаем в нижний регистр типа поля
            f_type = f_type.toLowerCase();
            
            // Если текущее поле, определённое в массиве checkedFields определено как text
            // и поле с такм именем реально существует и является текстовым, то делаем проверку.
            if (f_type == "text" && f_name && 
			   (this.formObj[f_name].type == "text"
                || this.formObj[f_name].type == "password"
                || this.formObj[f_name].type == "textarea") )
            {
				
                // Если требуется сделать проверку на noempty
                if (f_val.in_array("noempty") != -1)
                {    // Ошибка - поле пустое.
                    if (!this.formObj[f_name].value.noempty())
                    {
                        str_err += f_err + "\n";
                        alert(str_err);
                        this.formObj[f_name].focus();
                        return false;
                    }
                }
				
                // Если требуется сделать проверку на is_mail
                if (f_val.in_array("is_mail") != -1)
                {
                    // Ошибка - это не email.
                    if (!this.formObj[f_name].value.is_mail())
                    {
                        str_err += f_err + "\n";
                        alert(str_err);
                        this.formObj[f_name].focus();
                        return false;
                    }
                }
            }
            // Если текущее поле, определённое в массиве checkedFields определено как select-one
            // и поле с такм именем реально существует и является текстовым, то делаем проверку.
            else if (f_type == "select-one" && this.formObj[f_name] != null 
			         && this.formObj[f_name].type == "select-one") 
            {
                // Ошибка - не выбрано значение из списка.
                if (f_val.in_array(this.formObj[f_name].value) != -1) {
                    str_err += f_err + "\n";
                    alert(str_err);
                    this.formObj[this.checkedFields[i][1]].focus();
                    return false;
                }
            }
            // Радио-кнопки.
            else if (f_type == "radio")
            {   
                var link = this.formObj[f_name];
                str_err += f_err + "\n";
                
                // Ошибка - не выбрана ни одна кнопка.
                if (!isCheckRadio(link)) {
                    alert(str_err);
                    link.item(0).focus();
                    return false;
                }
            }
        } // end for
        
        return true;
    }
}// конец класса




/*************************************************************
* Проверка правильности введенного изображения для загрузки
*************************************************************/

/**
* Ищет в строке окончания похожее на один из типов изображений,
* перечисленных в массиве CONFIGS["TRUE_IMAGES_TYPES"].
* Возвращает TRUE, если такое окончание найдено, FALSE при неудаче.
* ИСПОЛЬЗУЕТСЯ В ФУНКЦИЯХ: check_image_in_input
* ВЗАИМОДЕЙСТВУЮЩИЙ МЕТОД: in_array
* 
* @param string путь к файлу-изображению
* @return boolean
*/
function is_image(path)
{
    var type = path.substr(path.lastIndexOf(".")+1).toLowerCase();

    if (CONFIG["TRUE_IMAGES_TYPES"].in_array(type) != -1) {
        return true;
    }

    return false;
}

/**
* Проверяет значение поля выбора файла на предмет
* соответствия правилному расширению рисунка и в случае, если указан путь
* не к файлу-изображению, то выдает соответствующее предупреждение 
* и убирает из текстового поля путь к несоответствующему файлу.
* @param string путь до файла с машины пользователя
* @return boolean
*/
function check_image_in_input(_this)
{
    if (!_this.value) {
        return;
    }
    
    if (!is_image(_this.value))
    {
        _this.value = '';
        alert("Недопустимый тип изображения!\n" + 
        "Допустимы лишь следующие типы изображений: " +
        CONFIG["TRUE_IMAGES_TYPES"].toString());
        return false;
    }
    
    return true;
}

/**
* Возвращает имя файла из строки
* Т.е. из строки-пути 
* C:\documents\Документы\Фотографии\Irachka.jpg
* функция вернёт Irachka.jpg
*/
String.prototype.getFilenameInString = function(get_ext)
{
    if (this == '' || this == null)
    {
        return '';
    }
    
    var filename = this.substring(this.lastIndexOf("\\")+1, this.length);
    
    // возвратить вместе с расширением
    if (get_ext)
    {
        return filename;
    }
    // возвратить без расширения
    else
    {
        return filename.substring(0, filename.lastIndexOf('.'));
    }
}

/*************************************************************
* Установка состояний формы
*************************************************************/

/** 
* Cтавит checked на элемент elname (имя элемента) под индексом idx.
* Используется при событии onclick, когда нажимают текстовую метку 
* перед радиокнопкой или чекбоксом.
* Если элемент, от имени которого используется функция, является checkbox, 
* то повторный клик снимает с него checked-выделение.
* @param string elname имя группы элементов radio или checkbox 
* @param int idx индекс элемента, который необходимо активизировать
* @return void
*/
function check(elname, idx)
{
    var lnk = document.getElementsByName(elname)[idx];

    if (lnk.type == "radio")
    {
        lnk.checked = true;
    }
    else if(lnk.type == "checkbox")
    {
        if (lnk.checked == true) {
            lnk.checked = false;
        }
        else {
            lnk.checked = true;
        }
    }
    
    return true;
}

/**
* Функция принимает ссылку на наборв радиокнопок и
* возвращает true, если набор radio-кнопок активирован, т.е. 
* отмечено значение из набора radio-кнопок, и false в обратном случае.
* Используется в методе: isEmptyThisFields
*/
function isCheckRadio(id)
{
    for (var i=0; i<id.length; i++) {
        if (id.item(i).checked) {
            return true;
        }
    }
    
    return false;
}

/**
* Очищает форму с идентификатором id_form:
* текстовые поля любого рода очищаются,
* значение select становится в 0-й элемент option,
* с radio и checkbox снимается выделение.
* 
* @param string id формы
* @return void
*/
function clear_form(id_form)
{
    var id_form = document.getElementById(id_form);
    
    for (i=0; i<id_form.elements.length; i++)
    {
        var lnk = id_form.elements.item(i);
        
        switch(lnk.tagName.toUpperCase())
        {
            case 'INPUT':
                if (lnk.type.toLowerCase() == 'text' 
                    || lnk.type.toLowerCase() == 'password'
                    || lnk.type.toLowerCase() == 'file')
                {
                    lnk.value = '';
                }
                else if (lnk.type.toLowerCase() == 'checkbox')
                {
                    lnk.checked = false;
                }
                else if (lnk.type.toLowerCase() == 'radio')
                {
                    lnk.checked = false;
                }
            break;
            
            case 'SELECT':
                if(lnk.multiple)
                {
                    lnk.selectedIndex = -1;
                }
                else
                {
                    lnk.selectedIndex = 0;
                }
            break;
            
            case 'TEXTAREA':
                lnk.value = '';
            break;
        }
    }
}

/**
* Функция вырезает все не числовые символы из поля ввода,
* на который указывает _this (ссылка на this поля ввода).
* Вызывается по событию onkeyup, например.
*/
function filterFieldDigit(_this, _alert)
{
	if (_alert == null)
	{
		_alert = 'В данное поле допускается вводить только цифры!'; 
	}
    
	var newstr = '';
	var str = _this.value;
	var len = _this.value.length;
	var k = 0;
	
	for (var i = 0; i<len; i++)
	{
		var chr = str.substring(i, i+1);
		if (/[0-9]/.test(chr))
		{	
			newstr = newstr + chr;
		}
		else
		{
			if (_alert && !k)
			{
				alert(_alert);
				k = 1;
			}
		}
	}
	
	_this.value = newstr;
	_this.focus();
}


/**
* Функция вырезает все символы за исключением a-z,0-9,-,_ из поля ввода,
* на который указывает _this (ссылка на this поля ввода).
* Вызывается по событию onkeyup, например.
*/
function filterFieldAlnum(_this, _alert)
{
	var newstr = '';
	var str = _this.value;
	var len = _this.value.length;
	var k = 0;
	
	for (var i = 0; i<len; i++)
	{
		var chr = str.substring(i, i+1);
		if (/[0-9a-z_-]/i.test(chr))
		{	
			newstr = newstr + chr;
		}
		else
		{
			if (_alert && !k)
			{
				alert(_alert);
				k = 1;
			}
		}
	}
	
	_this.value = newstr;
	_this.focus();
}