﻿Array.prototype.indexOf = function(what)
{
    for (var i = 0; i < this.length; i++)
        if (this[i] == what)
            return i;
    return -1;
}

String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); }
String.prototype.startsWith = function(head) { return this.indexOf(head) == 0; }
String.prototype.endsWith = function(tail) { return this.lastIndexOf(tail) == this.length - tail.length; }
String.prototype.compare = function(b) { return this == b ? 0 : (this > b ? 1 : -1); }

function $(id)
{
    return document.getElementById(id);
}

function ShowHide(show, hide)
{
    if (show != null)
        show.style.display = 'block';
    if (hide != null)
        hide.style.display = 'none';
}

function IsShow(elem)
{
    return (elem.style.display == 'block');
}

function IsHide(elem)
{
    return (elem.style.display == 'block');
}

function SetShow(elem, show, highlight)
{
    elem.style.display = show ? "block" : "none";
    if (highlight != null)
    {
        //elem.style.backgroundColor = highlight ? "#ffff80" : "";
        elem.style.color = highlight ? "red" : "";
        elem.style.fontWeight = highlight ? "bold" : "";
    }
}

function FindPosition(elem)
{
    var pos = { x:elem.offsetLeft, y:elem.offsetTop };
    while (elem.parentElement != null)
    {
        elem = elem.parentElement;
        pos.x += elem.offsetLeft;
        pos.y += elem.offsetTop;
    }
    return pos;
}

//PATCH: IE DOM fails to display distance after changes made by code above;
//       force IE to redraw column (aparently)
function ForceRefresh(elem)
{
//    // keep the current element-in-focus, so we can resume it later
//    var focused = null;
//    for(var i = 0; i < document.all.length; i++)
//        if (document.all[i].gotFocus)
//            focused = document.all.items[i];
//    // causes a refresh
    elem.style.display = 'none';
    elem.style.display = 'block';
//    // restore the focus
//    if (focused != null)
//        window.setTimeout(function(){focused.focus()}, 250);
}
function ForceRefreshGrid()
{
    ForceRefresh(exerRow(0).cells(0));
}

function ajax(url, vars, callbackFunction)
{
    var request = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("MSXML2.XMLHTTP.3.0");
    request.open(vars == null ? "GET" : "POST", url, true);
    request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 
    request.onreadystatechange = function()
    {
        if (request.readyState == 4)
        {
            if (request.status == 200) 
            {
                if (request.responseText)
                {
                    var res;
                    if (request.responseText.charAt(0) == '{' || request.responseText.charAt(0) == '[') // if JSON
                    {//alert(url + ": \n" + request.responseText);
                        eval("res=" + request.responseText);
                        if ("Exception" in res)
                        {
                            UserAlert(res.Exception.replace(/&nbsp;/g,"'").replace(/<br\/>/g,"\n"));
                            callbackFunction(null);
                        }
                        else
                            callbackFunction(res);
                    }
                    else
                        callbackFunction(request.responseText);
                }
            }
            else 
                UserAlert("Error " + request.status + " " + request.statusText + ".");
        }
    };
    request.send(vars);
}

function Log(s, newline) { Console.innerHTML += s; }
function LogLine(s, newline) { Console.innerHTML += s + "<br>"; }

function EncodeURL(url)
{
    return url.replace(/\./g, "%2d");
}

function FillDropDownRange(node)
{
    if (("range" in node) && node.tagName == "SELECT")
    {
        var ranges = node.range.split(',');
        for (var i = 0; i < ranges.length; i++)
        {
            var fromtostep = ranges[i].replace(/-/g, ',').replace(/@/g, ',').split(',');
            var from = parseFloat(fromtostep[0]);
            var to = fromtostep.length > 1 ? parseFloat(fromtostep[1]) : from;
            var step = 1, stepdigits = 0;
            if (fromtostep.length > 2)
            {
                step = parseFloat(fromtostep[2]);
                stepdigits = (fromtostep[2].indexOf('.') >= 0) ? (fromtostep[2].length - fromtostep[2].indexOf('.') - 1) : 0;
            }
            for (var value = from; value <= to+0.0001; value += step)
            {
                var option = document.createElement("OPTION");
                option.value = value.toFixed(stepdigits);
                option.innerHTML = value.toFixed(stepdigits);
                if (value.toFixed(stepdigits) == node.defaultvalue)
                    option.selected = "selected";
                node.appendChild(option);
            }
        }
    }
}

function SelectRadio(radiogroup, value)
{
    for (var i = 0; i < radiogroup.childNodes.length; i++)
    {
        var elem = radiogroup.childNodes[i];
        if (elem.tagName == "INPUT" && elem.type == "radio")
            elem.checked = (elem.value == value) ? 'checked' : '';
        else
            SelectRadio(elem, value);
    }
}

