﻿//Editable grid. Allows in-place grid rows editing and asynchronous updates to server.
//For example see SurveyManagementControl.
(function ($) {

    //TODO: rewrite through class!

    $.handleGridEditClick = function (event) {

        gridEditButton = $(event.target);
        var editableLabel = gridEditButton.parents('tr:first').find('.grid-edit-input');

        if (gridEditButton.data('isEditing') == null) {
            gridEditButton.data('isEditing', false);
        }

        var input = editableLabel.siblings('input');

        var isEditing = gridEditButton.data('isEditing');
        if (isEditing) {
            $.stopEditing(gridEditButton, editableLabel, input);
        } else {
            $.startEditing(gridEditButton, editableLabel, input);
        }

        return false;
    };

    $.stopEditing = function (gridEditButton, editableLabel, input) {
        gridEditButton.data('isEditing', false);
        gridEditButton.text(gridEditButton.data('initialText'));

        editableLabel.text(input.val()).show();
        input.hide();

        //send request
        var entityKey = gridEditButton.siblings('input[type="hidden"]').val();

        var propertyName = input[0].name;
        var objectToSend = { action: $.editableGridSettings.actionParameter };
        objectToSend[$.editableGridSettings.entityKeyName] = entityKey;
        objectToSend[propertyName] = input.val();

        $('#' + $.editableGridSettings.gridUpdatedFieldId).val('true');

        $.post($.editableGridSettings.saveUrl, objectToSend);
    };

    $.startEditing = function (gridEditButton, editableLabel, input) {
        gridEditButton.data('isEditing', true);
        gridEditButton.data('initialText', gridEditButton.text());
        gridEditButton.text($.editableGridSettings.saveButtonText);

        editableLabel.hide();
        input.val(editableLabel.text()).show();
    };

    $.editableGridSettings = {
        saveUrl: '',
        actionParameter: 'saveMaxDuration',
        saveButtonText: 'Save',
        gridUpdatedFieldId: '',
        entityKeyName: ''
    };

    $.fn.editableGrid = function (settings) {
        $.editableGridSettings = $.extend({}, $.editableGridSettings, settings);

        //Here 'this' is the jQuery selection set, over which the editableGrid function was called.
        return this.each(function () {
            //Here 'this' is the DOM child element of the selection set, over which the editableGrid function was called.
            $(this).click($.handleGridEditClick);
        });
    };

})(jQuery);

//Roller. Collapses node tree panel.
(function ($) {
    $.fn.roller = function (configuration) {
		var defaults = {
			useCookies: true
		};

		var options = $.extend(defaults, configuration);

        return this.each(function () {
            $(this)
			    .find(".roller")
			    .toggle(
				    function () {
				        //"this" is roller
				        $(this).parents(".hierarchy-container").find(".group-header").siblings().hide();
				        $(this).siblings().hide();

				        $(this).parents(".hierarchy-container").animate({ width: "35px" }, 300);
				        $(this).removeClass("roll").addClass("unroll");

						if (options.useCookies === true) {
							setCookie("hierarchy-expanded", "false", 30);
						}
				    },
				    function () {
				        //"this" is roller
				        $(this).parents(".hierarchy-container").animate({ width: "300px" }, 300,
						    function () {
						        //"this" is hierarchy-container
						        $(this).find(".group-header").siblings().show();
						        $(this).find(".roller").siblings().show();
						    }
					    );
				        $(this).removeClass("unroll").addClass("roll");

						if (options.useCookies === true) {
							setCookie("hierarchy-expanded", "true", 30);
						}
				    }
			    );

			if (options.useCookies === true) {
				if (getCookie("hierarchy-expanded") === "false") {
					$(".hierarchy-container").find(".roller").trigger("click");
				}
			}
        });
    };

})(jQuery);

