/*
 * <COPYRIGHT>
 * Copyright 2003 Gerd Stolpmann
 *
 * <GPL>
 * This file is part of WTimer.
 * 
 * WTimer is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * WTimer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with WDialog; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * </>
 */

/**********************************************************************/
/* Preamble                                                           */
/**********************************************************************/

/* The application does not depend on Javascript code, it works without.
 * However, Javascript adds convenience functionality that most users
 * want to have, e.g. input errors are rejected immediately. 
 *
 * Some users don't trust "active contents" and disable them in the
 * browser, and there are actually many security flaws in browsers 
 * that can only be avoided by turning Javascript off. Other browsers
 * do not have Javascript support. For these users it must be ensured
 * that the application works without Javascript.
 * 
 */

/**********************************************************************/
/* Check browser capabilities                                         */
/**********************************************************************/

var have_dom = document.getElementById != null;

/**********************************************************************/
/* Submit handler                                                     */
/**********************************************************************/

/* Submission can be blocked for a short period of time (0.1 sec) by
 * setting the submit lock
 */

var submit_lock = 0;

function clear_submit_lock () {
    submit_lock = 0;
}


function set_submit_lock () {
    /* lock the submit button for the next 100 ms */
    submit_lock = 1;
    window.setTimeout(clear_submit_lock, 100);
}

/* The global_submit_handler is defined for the FORM element (see the
 * grid definitions in definitions.ui). Tasks of this handler:
 * - Save the scroll position (only if there is the hidden form field
 *   var_scroll_position; the existence of this field enables the scroll
 *   handling.
 * - Check whether submission is to be blocked because the submit lock
 *   is active.
 */

function global_submit_handler () {
    if (document.uiform.var_scroll_position != null && have_dom ) {
	// Save the scroll position of the main column:
	// NOTE: The property scrollTop is non-standard but supported by 
	// several browsers. We simply test whether we have it, and if 
	// so we take advantage from it.
	var e = document.uiform.scrolled_element.value;
	if (e == 'frame') {
	    document.uiform.var_scroll_position.value = window.pageYOffset;
	} else {
	    var m = document.getElementById(e);
	    if (m != null && m.scrollTop != null) {
		// alert("Saving scroll position: " + m.scrollTop);
		document.uiform.var_scroll_position.value = m.scrollTop;
	    }
	}
    }
    // Stop submission if there is a submit lock:
    if (submit_lock) {
        window.status = "Action cancelled.";
    };
    return !submit_lock;
}

/**********************************************************************/
/* Load handler                                                       */
/**********************************************************************/

/* The global_load_handler is defined for the BODY element (see the
 * grid definitions in definitions.ui). Tasks of this handler:
 * - Restore the scroll position (only if there is the hidden form field
 *   var_scroll_position; the existence of this field enables the scroll
 *   handling.
 */

function global_load_handler () {
    if (document.uiform.var_scroll_position != null && have_dom) {
        // Restore the scroll position of the main column:
	var e = document.uiform.scrolled_element.value;
	if (e == 'frame') {
	    window.scrollTo(0,document.uiform.var_scroll_position.value);
	} else {
	    var m = document.getElementById(e);
	    var v = document.uiform.var_scroll_position.value;
	    if (m != null && m.scrollTop != null && v != '') {
		// alert("Restoring scroll position: " + v);
		m.scrollTop = parseInt(v);
	    }
	}
    }
}

/**********************************************************************/
/* Checking whether user input is valid                               */
/**********************************************************************/

/* Invalid user input is rejected by an alert box, and submission 
 * is blocked.
 * Furthermore, any valid user input causes that the "modified" flag
 * appears.
 */

function set_modified_flag () {
    /* See also the template head_modified_flag in definition.ui */
    if (have_dom) {
        document.getElementById("modified").style.visibility = "visible";
    }
}

var time_re = /^[ \t]*(\d{1,2}:\d{2})?[ \t]*$/;

var previous_values = new Object();

function check_time_string (widget) {
    var v;
    if (! time_re.test(widget.value)) {
	v = previous_values[widget.name];
        if (v == null) {
	    v = widget.defaultValue;
        };
	alert("This is not a valid time value!");
	widget.value = v;
	// The "alert" statement seems to block submits already, but
        // this is not specified anywhere. To be on the safe side,
        // set the submit lock to inhibit submit actions that
        // are triggered now.
	set_submit_lock();
    }
    else {
	previous_values[widget.name] = widget.value;
	set_modified_flag();
    }
}

var date_re = /^[ \t]*(\d{4})-(\d{1,2})-(\d{1,2})[ \t]*$/;