function FindParent(elem, tag)
{
    do
        elem = elem.parentElement;
    while (elem != null && elem.tagName != tag);
    return elem;
}

var deferparam;
function defer(func, param)
{
    deferparam = param;
    window.setTimeout(func+"()", 1);
}

function stop() { debugger; }

function ParseInt(s)
{
    return Math.floor(parseFloat(s));
}

function MaskMaxValue(mask)
{
    switch (mask)
    {
        case "MSS": return 599;
        case "MMSS": return 3599;
        case "HMMSS": return 35999;
    }
    throw "Unknown mask";
}

function parseMMSS(s)
{
    if (s == "") return 0;
    var ms = s.split(":");
    return (ms.length > 1 ? ParseInt(ms[0]) : 0) * 60 + ParseInt(ms[ms.length - 1]);
}

function parseHMMSS(s)
{
    if (s == "") return 0;
    var ms = s.split(":");
    return (ms.length > 2 ? ParseInt(ms[0]) : 0) * 3600 + 
           (ms.length > 1 ? ParseInt(ms[ms.length - 2]) : 0) * 60 + 
           ParseInt(ms[ms.length - 1]);
}

function toMSS(secs)
{
    secs = Math.round(secs);
    return (10 + secs / 60).toString().substr(1,1) + ":" + (100 + secs % 60).toString().substr(1,2);
}

function toMMSS(secs)
{
    secs = Math.round(secs);
    return (100 + secs / 60).toString().substr(1,2) + ":" + (100 + secs % 60).toString().substr(1,2);
}

function toHMMSS(secs)
{
    secs = Math.round(secs);
    return (Math.floor(secs / 3600)).toString() + ":" + (100 + (secs % 3600) / 60).toString().substr(1,2) + ":" + (100 + secs % 60).toString().substr(1,2);
}

var months = [ "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sep", "Oct", "Nov", "Dec" ];
function toDDMMMYYYY(d)
{
    return d.getDate() + " " + months[d.getMonth()] + " " + d.getFullYear();
}
function toDDMMMYY(d)
{
    return d.getDate() + "" + months[d.getMonth()] + "" + d.getYear().toString().substring(d.getYear().toString().length - 2);
}
function toHHMM(t)
{
    return t.getHours() + ":" + (100 + t.getMinutes()).toString().substring(1);
}
function toDDMMMYYHHMM(d)
{
    return toDDMMMYY(d) + " " + toHHMM(d);
}
function parseDateTime(dt)
{
    var tokens = dt.replace(":"," ").split(' ');
    var date = ParseInt(tokens[0]);
    var month = -1;
    for (var i = 0; i < months.length; i++)
        if (tokens[1].substring(0, 3).toLowerCase() == months[i].substring(0, 3).toLowerCase())
            { month = i; break; }
    var year = ParseInt(tokens[2]);
    if (year < 100) year += 2000;
    var hour = tokens.length > 3 ? ParseInt(tokens[3]) : 0;
    var minute = tokens.length > 4 ? ParseInt(tokens[4]) : 0;
    return new Date(year, month, date, hour, minute, 0);
}
function ToUTC(d)
{
    return d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d.getDate() + "T" + d.getHours() + ":" + (100+d.getMinutes()).toString().substring(1);
}

function formatTime(value, mask)
{
    value = value.replace(/:/g, "");
    value = value.substr(value.length - mask.length);
    var pos = value.length - 2;
    while (pos > 0)
    {
        value = value.substr(0, pos) + ":" + value.substr(pos);
        pos -= 2;
    }
    return value;
}

function selectNode(node) 
{
    var selection, range, doc, win;
    if ((doc = node.ownerDocument) && (win = doc.defaultView) && 
        typeof win.getSelection != 'undefined' && typeof doc.createRange != 'undefined' &&
        (selection = window.getSelection()) && typeof selection.removeAllRanges != 'undefined') 
    {
        range = doc.createRange();
        range.selectNode(node);
        selection.removeAllRanges();
        selection.addRange(range);
    }
    else if (document.body && typeof document.body.createTextRange != 'undefined' && 
        (range = document.body.createTextRange())) 
    {
        range.moveToElementText(node);
        range.select();
    }
} 

function ClearCombo(combo)
{
    while(combo.firstChild) // delete all nodes
        combo.removeChild(combo.firstChild);
}

function FillCombo(combo, values)
{
    var ranges = values.split(',');
    for (var i = 0; i < ranges.length; i++)
    {
        var limits = ranges[i].split('-');
        var start = limits[0];
        var end = limits[limits.length - 1]; // may be the same as start, if actually a single value '7' and not range '3-7'
        for (var j = start; j <= end; j++)
        {
            var opt = document.createElement("OPTION");
            opt.value = j;
            opt.innerHTML = j;
            combo.appendChild(opt);
        }
    }
}