//Report range. Used for ReportRangeControl manipulation.
(function ($) {
    $.fn.reportRange = function () {
        return this.each(function () {
            $(this).find(".date-picker")
                .datepicker()
                .attr("readonly", "readonly");

            $(this).find(".data-range-options").disableOptions();
            $(this).find("tr:has(input[type='radio']:checked)").enableOption();

            $(this).find(".data-range-option").click(function () {
                $(this)
                        .parents(".report-range-options")
                        .find(".data-range-options")
                        .disableOptions();

                $(this)
                        .parent()
                        .parent()
                        .enableOption();
            });

            $(this).find(".last-days-input").numeric();
        });
    };

    //acts over the whole table
    $.fn.disableOptions = function () {
        return $(this).each(function () {
            $(this)
				.setSpinEditState(false)
                .find(".options input")
                .attr("disabled", "disabled");
        });
    };

    //acts over the enabled row
    $.fn.enableOption = function () {
        return $(this).each(function () {
            $(this)
				.setSpinEditState(true)
                .find(".options input")
                .removeAttr("disabled");
        });
    };

})(jQuery);

//testsExpander. Expands tests in survey assignments or survey node assignments tables.
(function ($) {
    SurveyAssignmentRow = function(gridRow, options, testsByAssignmentUnitIds) {
		this.gridRow = gridRow;
		this.options = options;
        this.testsByAssignmentUnitIds = testsByAssignmentUnitIds;

		this.testsVisible = false;
        this.viewTestsButton = $('a', gridRow);

		this.assignmentUnitId = this.viewTestsButton.siblings('.assignment-unit-id').text();
		this.testRows = null;

        this.init();
    };

	SurveyAssignmentRow.prototype = {
		init: function() {
			this.viewTestsButton.click(createDelegate(this, this.handleViewTestsButtonClick));

			if(this.options.useTristateCheckbox) {
				var tristateInput = $('.tristate > input', this.gridRow);
				if(tristateInput.length > 0) {
					var allowUndefinedState = tristateInput.val() === 'undefined';
					tristateInput.tristate({allowUndefinedState : allowUndefinedState});

					$('td:not(:first)', this.gridRow).click(function(e){
						$(this).parents('tr').find('.tristate input').tristate('changeState');
					});
				}
			}
		},

		handleViewTestsButtonClick: function(event) {
			this.testsVisible = !this.testsVisible;

			var grid = this.gridRow.parent();

			if(!this.testsVisible) {
				this.testRows.hide();
				this.viewTestsButton.text(this.options.showTests);
			}
			else {
				this.showTestRows();
				this.viewTestsButton.text(this.options.hideTests);
			}

			event.stopPropagation();
			return false;
		},

		showTestRows: function() {
			if(this.testRows != null) {
				this.testRows.show();
				return;
			}
			
			var tests = this.testsByAssignmentUnitIds[this.assignmentUnitId];
			if(tests == null || tests.length == 0) {
				return;
			}

			this.createTestRows(tests);
		},

		createTestRows: function(tests) {
			var testRowDomObjects = [];

			var currentRow = this.gridRow;
			var testsCount = tests.length;
			for(var i = 0; i < testsCount; i++) {
				var test = tests[i];
				var surveyIsActive = test.surveyId && this.options.currentSurveyId && test.surveyId == this.options.currentSurveyId;
				var newRow = $('<tr/>', {'class': 'test-info-row'});
				if(!surveyIsActive) {
					newRow.addClass('inactive-survey-row');
				}

				//append columns to the left
				for(var columnIndex = 0; columnIndex < this.options.testNameColumnIndex; columnIndex++) {
					newRow.append($('<td/>'));
				}

				newRow
					.append($('<td/>', {text: test.testName, colspan: this.options.colspanForTestName, 'class': 'test-info-cell'}))
					.append($('<td/>', {text: test.surveyShortName, 'class': 'test-info-cell'}));
				
				var columnsWithValues = 2;
				var columnsToAddCount = this.options.columnsCount - columnsWithValues - this.options.testNameColumnIndex - (this.options.colspanForTestName - 1);
				for(var columnIndex = 0; columnIndex < columnsToAddCount; columnIndex++) {
					newRow.append($('<td/>'));
				}

				currentRow.after(newRow);
				currentRow = newRow;

				testRowDomObjects.push(newRow[0]);
			}

			this.testRows = $(testRowDomObjects);
		},

		defaultOptions: {
			hideTests: 'Hide Tests',
			showTests: 'View Tests',
			columnsCount: 4,
			colspanForTestName: 1,
			testNameColumnIndex: 1,
			currentSurveyId: -1,
			useTristateCheckbox: false
		}
	};

    $.fn.testsExpander = function (options, testsByAssignmentUnitIds) {
        var extendedOptions = $.extend({}, SurveyAssignmentRow.prototype.defaultOptions, options);

		if(extendedOptions.useTristateCheckbox) {
			var table = this.parents('table');
			table.find('tr.asp-grid-view-head input').click(function(){
				if(this.checked) {
					table.find('tr div.tristate input').tristate('check');
				}
				else {
					table.find('tr div.tristate input').tristate('uncheck');
				}
			});
		}

        //Here 'this' is the jQuery selection set, over which the plugin function was called.
        return this.each(function () {
            //Here 'this' is the DOM child element of the selection set, over which the plugin function was called.
            var surveyNodeAssignmentRow = new SurveyAssignmentRow($(this), extendedOptions, testsByAssignmentUnitIds);
        });
    };

})(jQuery);

