function $(s){
    return document.getElementById(s);
}

function extend(sub, base){
    for(var x in base.prototype){
        sub.prototype[x] = base.prototype[x];
    }
}

/*
if (!Array.prototype.map)
{
  Array.prototype.map = function(fun )
  {
    var len = this.length >>> 0;
    if (typeof fun != "function")
      throw new Error("type error");

    var res = new Array(len);
    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in this)
        res[i] = fun.call(thisp, this[i], i, this);
    }

    return res;
  };

}
    */


function loop(list, callback){
    var len = list.length;
    for(var x=0; x<len; x++){
        callback(list[x]);
    }
}


function loopNodes(list, callback){
    var node = list.length ? list[0] : list.firstChild;

    while(node){
        var next = node.nextSibling;
        callback(node);
        node = next;
    }
}



function addXFunction(obj, name, func){
    if(obj.prototype[name] == undefined)
        obj.prototype[name] = func;
}


function evtSrc(e){
    if(e.target)
        return e.target;
    else
        return e.srcElement;
}

function sliceNode(node){
    if(node.parentNode) {
        var parent = node.parentNode;

        while(node.childNodes && node.childNodes.length > 0) {
            var child = node.removeChild(node.firstChild);
            parent.insertBefore(child, node);
        }

        parent.removeChild(node);
        delete node;
    }

}

function splitParent(splittingNode, parentTag, splitParent){
    if((!splittingNode.parentNode || !splittingNode.parentNode.parentNode) && !splitParent)
        return;
    
    if(splittingNode.nodeName.toLowerCase() == "#text") 
        splittingNode = splittingNode.parentNode;

    var parent = splitParent ? splitParent : splittingNode.parentNode;
    if(parent.nodeName.toLowerCase() != parentTag.toLowerCase())
        return;

    var grand = parent.parentNode;
    var newHalf = parent.ownerDocument.createElement(parent.nodeName);

    var hasSplit = false
    var node = parent.firstChild;
    //split the node at the designated child
    while(node){
        var next = node.nextSibling;

        //move subsequent nodes into the new half
        if(hasSplit){
            parent.removeChild(node);
            newHalf.appendChild(node);
        }



        //remove split node
        if(node == splittingNode){
            
            parent.removeChild(node);
            grand.insertBefore(node, parent.nextSibling);
            if(parent.childNodes.length > 0) {
                grand.insertBefore(newHalf, node.nextSibling);
                hasSplit = true;
            } 

            //set to previous sibling to not screw up the collection

        }

        node = next;
    }

    //cleanup parent if empty
    if(parent.childNodes.length == 0){
        grand.removeChild(parent);

    }

}

function isChildOf(child, parent){
    if(child.parentNode === null) {
        return false;
    } else if(child.parentNode == parent) {
        return true;
    } else {
        return isChildOf(child.parentNode, parent);
    }
}

function getEvent(e){
    return e ? e : window.event;
}

function getKeyCode(e){
    var code;

	if (e.keyCode) 
        code = e.keyCode;
	else if (e.which) 
        code = e.which;

    return code;
}


function getElementCoordinates(el){
    function getTotalCoord(node, prop){
        if(!node || isNaN(node[prop]))
            return 0;
        else if(node[prop] !== undefined)
            return node[prop] + getTotalCoord(node.parentNode, prop);
    }

    return {"x" : getTotalCoord(el, "offsetLeft"), "y" : getTotalCoord(el, "offsetTop")};

}


function addMouseOverOutListener(el, overCallback, outCallback){

    function doMouseOverOut(e){
        var listenMouseOut = function (e){
            var evt = getEvent(e);
            var src = evtSrc(evt);
            var coords = getMouseCoordinates(evt);
            var elCoord = getElementCoordinates(el);
                //if(src != el && !isChildOf(src, el)) {
            if((coords.x < elCoord.x || coords.x > elCoord.x + el.offsetWidth)
               || (coords.y < elCoord.y || coords.y > elCoord.y + el.offsetHeight)) {
                stopEvent(evt);
                removeEventListener(document.body, "mouseover", listenMouseOut);
                outCallback(evt);
            }
        }
        
        addEventListener(document.body, "mouseover", listenMouseOut);        

        overCallback(getEvent(e));

    }

    addEventListener(el, "mouseover", doMouseOverOut);        
    

}

//create for synthetic events
LISTENERS = {};