function validateInput(elem, msg)
{
    if ((("minvalue" in elem) && parseFloat(elem.minvalue) > parseFloat(elem.value)) ||
        (("maxvalue" in elem) && parseFloat(elem.maxvalue) < parseFloat(elem.value)))
    {
        elem.focus();
        UserAlert(msg);
        elem.value = elem.original;
        return false;
    }
    return true;
}

// validate mandatory field: 
function ValidateMandatory(elem, msg, display, caption)
{
    if (elem.value == "") // || elem.value == msg)
    {
        ShowHide($(elem.id + "Required"));
        //elem.value = msg;
        if (display != null)
        {
            (caption == null ? display : caption).innerHTML = msg;
            display.style.visibility = 'visible';
        }
        //elem.select();
        //elem.className = "InvalidInput";
        //SetToBeFocus(elem);
        //elem.focus();
        return true;
    }
    else
    {
        ShowHide(null, $(elem.id + "Required"));
        if (display != null)
            display.style.visibility = 'hidden';
        return false;
    }
    //return (elem.className == "InvalidInput"); // may be left-over from previous validation
}

function ClearField(elem)
{
    elem.value = "";
    ShowHide(null, $(elem.id + "Required"));
}

// Check if string is a valid email address
function regIsEmail(fData)
{
    var reg = new RegExp("^[0-9a-zA-Z]+@[0-9a-zA-Z\-]+[\.]{1}[0-9a-zA-Z]+[\.]?[0-9a-zA-Z]+$");
    return reg.test(fData);
}

var contextmenus = new Array();
var contextitem = null;
var ContextMenuJustOpened = false;

function IsContextMenuOpen() { return contextmenus.length > 0; }

function CloseContextMenu()
{
    while (contextmenus.length > 0)
    {
        document.body.removeChild(contextmenus.pop());
    }
}

function CreateContextMenu(items, pos)
{
    if (pos == null || !("nested" in pos) || !pos.nested)
        CloseContextMenu();
    if (pos == null)
        pos = event;
    var contextmenu = document.createElement("DIV");
    contextmenu.style.position = "absolute";
    contextmenu.style.left = pos.x;
    contextmenu.style.top = pos.y;
    contextmenu.style.overflowX = "hidden";
    if ("height" in pos)
    {
        contextmenu.style.maxHeight = pos.height;
        contextmenu.style.overflowY = "auto";
    }
    if ("width" in pos)
        contextmenu.style.width = pos.width;
    contextmenu.style.backgroundColor = ("bgcolor" in pos) ? pos.bgcolor : "White";
    contextmenu.style.border = "solid 1px Black";
    contextmenu.style.zIndex = 999;
    for (var i = 0; i < items.length; i++)
    {
        var item = document.createElement("DIV");
        item.innerText = items[i].Text;
        item.Data = items[i].Data;
        item.style.cursor = "pointer";
        item.style.padding = "3px";
        item.style.color = (items[i].Action != null) ? "black" : "gray";
        if (items[i].Action != null)
        {
            item.attachEvent('onmouseenter', function(){event.srcElement.style.backgroundColor='yellow';});
            item.attachEvent('onmouseleave', function(){event.srcElement.style.backgroundColor='';});
            item.attachEvent('onclick', items[i].Action);
        }
        contextmenu.appendChild(item);
    }
    contentmenu = "TheContextMenu";
    document.body.appendChild(contextmenu);
    // if bottom of menu is below the end of visible document body area, lift it a bit
    if (contextmenu.offsetTop + contextmenu.offsetHeight > document.body.offsetTop + document.body.offsetHeight)
        contextmenu.style.top = document.body.offsetTop + document.body.offsetHeight - contextmenu.offsetHeight - 8;
    // mark top-level document.oncontextmenu we just opened, so not to close the menu
    ContextMenuJustOpened = true;
    contextmenus.push(contextmenu);
    return contextmenu;
}
function CreateRangesContextMenu(values, pos, action)
{
    var items = [];
    var ranges = values.split(',');
    for (var i = 0; i < ranges.length; i++)
    {
        var limits = ranges[i].split('-');
        var start = limits[0];
        var end = limits[limits.length - 1]; // may be the same as start, if actually a single value '7' and not range '3-7'
        for (var j = start; j <= end; j++)
        {
            items.push({ Text:j, Action:action });
        }
    }
    return CreateContextMenu(items, pos);
}

function GetActivity()
{
    if (IsSwim) return "Swim";
    else if (IsRun) return "Run";
    else throw "Unknown activity!";
}