//surveyNodeAssignments. Allows min and max date changes.
(function ($) {
    SurveyNodeAssignmentRow = function(gridRow, options) {
        this.options = options;

		var surveyId = $('.survey-id', gridRow).text();
		this.maxDurationInDays = this.options.surveyMaxDurationsBySurveyIds[surveyId];
        this.startDateInput = $('.start-date', gridRow);
        this.endDateInput = $('.end-date', gridRow);
		this.assignmentCheckbox = $('input[type="checkbox"]', gridRow);

        this.init();
    };

    SurveyNodeAssignmentRow.prototype = {
        init: function() {
            this.startDateInput.datepicker({ dateFormat: this.options.dateFormat, onSelect: createDelegate(this, this.updateEndDatePicker) });
            this.endDateInput.datepicker({ dateFormat: this.options.dateFormat, onSelect: function(){return false;} });

            this.startDateInput.keydown(function () { return false; });
            this.endDateInput.keydown(function () { return false; });

			this.assignmentCheckbox.click(createDelegate(this, this.handleCheckedChanged));
			this.updateInputsEnabling(!this.assignmentCheckbox[0].checked);

            if(this.assignmentCheckbox[0].checked) {
                //End date and start date should be filled by asp.net control.

                //Also, we do not call setSelectedEndDate.
                //The following situation may be possible: end date was set to survey max duration, then survey max duration was decreased,
                //and now the end date is in the prohibited area.
                this.setEndDateBoundaries(true);
            }
        },

        handleCheckedChanged: function(event, value) {
            var disabled = !this.assignmentCheckbox[0].checked;

			this.updateInputsEnabling(disabled);
        },

		updateInputsEnabling: function(inputsDisabled) {
            var inputs = [this.startDateInput, this.endDateInput];
            for(var i = 0; i < inputs.length; i++) {
	            inputs[i][0].disabled = inputsDisabled;
            }

			var haveNoDates = this.startDateInput.datepicker('getDate') == null || this.endDateInput.datepicker('getDate') == null;
			var enableForTheFirstTime = !inputsDisabled && haveNoDates;
            if(enableForTheFirstTime) {
                //Enable surveys for the first time for earlier disabled setting.
                this.setDefaultDates();
            }
		},

        setDefaultDates: function() {
            var currentDate = new Date();
            this.startDateInput.datepicker('setDate', currentDate);

            this.updateEndDatePicker();
        },
        updateEndDatePicker: function(event) {
            this.setEndDateBoundaries(false);
            this.setSelectedEndDate();

			return false;
        },

        setEndDateBoundaries: function(preserveCurrentDate) {
            var selectedStartDate = this.startDateInput.datepicker('getDate');
            this.endDateInput.datepicker('option', 'minDate', selectedStartDate);

            var maxEndDate = this.getMaxEndDate(selectedStartDate);

            if(!preserveCurrentDate) {
                this.endDateInput.datepicker('option', 'maxDate', maxEndDate);
            }
            else {
                var selectedEndDate = this.endDateInput.datepicker('getDate');
                var useSelectedDate = selectedEndDate != null && maxEndDate != null && selectedEndDate > maxEndDate;
                if(useSelectedDate) {
                    this.endDateInput.datepicker('option', 'maxDate', selectedEndDate);
                }
                else {
                    this.endDateInput.datepicker('option', 'maxDate', maxEndDate);
                }
            }
        },

        getMaxEndDate: function(selectedStartDate) {
            if(!this.maxDurationInDays) {
                return null;
            }

            return this.addDays(selectedStartDate, this.maxDurationInDays);
        },

        setSelectedEndDate: function() {
            var minEndDate = this.endDateInput.datepicker('option', 'minDate'); //minDate is alsways set to the start date
            var maxEndDate = this.endDateInput.datepicker('option', 'maxDate'); //max date may be null

            var selectedEndDate = this.endDateInput.datepicker('getDate');

            var minEndDateMilliseconds = minEndDate.getTime();

            if(maxEndDate == null) {
                if(selectedEndDate == null || selectedEndDate < minEndDate) {
                    var endDate = this.addDays(minEndDate, this.options.defaultDuration);
                    this.endDateInput.datepicker('setDate', endDate);
                }
            }
            else {
                if(selectedEndDate == null || selectedEndDate > maxEndDate || selectedEndDate < minEndDate) {
                    this.endDateInput.datepicker('setDate', maxEndDate);
                }
            }
        },

        addDays: function(startDate, daysCount) {
            var startDateMilliseconds = startDate.getTime();

			//Start date is inclusive date, so we have to substract 1 day, from added days count.
            var daysInMilliseconds = (daysCount - 1) * 24 * 60 * 60 * 1000;
            var endDateMilliseconds = startDateMilliseconds + daysInMilliseconds;
            var endDate = new Date(endDateMilliseconds);

            return endDate;
        },

        defaultOptions: {
            dateFormat: 'yy-mm-dd',
            defaultDuration: 30,
            surveyMaxDurationsBySurveyIds: {}
        }
    };

    $.fn.surveyNodeAssignments = function (options) {
        var extendedOptions = $.extend({}, SurveyNodeAssignmentRow.prototype.defaultOptions, options);

        //Here 'this' is the jQuery selection set, over which the surveySettings function was called.
        return this.each(function () {
            //Here 'this' is the DOM child element of the selection set, over which the surveySettings function was called.
            var surveyNodeAssignmentRow = new SurveyNodeAssignmentRow($(this), extendedOptions);
        });
    };

})(jQuery);