//Crossbrowser add event listener
function addEventListener(el, type, f, userCapture){

    if(el.addEventListener) {
        el.addEventListener(type, f, null);  
    } else if(el.attachEvent){
        var ietype = "on" + type;
        el.attachEvent(ietype, f);
        if(el["on" + type] == undefined){
            if(LISTENERS[ietype] == undefined) LISTENERS[ietype] = [];

            LISTENERS[ietype].push(f);
        }

    }
}

function removeEventListener(el, type, f, useCapture){
  if (el.removeEventListener){
    el.removeEventListener(type, f, null);
  } else if (el.detachEvent){
      var ietype = "on" + type;
      el.detachEvent(ietype, f);

      //delete fake listeners
      if(el[ietype] == undefined && LISTENERS[ietype] != undefined) {
          for(var x in LISTENERS){
              if(LISTENERS[ietype][x] == f) 
                  LISTENERS[ietype].slice(x, 1);
          }
      }

  }
} 



function stopEvent(e) {
    var evt = getEvent(e);

    if(evt.stopPropagation) {
        //for FF
        evt.stopPropagation();
    } else {
        //for IE
        evt.cancelBubble = true;
    }
}

function createEvent(el, type, canBubble, can ){

    if (document.createEventObject){
        //IE dispatch
        //use fake event tracking to kick off synthetic events that IE doesn't allow
        var evt = document.createEventObject();
        var ietype = "on" + type;
        if(el.ietype != undefined) {
            el.fireEvent(ietype,evt);
        } else {
            if(LISTENERS[ietype]){
                for(var x in LISTENERS[ietype]){
                    LISTENERS[ietype][x](el);
                }
            }
        }
    }
    else{
        //dom dispatch
        var evt = document.createEvent("Events");
        evt.initEvent(type, true, true ); 
        return el.dispatchEvent(evt);
    }
}
 
function xInnerHTML(node, newInnerHTML){
    node.innerHTML = newInnerHTML;
    createEvent(node, "htmlchange");
}



function waitUntil(action, interval, condition){
    var intID = setInterval(tryAction, interval);

    function tryAction(){
        var intervalID = intID;
        if(condition()){
            //clear first in case action recalls wait
            clearInterval(intervalID);

            action();
        }
    }
    

}




function getInnerText(node){
    if(node.textContent || node.textContent == '') 
        return node.textContent; 
    else 
        return node.innerText;
}

/**
 *
 * @return object browser object
 */
function getBrowser(){
    var o = {};
    
    alert(navigator.appName);
    //o["browser"] == "IE";

}


function resizeInput(){

    var iframe = document.getElementById("templateFrame");
    var inputs = iframe.contentDocument.getElementsByTagName("INPUT");

    var div = document.createElement("DIV");
    document.body.appendChild(div);
    div.style.display = "inline";
    div.style.fontSize = '12px';
    div.style.paddingLeft = "10px";
    div.style.paddingRight = "10px";
    div.style.marginLeft = "10px";
    div.style.marginRight = "10px";

    for(k in inputs){
        var item = inputs.item(k);     
        div.innerHTML = item.value;
        div.style.visibility = "hidden";
        item.style.width = div.offsetWidth + 'px';
        
    }

    document.body.removeChild(div);

}

Constants = {
    "CSS_SHOW" : "show",
    "CSS_HIDE" : "hide"
}

function hide(o){
    addClass(o, Constants.CSS_HIDE);
}

function show(o){
    removeClass(o, Constants.CSS_HIDE);
}

function hasClass(o, className){
    var sReg = "\\b" + className + "\\b";
    var found = o.className.search(sReg);
    return (found > -1 ? true : false);
}

function addRemoveClass(o, className, removeClass){
    var sReg = "\\b" + className + "\\b";
    var found = o.className.search(sReg);

    if(found > -1 && removeClass)
        o.className = o.className.replace(new RegExp(sReg + "\\s*", "g"), "");

    if(found == -1 && !removeClass) {
        var classes = o.className.split(" ");
        classes.push(className);
        o.className = classes.join(" ");
    }

}

function removeClass(o, className){
    addRemoveClass(o, className, true);
}

function addClass(o, className){
    addRemoveClass(o, className, false);
}

function forAncestors(node, func){
    if(node.parentNode){
        if(func(node.parentNode) !== false)
            forAncestors(node.parentNode, func);
    }

    return node;
}

function forChildren(node, func){
    if(node.childNodes){
        for(var x =0; x < node.childNodes.length; x++){
            forChildren(node.childNodes[x], func);
            func(node.childNodes[x])
        }
    }

    return node;
}