function GetFieldValue(fld)
{
    return (fld.tagName == "INPUT") ? fld.value : fld.innerText;
}
function SetFieldValue(fld, value)
{
    if (fld.tagName == "INPUT")
        fld.value = value;
    else
        fld.innerText = value;
}
function SetFieldFocus(fld)
{
    if (fld.tagName == "INPUT")
        fld.select();
    else
        selectNode(fld);
}
function ReventFieldValue(fld)
{
    if (fld.tagName == "INPUT")
        fld.value = fld.original;
    else
        fld.innerText = fld.original;
}
function ElemDesc(elem)
{
    return elem.id + (("desc" in elem) ? elem.desc : "");
}
function OnFieldFocus(fld)
{
    if (logevents.focus) Consol.WriteLine("OnFieldFocus " + ElemDesc(fld));
    fld.original = GetFieldValue(fld);
    SetFieldFocus(fld);
}
function LogKeyEvent(handler, fld, next)
{
    if (logevents.key) 
        Consol.WriteLine(handler + " " + ElemDesc(fld) + (next != null ? (" next " + ElemDesc(next)) : "") + " key " + event.keyCode);
} 
function OnFieldKeyDown(fld, next)
{
    LogKeyEvent("OnFieldKeyDown", fld, next);
    if (event.keyCode == 27) // ESC to revert to original value
    {
        ReventFieldValue(fld);
        SetFieldFocus(fld);
    }
    else if (event.keyCode == 13 || event.keyCode == 9) // Enter to move to next field
    {
        next.focus();
        event.returnValue = false; // cancel the Enter key event, or it may key-up on the next field and destroy its value!
        return false;
    }
    return true;
}
function OnNumericFieldKeyDown(fld, next)
{
    LogKeyEvent("OnNumericFieldKeyDown", fld, next);
    fld.beforekey = fld.innerText;
    if (event.keyCode == 27 || event.keyCode == 13 || event.keyCode == 8 || event.keyCode == 9) // ESC, Enter, BS are handled by generic field handler
        return OnFieldKeyDown(fld, next);
//    return (!("size" in fld) || fld.innerText.replace('.','').length < fld.size);
//    return (event.keyCode >= 48 && event.keyCode <= 57); // allow only digits
}
function OnNumericFieldKeyUp(fld)
{
    LogKeyEvent("OnNumericFieldKeyUp", fld);
    if ("size" in fld && fld.innerText.replace('.','').length > parseInt(fld.size))
        fld.innerText = fld.beforekey;
}
function OnNumericFieldKeyPress(fld)
{
    LogKeyEvent("OnNumericFieldKeyPress", fld);
    var ch = String.fromCharCode(event.keyCode);
    if (ch == '.')
        return fld.innerText.indexOf('.') < 0;
    return (ch >= '0' && ch <= '9');
}
function OnTimeFieldKeyDown(fld, next)
{
    LogKeyEvent("OnTimeFieldKeyDown", fld, next);
    if (event.keyCode == 27 || event.keyCode == 13 || event.keyCode == 8 || event.keyCode == 9) // ESC, Enter, BS are handled by generic field handler
        return OnFieldKeyDown(fld, next);
    if (event.keyCode < 48 || event.keyCode > 57) // only digits allowed
        return false;
    else if (document.selection.createRange().text != GetFieldValue(fld))
    {
//        var value = parseHMMSS(GetFieldValue(fld));
//        if ((fld.mask == "MSS" && value*10+9 >= 600) || (fld.mask == "MMSS" && value*10+9 >= 3600) || (fld.mask == "HMMSS" && value*10+9 >= 36000))
//            return false;
        // produce value without separators (:) or leading zeros
        var value = GetFieldValue(fld).replace(/:/g, "");
        while (value.charAt(0) == '0')
            value = value.substring(1);
        if (value.length >= fld.mask.length)
            return false;
    }
    return true;
}
function OnTimeFieldKeyUp(fld)
{
    LogKeyEvent("OnTimeFieldKeyUp", fld);
    if (event.keyCode != 13) // && event.keyCode != 9) // if not Enter or BS
    {
        SetFieldValue(fld, formatTime(GetFieldValue(fld), fld.mask));
        if (event.keyCode == 9)
            OnFieldFocus(fld); // as it will lose highlight after SetFieldValue
    }
    //else if (event.keyCode == 9) // BS pops an IE problem
        ForceRefreshGrid();
    return true;
}

function TooltipMouseOver(tooltip, button)
{
    tooltip.style.top = AbsTop(button) + button.clientHeight + 6;
    tooltip.style.left = Math.max(AbsLeft(button) - 100, 10);
    tooltip.style.display = 'block';
}

function TooltipMouseOut(tooltip)
{
    tooltip.style.display = 'none';
}