function check_date_string (widget) {
    var v;
    var valid = 0;
    var slots = date_re.exec(widget.value);
    if (slots != null) {
	var yr = parseInt(slots[1]);
        var mon = parseInt(slots[2]);
        var day = parseInt(slots[3]);
	var d = new Date(yr,mon-1,day);
        valid = (yr == d.getYear()+1900) && 
	        (mon == d.getMonth()+1) && 
		(day == d.getDate());
    }
    if (! valid ) {
	v = previous_values[widget.name];
        if (v == null) {
	    v = widget.defaultValue;
        };
	alert("This is not a valid date!");
	widget.value = v;
	// The "alert" statement seems to block submits already, but
        // this is not specified anywhere. To be on the safe side,
        // set the submit lock to inhibit submit actions that
        // are triggered now.
	set_submit_lock();
    }
    else {
	previous_values[widget.name] = widget.value;
	set_modified_flag();
    }
}

var year_re = /^\d\d\d\d$/;

function check_year_string (widget) {
    var v;
    if (! year_re.test(widget.value) || parseInt(widget.value) < 1902 ||
	parseInt(widget.value) > 2037) {
	v = previous_values[widget.name];
        if (v == null) {
	    v = widget.defaultValue;
        };
	alert("This is not a valid year!\nPlease enter a number between 1902 and 2037.");
	widget.value = v;
	// The "alert" statement seems to block submits already, but
        // this is not specified anywhere. To be on the safe side,
        // set the submit lock to inhibit submit actions that
        // are triggered now.
	set_submit_lock();
    }
    else {
	previous_values[widget.name] = widget.value;
	//set_modified_flag();  // not used in the "timetravel" dialog
    }
}


function check_number (widget, min, max) {
    /* widget must contain a number >= min and <= max */
    var v;
    if (! /^-?\d+$/.test(widget.value) || 
        parseInt(widget.value) < min ||
        parseInt(widget.value) > max) {
	    v = previous_values[widget.name];
            if (v == null) {
	        v = widget.defaultValue;
            };
	    alert("This is not a number, or the number is not in the valid range!");
	    widget.value = v;
    }
    else {
	previous_values[widget.name] = widget.value;
    }
}


function admin_pw_check (pw1, pw2) {
    // if pw1 != pw2: alert and lock
    if (pw1.value != pw2.value) {
	alert("The new passwords are not the same!");
	pw1.value = "";
	pw2.value = "";
	set_submit_lock();
    } else {
	if (pw1.value == '') {
	    alert("The new passwords are empty!");
	    set_submit_lock();
	}
    }
}


/**********************************************************************/
/* Input helpers                                                      */
/**********************************************************************/

/* For the "+" and "-" buttons on the calendar page: */

function inc_year ( wdg ) {
    var v = parseInt(wdg.value) + 1;
    if (v > 2037) v = 2037;
    wdg.value = v;
}

function dec_year ( wdg ) {
    var v = parseInt(wdg.value) - 1;
    if (v < 1902) v = 1902;
    wdg.value = v;
}

/**********************************************************************/
/* Managing the currently selected rows                               */
/**********************************************************************/

var checkboxes_sel = [ ];
var checkboxes_app = [ ];
var lastbox_sel = null;
var lastbox_app = null;


function find_box (checkboxes, target) {
    /* Returns the index of the checkbox target */
    for (var k=0; k<checkboxes.length; k++) {
	var n = checkboxes[k];
	if (n == target) return k;
    }
    return null;
}

function containing_tr (node) {
    /* Returns the containing table row element */
    var n = node;
    while (n != document && n.tagName != 'TR') {
        n = n.parentNode;
    }
    return n;
}

function visualize_selection (node) {
    /* Visualizes the selection by adding the 'wtimer-selected' attribute
     * to the containing table rows 
     */
    var tr = containing_tr(node);
    tr.setAttribute('wtimer-selected', node.checked ? 'yes' : 'no');
}

function nothing_selected (checkboxes, from, to) {
    /* True if all selection checkboxes are unchecked */
    var r = true;
    for (var k=from; k<=to; k++) {
	var n = checkboxes[k];
	if (n.checked) { r = false }
    }
    return r;
}

function all_selected (checkboxes, from, to) {
    /* True if all selection checkboxes are checked */
    var r = true;
    for (var k=from; k<=to; k++) {
	var n = checkboxes[k];
	if (!n.checked) { r = false }
    }
    return r;
}

function set_selected (checkboxes, from, to, value) {
    /* Set the boxes in the range to value */
    for (var k=from; k<=to; k++) {
	var n = checkboxes[k];
	n.checked = value;
        visualize_selection(n);
    }
}

function click_checkbox_sel (e) {
    /* The onclick handler for checkboxes_sel */
    if (e == null) return;
    if (e.shiftKey && lastbox_sel != null) {
        /* Select a range */
	var k1 = find_box(checkboxes_sel,lastbox_sel);
        var k2 = find_box(checkboxes_sel,e.target);
        if (k1==null || k2==null) return;
        var from = k1 < k2 ? k1 : k2;
        var to = k1 < k2 ? k2 : k1;
	if (checkboxes_sel[k1].checked) {
	    set_selected(checkboxes_sel,from,to,true);
	} else {
	    set_selected(checkboxes_sel,from,to,false);
	}
    } else {
        /* Simple click: Just remember this box */
        lastbox_sel = e.target;
	lastbox_app = null;
	visualize_selection(e.target);
    }
}

