
// equivalent of firstChild but crossbrowser (since FF considers spaces and new lines as child nodes)
// if properties are specified, it will check them to see if they match the node before returning it
function getFirstChild (node, props)
{
    if (!node)
        return null;
        
    var result = node.firstChild;
    
    while (result != null)
    {
        if (result.nodeType == 1 && (!props || checkNodeHasProperties (result, props)))
            break;
        
        result = result.nextSibling;
    }
    
    return result;
}

// equivalent of lastChild but crossbrowser (since FF considers spaces and new lines as child nodes)
// if properties are specified, it will check them to see if they match the node before returning it
function getLastChild(node, props)
{
    if (!node)
        return null;

    var result = node.lastChild;

    while (result != null)
    {
        if (result.nodeType == 1 && (!props || checkNodeHasProperties (result, props)))
            break;

        result = result.previousSibling;
    }

    return result;
}

// equivalent of firstChild but crossbrowser (since FF considers spaces and new lines as child nodes)
// if properties are specified, it will check them to see if they match the node before returning it
function getNextSibling(node, props)
{
    if (!node)
        return null;

    var result = node.nextSibling;

    while (result != null)
    {
        if (result.nodeType == 1 && (!props || checkNodeHasProperties (result, props)))
            break;

        result = result.nextSibling;
    }
    
    return result;
}

// equivalent of firstChild but crossbrowser (since FF considers spaces and new lines as child nodes)
// if properties are specified, it will check them to see if they match the node before returning it
function getPreviousSibling(node, props)
{
    if (!node)
        return null;

    var result = node.previousSibling;

    while (result != null)
    {
        if (result.nodeType == 1 && (!props || checkNodeHasProperties (result, props)))
            break;

        result = result.previousSibling;
    }
    
    return result;
}

// this will check the node against the properties specified as an associative array
// if the property is an object, it will check the reference
// else it will check the lowercase value of the properties to see if they match
function checkNodeHasProperties (node, props)
{
    if (!node)
        return false;

    for (var property in props)
        if (
                (typeof node[property] == "undefined" ||
                (typeof props[property] == "object" && node[property] != props[property]) ||
                (typeof node[property].toLowerCase == "undefined" || node[property].toLowerCase() != props[property].toLowerCase()))
                &&
                (node.getAttribute(property) == null ||
                (typeof props[property] == "object" && node[property] != props[property]) ||
                (typeof node.getAttribute(property).toLowerCase == "undefined" || node.getAttribute(property).toLowerCase() != props[property].toLowerCase()))
            )
            return false;
    
    return true;
}