function getNodesWithAttr(contextNode, attr){
    var list = [];
    
    function recurseNodes(node){
        if(node.getAttribute && node.getAttribute(attr)){
            list.push(node);
        }


        if(node.childNodes){
            for(var x=0; x < node.childNodes.length; x++){
                recurseNodes(node.childNodes[x]);
            }
        }

    }

    if(contextNode)
        recurseNodes(contextNode, attr);

    return list;
    
}

function getNodesByName(contextNode, nodeName){
    var list = [];
    
    function recurseNodes(node){
        if(node.nodeName.toLowerCase() == nodeName.toLowerCase()){
            list.push(node);
        }

        if(node.childNodes){
            for(var x=0; x < node.childNodes.length; x++){
                recurseNodes(node.childNodes[x]);
            }
        }

    }

    if(contextNode)
        recurseNodes(contextNode, nodeName);

    return list;
    
}



function getMouseCoordinates(e){

    var posx = 0;
	var posy = 0;
	if (!e) var e = window.event;
	if (e.pageX || e.pageY) 	{
		posx = e.pageX;
		posy = e.pageY;
	}
	else if (e.clientX || e.clientY) 	{
        var src = evtSrc(e);
		posx = e.clientX + document.body.scrollLeft
			+ src.scrollLeft;
		posy = e.clientY + document.body.scrollTop
			+ src.scrollTop;
	}

    return {"x" : posx, "y" : posy};
}

function xpathQuery(node, query, type){
/*    if(node.selectNodes) {
        return node.selectNodes(query);
    } else if(!(window.XPathExpression === undefined)){
    */
    if(document.evaluate){
        var type = type ? type : XPathResult.ANY_TYPE;

        try {
            var result = document.evaluate(query, node, null, type, null);

            var next = null;
            var results = [];
            while(next = result.iterateNext()){
                results.push(next);
            }
        } catch (e){

            log(e);
        }

        return results;
    }

}


function getIframeDocument(iframe){
    //FF,IE
    if(iframe.contentDocument){
        return iframe.contentDocument;
    } else if (iframe.contentWindow.document) {
        return iframe.contentWindow.document;
    }

}

function getIframeInnerHeight(iframe){
    var doc = getIframeDocument(iframe);
    return (iframe.contentDocument ? doc.body.offsetHeight : doc.body.scrollHeight) + "px";
}


/**
 * @iframe
 * @size optional
 */
function resizeIframe(iframe, size){
    //set the height or continue to try to set it until it is displayed
    iframe.style.height = getIframeDocument(iframe).body.scrollHeight + "px";

    var intervalIframeID = -1;

    function isIframeResized(iframe){
        return (parseInt(iframe.style.height) == getIframeInnerHeight(iframe) );
    }

    function intervalSetIframeHeight(){
        if(!isIframeResized(iframe)) {
            iframe.style.height = getIframeInnerHeight(iframe);
            clearInterval(intervalIframeID);
        }
    }

    if(!isIframeResized(iframe))
        setInterval(intervalSetIframeHeight, 10);


}

function addStyleSheet(doc, url){
    var head = doc.getElementsByTagName("head");
    var style = doc.createElement("LINK");
    style.rel = "stylesheet";
    style.href = url;
    head.item(0).appendChild(style);

}


function log(e){
    if(e instanceof Error){
        ;//do log stuff
    } else {
        //new Error();
    }

}

function loadSources(doc, scripts){
    var hds = doc.getElementsByTagName("HEAD");
    var len = scripts.length;
    for(var x = 0; x < len; x++){
        var obj = scripts[x];
        var el;
        if(obj.type.toLowerCase() == "css"){
            el = doc.createElement("LINK");
            el.href = obj.src;
            el.setAttribute("type",  "text/css");
            el.setAttribute("rel",   "stylesheet");
            el.setAttribute("media", "all");
        }

        if(obj.type.toLowerCase() == "script"){
            el = doc.createElement("SCRIPT");
            el.src = obj.src;
        }

        hds[0].appendChild(el);

    }

}

/**
 *
 */
