function getElem(elemOrId) {
    return (typeof(elemOrId) == 'string') ?
         document.getElementById(elemOrId) :
         elemOrId;
}

function focusElem(elemOrId) {
    var elem = getElem(elemOrId)
    if (elem && elem.focus) elem.focus()
}

function showElem(elemOrId) {
    var elem = getElem(elemOrId);
    //if (!elem) alert(elemOrId);
    if(elem.style.display != 'none') return;
    if(!elem.olddisplay) {
        elem.style.display = 'block';
    } else if(elem.olddisplay != 'none') {
        elem.style.display = elem.olddisplay;
    } else {
        elem.style.display = 'block';
    }
}

function hideElem(elemOrId) {
    var elem = getElem(elemOrId);
    if (elem.style.display == 'none') return;
    elem.olddisplay = elem.style.display;
    elem.style.display = 'none';
}


/* prelude.js library. http://code.google.com/p/prelude-js/ */

function stub(arg) {
    return arg
}

function map(func, seq) {
    var result = []
    for(var i = 0; i < seq.length; i++)
        result.push(func(seq[i]))
    return result
}

function each(func, seq) {
    for(var i = 0; i < seq.length; i++)
        func(seq[i])
}

function filter(func, seq) {
    var result = []
    if (!func) func = stub
    for(var i = 0; i < seq.length; i++)
        if (func(seq[i])) result.push(seq[i])
    return result
}

function all(func, seq) {
    for(var i = 0; i < seq.length; i++)
        if (!func(seq[i])) return false
    return true
}

function any(func, seq) {
    for(var i = 0; i < seq.length; i++)
        if (func(seq[i])) return true
    return false
}

function sum(seq) {
    var result = (typeof(seq[0]) == 'string') ? '' : 0
    for(var i = 0; i < seq.length; i++)
        result += seq[i]
    return result
}

function reduce(func, initval, seq) {
    var result = initval
    for(var i = 0; i < seq.length; i++)
        result = func(result, seq[i])
    return result
}

function min(seq) {
    return reduce(Math.min, Number.POSITIVE_INFINITY, seq)
}

function max(seq) {
    return reduce(Math.max, Number.NEGATIVE_INFINITY, seq)
}

function zip(/* seq, seq, ...*/) {
    var result = []
    var lists = arguments
    var m =  min(map(operator.itemgetter('length'), lists))
    var n = lists.length
    for(var i = 0; i < m; i++) {
        var elem = []
        for(var j = 0; j < n; j++)
            elem.push(lists[j][i])
        result.push(elem)
    }
    return result
}

function unzip(/* seq, seq, ...*/) {
    return zip(arguments)
}

// TODO uncomment?
//
//function compose() {
//    var functions = arguments
//    return function() {
//        var result = functions.pop()(arguments)
//        while (functions.length > 0)
//            result = functions.pop()(result)
//        return result
//    }
//}
//
//function slice(from, to/* , step */) {
//    var result = []
//    for(var i = 1; i < seq.length; i++)
//        result.push(seq[i])
//    return result
//}

var operator = {}

operator.getattr = function(obj, attr) {
    return obj[attr]
}

operator.itemgetter = function (attr) {
    var bits = attr.split('.')
    if (bits.length == 1)
        return function(obj) { return obj[attr] }
    return function(obj) { return reduce(operator.getattr, obj, bits) }
}

operator.itemchecker = function (attr, value) {
    var getter = operator.itemgetter(attr)
    return function(obj) { return getter(obj) == value }
}

operator.itemsetter = function (attr, value) {
    var bits = attr.split('.')
    if (bits.length == 1)
        return function(obj) { obj[attr] = value }
    else if (bits.length == 2)
        return function(obj) { obj[ bits[0] ][ bits[1] ] = value }
    else if (bits.length == 3)
        return function(obj) { obj[ bits[0] ][ bits[1] ][ bits[2] ] = value }
    else if (bits.length == 4)
        return function(obj) { obj[ bits[0] ][ bits[1] ][ bits[2] ][ bits[3] ] = value }
    else
        throw 'operator.itemsetter doesnt support high deep yet'
}
