/**
 * common.js - Useful methods for common functionality between scripts  
 *
 * Copyright 2006, iMarc <info@imarc.net>
 * 
 * @version  1.1.0
 *
 * @author   William Bond    [wb] <will@imarc.net>
 * @author   Patrick McPhail [pm] <patrick@imarc.net>
 * 
 * @changes  1.2.0  Added in_array() function [pm, 2007-09-24] 
 * @changes  1.1.0  Added find_x(), find_y() and last_child() methods, updated to iMarc code standards [wb, 2006-10-18] 
 * @changes  1.0.0  Initial implementation [wb, 2006-08-22]
 */


/**
 * returns if a string exists within an array
 *
 * @since 1.0.0
 * 
 * @param  string needle  the string to search for
 * @param  array haystack to search in
 * @return mixed  true if string is within array, false otherwise
 */
function in_array(needle, haystack)
{

	for (lp=0; lp < haystack.length; lp++) {
		
		if (haystack[lp] == needle) {
			return true;
		}
	}
	
	return false;

}


/**
 * Gets the parent node of an element
 *
 * @since 1.0.0
 * 
 * @param  object object  The html object to get the parent of
 * @param  integer depth  How many levels to go up (2 would mean get the object.parentNode.parentNode)
 * @return mixed  false if an error, parent object if successful
 */
function parent_node(object, depth)
{
    if (!depth) {
        depth = 1;
    }
    var parent_object = object;
    while (depth > 0) {
        if (parent_object) {
            parent_object = parent_object.parentNode;
        }
        depth -= 1;
    }
    if (!parent_object) {
        return false;
    }
    return parent_object;
}


/**
 * Gets the first child of an element, ignoring text nodes
 *
 * @since 1.0.0
 * 
 * @param  object object  The html object to get the first child of
 * @param  integer depth  How many levels to go down (2 would mean get the object.firstChild.firstChild)
 * @return mixed  false if an error, first child object if successful
 */
function first_child(object, depth)
{
    if (!depth) {
        depth = 1;
    }
    var first_child = object;
    while (depth > 0) {
        if (first_child) {
            first_child = first_child.firstChild;
            while (first_child && first_child.nodeType != 1) {
                first_child = first_child.nextSibling
            }
        }
        depth -= 1;
    }
    if (!first_child) {
        return false;
    }
    return first_child;
}


/**
 * Gets the last child of an element, ignoring text nodes
 *
 * @since 1.1.0
 * 
 * @param  object object  The html object to get the last child of
 * @param  integer depth  How many levels to go down (2 would mean get the object.lastChild.lastChild)
 * @return mixed  false if an error, last child object if successful
 */
function last_child(object, depth)
{
    if (!depth) {
        depth = 1;
    }
    var last_child = object;
    while (depth > 0) {
        if (last_child) {
            last_child = last_child.lastChild;
            while (last_child && last_child.nodeType != 1) {
                last_child = last_child.previousSibling
            }
        }
        depth -= 1;
    }
    if (!last_child) {
        return false;
    }
    return last_child;
}


/**
 * Gets the next sibling of an element, ignoring text nodes
 *
 * @since 1.0.0
 * 
 * @param  object object     The html object to get the next sibling of
 * @param  integer distance  How many objects to go forward (2 would mean get the object.nextSibling.nextSibling)
 * @return mixed  false if an error, next sibling object if successful
 */
function next_sibling(object, distance)
{
    if (!distance) {
        distance = 1;
    }
    var next_sibling = object;
    while (distance > 0) {
        if (next_sibling) {
            next_sibling = next_sibling.nextSibling;
            while (next_sibling && next_sibling.nodeType != 1) {
                next_sibling = next_sibling.nextSibling
            }
        }
        distance -= 1;    
    }
    if (!next_sibling) {
        return false;
    }
    return next_sibling;
} 


/**
 * Gets the previous sibling of an element, ignoring text nodes
 *
 * @since 1.0.0
 * 
 * @param  object object     The html object to get the previous sibling of
 * @param  integer distance  How many objects to go backwards (2 would mean get the object.previousSibling.previousSibling)
 * @return mixed  false if an error, previous sibling object if successful
 */
function previous_sibling(object, distance)
{
    if (!distance) {
        distance = 1;
    }
    var previous_sibling = object;
    while (distance > 0) {
        if (previous_sibling) {
            previous_sibling = previous_sibling.previousSibling;
            while (previous_sibling && previous_sibling.nodeType != 1) {
                previous_sibling = previous_sibling.previousSibling
            }
        }
        distance--;    
    }
    if (!previous_sibling) {
        return false;
    }
    return previous_sibling;
}


/**
 * Gets the x position of the left edge of an html element - based on code from http://www.quirksmode.org/js/findpos.html
 *
 * @since 1.1.0
 * 
 * @param  object object  The html object to get the x position of
 * @return integer  The x position of the left edge of the element
 */
function find_x(object)
{
    var left = 0;
    if (object.offsetParent) {
        while (object.offsetParent) {
            left += object.offsetLeft
            object = object.offsetParent;
        }
    } else if (object.x) {
        left += object.x;
    }
    return left;
}


/**
 * Gets the y position of the top edge of an html element - based on code from http://www.quirksmode.org/js/findpos.html
 *
 * @since 1.1.0
 * 
 * @param  object object  The html object to get the y position of
 * @return integer  The y position of the top edge of the element
 */
function find_y(object)
{
    var top = 0;
    if (object.offsetParent) {
        while (object.offsetParent) {
            top += object.offsetTop
            object = object.offsetParent;
        }
    } else if (object.y) {
        top += object.y;
    }
    return top;
}