//Numeric. Used to restrict user input just to numeric characters. Based on jQuesry.alphanumeric plugin,
//but better, as doesn't allow ctrl+v and russian characters.
(function ($) {

	$.fn.numeric = function (options) {

		options = $.extend({
			validChars: "1234567890"
		}, options);

		return this.each(function () {
			//IE doesn't fire keypress for special character clicks (that's why we handle pasteing later directly),
			//and keyCode contains the ASCII code of the printed character.
			//IE doesn't support charCode, so we use keyCode.
			if ($.browser.msie) {
				$(this).keypress(function (e) {
					var character = String.fromCharCode(e.keyCode);
					if (options.validChars.indexOf(character) == -1) e.preventDefault();
				});
			}
			//FF fires keypress, when special characters are clicked, so we should avoid them.
			//KeyCode contains a keyboard code of a character pressed, and charCode contains the ASCII printed value.
			else {
				$(this).keypress(function (e) {
					//Not a special key has been pressed
					if (e.charCode) {
						var character = String.fromCharCode(e.charCode);
						if (options.validChars.indexOf(character) == -1) e.preventDefault();
					}
				});
			}
			$(this).bind('paste', function(e) {e.preventDefault();});
			$(this).bind('contextmenu', function () { return false });
		});
	};
})(jQuery);