function getCleanedNode(oNode){
    var cloneNode = oNode.cloneNode(true);
    var inputs = cloneNode.getElementsByTagName("input");
    var doc = cloneNode.document ? cloneNode.document : cloneNode.ownerDocument;

    while(inputs.length > 0){
        var oldChild = inputs.item(0);
        var newChild = doc.createTextNode(oldChild.value);
        oldChild.parentNode.replaceChild(newChild, oldChild);
    }

    var selectsClone = cloneNode.getElementsByTagName("select");
    var selectsOrig = oNode.getElementsByTagName("select");

    var next = 0;
    for(var x = 0; x<selectsClone.length; x++){
        //get text from original node
        var origChild = selectsOrig.item(x);
        var text = origChild.options[origChild.selectedIndex].text;
        next++;

        //replace old child in cloned node
        var oldChild = selectsClone.item(x);
        var newChild = doc.createTextNode(text);
        oldChild.parentNode.insertBefore(newChild, oldChild);
    }

    while(selectsClone.item(0)){
        selectsClone.item(0).parentNode.removeChild(selectsClone.item(0));
    }    

    return cloneNode;
    
}




function previewInWindow(){
    var win = window.open();

    win.document.open();
    win.document.write("<html><head><title>WordsOnTheFly</title></head><frameset rows=\"50,*\"><frame src=\"frameBanner.html\"/><frame id=\"frame2\" /></frameset></html>");
    win.document.close();
    
    var prevDoc = win.frames[1].document;

    var id = -1;

    function tryInit(){
        if(prevDoc.body){
            var template = $("template");
            var cleaned = getCleanedNode(template);

            var tmp = document.createElement("div");
            tmp.appendChild(cleaned);

            //var head = windoc.getElementByTagName("head");
	        win.frames[1].document.designMode = "on";

            win.frames[1].document.body.innerHTML = tmp.innerHTML;
            
            clearInterval(id);
        }
    }

    id = setInterval(tryInit, 100);


}




function getMailToText(sAddress, sSubject, sBody){
    var addr = ["mailto:"];
    if(sAddress)
        a.push(address);
    
    var params = [];

    if(sSubject)
        params.push("subject=" + encodeURI(sSubject)); 

    if(sBody)
        params.push("body=" + encodeURI(sBody)); 

    params = params.join("&");
    addr.push(params);
    
    return addr.join("?");
}

//insert breaks
function addParagraphBreaks(txt){
    var pars = txt.getElementsByTagName("p");
    for(var x = 0; x < pars.length; x++){
	    var br = document.createElement("br");
	    var br2 = document.createElement("br");
	    var p = pars.item(x);
	    if(p.nextSibling){
	        p.parentNode.insertBefore(br, p.nextSibling);
	        br.parentNode.insertBefore(br2, p.nextSibling);
	    } else {
	        p.parentNode.appendChild(br);
	        p.parentNode.appendChild(br2);
	    }
    }
}

function refreshMailTo(){
    var email = $("email_template");
    if(email){
        var temp = $("template").cloneNode(true);
	    addParagraphBreaks(temp);
        var body = getCleanedNode(temp);
        var text = getInnerText(body);
	    
        email.href = getMailToText(null, null, text);

    }

}


function getUserSelection(doc, win) {
    win = win ? win : window;
    doc = doc ? doc : document;
    if (win.getSelection) {
	    return win.getSelection();
    }
    else if (doc.selection) { // should come last; Opera!
	    return doc.selection.createRange();
    }
}

function getRangeObject(sel, doc) {
    doc = doc ? doc : document;
	if (sel.getRangeAt) {
		return sel.getRangeAt(0);
    } else if (sel.pasteHTML){ //IE
        return sel;
    } else { // Safari!
		var range = doc.createRange();
        try {
		    range.setStart(sel.anchorNode,sel.anchorOffset);
		    range.setEnd(sel.focusNode,sel.focusOffset);
        } catch(e){ ;}

		return range;
	}
}


function rangeGetFrag(rng, doc){
    var doc = doc ? doc : document;
    var frag;
    if(rng.extractContents){ //FF
        frag = rng.extractContents();
    } else  { //IE
        frag = doc.createElement("DIV");
        frag.innerHTML = rng.htmlText;
    }
    return frag;

}

function rangeReplaceContents(rng, frag, doc){
    if(rng.extractContents){ //FF
        rng.deleteContents();
        rng.insertNode(frag);
    } else {

        var innerHTML = '';
        if(!frag.innerHTML) {
            var div = doc.createElement("DIV");
            div.appendChild(frag);
            innerHTML = div.innerHTML;
        } else {
            innerHTML = frag.innerHTML;
        }
        rng.pasteHTML(innerHTML);
    }
}

function selectionGetParent(sel, doc){
    var rng = getRangeObject(sel, doc);
    return (rng.commonAncestorContainer ? rng.commonAncestorContainer : sel.parentElement());
}