function click_checkbox_app (e) {
    /* The onclick handler for checkboxes_app */
    if (e == null) return;
    if (e.shiftKey && lastbox_app != null) {
        /* Select a range */
	var k1 = find_box(checkboxes_app,lastbox_app);
        var k2 = find_box(checkboxes_app,e.target);
        if (k1==null || k2==null) return;
        var from = k1 < k2 ? k1 : k2;
        var to = k1 < k2 ? k2 : k1;
	if (checkboxes_app[k1].checked) {
	    set_selected(checkboxes_app,from,to,true);
	} else {
	    set_selected(checkboxes_app,from,to,false);
	}
    } else {
        /* Simple click: Just remember this box */
        lastbox_app = e.target;
	lastbox_sel = null;
	visualize_selection(e.target);
    }
}

function init_checkboxes () {
    if (!have_dom) return;
    var base = document.getElementById('basic-grid-main-col');
    var all_boxes = base.getElementsByTagName('input');
    checkboxes_sel = [];
    checkboxes_app = [];
    for (var k=0; k<all_boxes.length; k++) {
	var n = all_boxes[k];
	// MSIE does not support hasAttribute, so work around
	if (n.getAttribute('wtimer-selector') != null) {
	    checkboxes_sel.push(n);
	    n.onclick = click_checkbox_sel;
	    visualize_selection(n);
	}
	if (n.getAttribute('wtimer-appender') != null) {
	    checkboxes_app.push(n);
	    n.onclick = click_checkbox_app;
	    visualize_selection(n);
	}
    }
}

function check_selection () {
    /* Called by "Del", "Copy" and "Cut" buttons (onclick) */
    if (nothing_selected (checkboxes_sel, 0, checkboxes_sel.length-1)) {
	alert("Nothing selected!");
	set_submit_lock();
    }
}

function check_selection_paste () {
    /* Called by "Paste" button (onclick) */
    if (nothing_selected (checkboxes_sel, 0, checkboxes_sel.length-1) &&
	nothing_selected (checkboxes_app, 0, checkboxes_app.length-1)) {
	alert("Nothing selected!");
	set_submit_lock();
    }
}

/**********************************************************************/
/* Popup pages                                                        */
/**********************************************************************/

/* popup_projects opens the small window displaying the list of 
 * available projects. The row_id identifies the widget into which
 * the selected project name is written back when the user presses
 * on "OK". It is saved in current_row_id for the time the popup
 * window is open.
 * x and y are the screen positions where the window should be 
 * located. These coordinates are optional.
 */

var current_row_id;

function popup_projects (row_id, x, y) {
    current_row_id = row_id;      /* Remember this id for later */
    var position='';
    if (x != null && y != null) {
	position=',screenX=' + x + ',left=' + x + 
                 ',screenY=' + y + ',top=' + y;
    };
    /* open_popup_projects is generated by WDialog. */
    var w = open_popup_projects('dependent=yes,' +
	                        'directories=no,' +
                                'hotkeys=no,' +
                                'location=no,' +
                                'menubar=no,' +
	                        'scrollbars=yes,' +
                                'status=no,' +
                                'toolbar=no,' +
                                'height=200,' +
	                        'width=200' + position);
}


function popup_projects_dom2 (row_id, ev) {
    popup_projects (row_id, ev.screenX, ev.screenY);
}


function configure_popup_projects (row_id) {
    var widget;
    if (!have_dom) return;
    widget = document.getElementById("projectbutton-" + row_id);
    if (widget.addEventListener != null) {
        // We have DOM2 events! Advantage: access to X and Y coordinate.
        // Set the preferred event handler for "click":
	widget.removeAttribute("onclick");
        widget.addEventListener('click',
	   		        function(ev) {
	                            popup_projects_dom2(row_id,ev)
                                },
	                        false);
    }
    else {
	// Fallback method: the "onclick" attribute of the button is
	// used to trigger the popup_projects function.
    }
}


/* select_project is called when the "OK" button is pressed in the
 * project list popup window. The selected project is written into
 * the widget that was remembered in current_row_id.
 */

function select_project ( popup_doc ) {
    var select_wdg;
    if (!have_dom) return;
    select_wdg = popup_doc.getElementById("popup-select");
    var k = select_wdg.selectedIndex;
    var project_name = select_wdg.options[k].value;
    var widget;
    widget = document.getElementById("projectcell-" + current_row_id);
    widget.value = project_name;
    close_popup();
    set_modified_flag();
}

