// Domain Public by Eric Wendelin http://eriwen.com/ (2008)
//                  Luke Smith http://lucassmith.name/ (2008)
//                  Loic Dachary <loic@dachary.org> (2008)
//                  Johan Euphrosine <proppy@aminche.com> (2008)
//
// Information and discussions
// http://jspoker.pokersource.info/skin/test-printstacktrace.html
// http://eriwen.com/javascript/js-stack-trace/
// http://pastie.org/253058
// http://browsershots.org/http://jspoker.pokersource.info/skin/test-printstacktrace.html
//

//
// guessFunctionNameFromLines comes from firebug
//
// Software License Agreement (BSD License)
//
// Copyright (c) 2007, Parakey Inc.
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above
//   copyright notice, this list of conditions and the
//   following disclaimer.
//
// * Redistributions in binary form must reproduce the above
//   copyright notice, this list of conditions and the
//   following disclaimer in the documentation and/or other
//   materials provided with the distribution.
//
// * Neither the name of Parakey Inc. nor the names of its
//   contributors may be used to endorse or promote products
//   derived from this software without specific prior
//   written permission of Parakey Inc.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

function printStackTrace(options) {
    if (options && options.guess) {
        var p = new printStackTrace.implementation();
        var result = p.run();
        return p.guessFunctions(result);
    }
    return (new printStackTrace.implementation()).run();
}

printStackTrace.implementation = function() {};

printStackTrace.implementation.prototype = {
    run: function() {
        mode = this.mode();
        if(mode != 'other') {
            try {(0)();} catch (e) {
                return this[mode](e);
            }
        } else {
            return this.other(arguments.callee);
        }
    },

    mode: function() {
        var mode;
        try {(0)();} catch (e) {
	        if (e.arguments) {
		        mode = 'chrome';
	        } else if (e.stack) {
	        	mode = 'firefox';
            } else {
            	mode = 'other';
            }
        }
        return mode;
    },

    chrome: function(e) {
        return e.stack.replace(/^.*?\n/,'').
        replace(/^.*?\n/,'').
        replace(/^.*?\n/,'').
        replace(/^[^\(]+?[\n$]/gm,'').
        replace(/^\s+at\s+/gm,'').
        replace(/^Object.<anonymous>/gm,'{anonymous}()').
        split("\n");
    },
    
    firefox: function(e) {
        return e.stack.replace(/^.*?\n/,'').
        replace(/(?:\n@:0)?\s+$/m,'').
        replace(/^\(/gm,'{anonymous}(').
        split("\n");
    },

    other: function(curr) {
        var ANON = "{anonymous}",
        fnRE  = /function\s*([\w\-$]+)?\s*\(/i,
        stack = [],j=0,fn,args;

		var maxStackSize = 10;
        while (curr && stack.length < maxStackSize) {
            fn = fnRE.test(curr.toString()) ? RegExp.$1 || ANON : ANON;
            args = Array.prototype.slice.call(curr['arguments']);
            stack[j++] = fn + '(' + printStackTrace.implementation.prototype.stringifyArguments(args) + ')';

			//Opera bug: if curr.caller does not exist, Opera returns curr (WTF)
            if (curr === curr.caller && window.opera) {
	            break;
	        } 
	        curr = curr.caller;
        }
        return stack;
    },

    stringifyArguments: function(args) {
        for (var i = 0; i < args.length; ++i) {
            var argument = args[i];
            if (typeof argument  == 'object') {
                args[i] = '#object';
            } else if (typeof argument == 'function') {
                args[i] = '#function';
            } else if (typeof argument == 'string') {
                args[i] = '"'+argument+'"';
            }
        }
        return args.join(',');
    },
    
    sourceCache: {},

    ajax: function(url) {
	    var req = this.createXMLHTTPObject();
	    if (!req) {
	        return;
	    }
	    req.open('GET', url, false);
	    req.setRequestHeader("User-Agent", "XMLHTTP/1.0");
	    req.send('');
		return req.responseText;
    },

	createXMLHTTPObject: function() {
		var XMLHttpFactories = [
		    function () {
		        return new XMLHttpRequest();
		    },
		    function () {
		        return new ActiveXObject("Msxml2.XMLHTTP");
		    },
		    function () {
		        return new ActiveXObject("Msxml3.XMLHTTP");
		    },
		    function () {
		        return new ActiveXObject("Microsoft.XMLHTTP");
		    }
		];
	    var xmlhttp = false;
	    for (var i = 0; i < XMLHttpFactories.length; i++) {
	        try {
	            xmlhttp = XMLHttpFactories[i]();
	        }
	        catch (e) {
	            e = null;
	            continue;
	        }
	        break;
	    }
	    return xmlhttp;
	},

    getSource: function(url) {
        var self = this;
        if (!(url in self.sourceCache)) {
            self.sourceCache[url] = self.ajax(url).split("\n");
        }
        return self.sourceCache[url];
    },

    guessFunctions: function(stack) {
        for (var i = 0; i < stack.length; ++i) {
            var reStack = /{anonymous}\(.*\)@(.*):(\d+)/;
            var frame = stack[i];
            var m = reStack.exec(frame);
            if (m) {
                var file = m[1];
                var lineno = m[2];
                if (file && lineno) {
                    var functionName = this.guessFunctionName(file, lineno);
                    stack[i] = frame.replace('{anonymous}', functionName);
                }
            }
        }
        return stack;
    },

    guessFunctionName: function(url, lineNo) {      
        var source;
        try {
            source = this.getSource(url);
        } catch (e) {
            return 'getSource failed with url: ' + url + ', exception: ' + e.toString();
        }
        return this.guessFunctionNameFromLines(lineNo, source);
    },

    guessFunctionNameFromLines: function(lineNo, source) {
        var reFunctionArgNames = /function ([^(]*)\(([^)]*)\)/;
        var reGuessFunction = /['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*(function|eval|new Function)/;
        // Walk backwards from the first line in the function until we find the line which
        // matches the pattern above, which is the function definition
        var line = "";
        var maxLines = 10;
        for (var i = 0; i < maxLines; ++i) {
            line = source[lineNo-i] + line;
            if (line !== undefined) {
                var m = reGuessFunction.exec(line);
                if (m) {
                    return m[1];
                } else {
                    m = reFunctionArgNames.exec(line);
                } 
                if (m && m[1]) {
                    return m[1];
                }
            }
        }
        return "(?)";
    }
};

function foo() {
    var blah;
    bar("blah");
}

function bar(blah) {
    var stuff;
    thing();
}

function thing() {
    if (true) { //your error condition here
        var st = printStackTrace();
		alert(st.join("\n\n"));
    }
}

function getEmSize(el) {
    // If you pass in an element ID then get a reference to the element
    if (typeof el == "string") el = document.getElementById(el);

    if (el != null) {
        var tempDiv = document.createElement("DIV");
        tempDiv.style.height = 1 + "em";
      // Make a readable bar with the em measurement
        tempDiv.style.background = "#FF9";
        tempDiv.style.color = "#000";
        tempDiv.style.paddingBottom = 4 + "px"; // This makes the DIV text readable
        // Just in case the content of "el" takes up it's container's height :)
        tempDiv.style.marginTop = -1 + "em";

        el.appendChild(tempDiv);
      // Remember to take off the 4px we added earlier
        var emSize = (tempDiv.offsetHeight - 4) + "px";
        tempDiv.innerHTML = emSize;
    }
}

function highlightOnLoad() {
    // Get search string
    if (/s\=/.test(window.location.search)) {
        var searchString = getSearchString();
        // Starting node, parent to all nodes you want to search
        var textContainerNode = document.getElementById("content");
        var searchInfo = 'Search Results for: ';
        // Split search terms on '|' and iterate over resulting array
        var searchTerms = searchString.split('|');
        for (var i in searchTerms) {
            // The regex is the secret, it prevents text within tag declarations to be affected
            var regex = new RegExp(">([^<]*)?(" + searchTerms[i] + ")([^>]*)?<", "ig");
            highlightTextNodes(textContainerNode, regex, i);
            searchInfo += ' <span class="highlighted term' + i + '">' + searchTerms[i] + '</span> ';
        }
        var searchTermDiv = document.createElement("H2");
        searchTermDiv.className = 'searchterms';
        searchTermDiv.innerHTML = searchInfo;
        textContainerNode.insertBefore(searchTermDiv, textContainerNode.childNodes[0]);
    }
}
  
  // Pull the search string out of the URL
function getSearchString() {
    var rawSearchString = window.location.search.replace(/[a-zA-Z0-9\?\&\=\%\#]+s\=(\w+)(\&.*)?/, "$1");
    // Replace '+' with '|' for regex
    // Also replace '%20' if your cms/blog uses this instead
    return rawSearchString.replace(/\%20|\+/g, "\|");
}

function highlightTextNodes(element, regex, termid) {
    var tempinnerHTML = element.innerHTML;
    element.innerHTML = tempinnerHTML.replace(regex, '>$1<span class="highlighted term' + termid + '">$2</span>$3<');
}

function showTwitterStatus(data) {
	if (data && data[0].text) {
		jQuery('#status-text').text(data[0].text);
	} else {
		jQuery('#status-text').text('Fail whale...');
	}	
}

function displayDeliciousCount(data) {
	var urlinfo = data[0]; if (!urlinfo || !urlinfo.total_posts) return; 
	var el = jQuery('span.delicious-count');
	if (el) {
		el.text(urlinfo.total_posts);
		el.css('display','inline');
		if (urlinfo.total_posts < 10) el.css('padding','3px 7px');
	}
}

function displayRedditScore(data) {
	if (data) {
		var score = data.children[0].data.score;
		//Inject reddit score
	}
}

function suprShorten(url) {
   	jQuery.getJSON('http://su.pr/api/shorten?longUrl='+url+'&login=emwendelin&apiKey=5231a051c912656a2db53ba0db7865e1',
	function(data) {
		if (data.results && data.results.shortUrl) {
			return data.results.shortUrl;
		}
	});	
}

function displayRetweetCount() {
    jQuery('li.sprite-twitter').each(function(elem) {
        elem.href = "http://twitter.com/home?status=" + encodeURIComponent(suprShorten(permalink));
    });
}

jQuery(document).ready(function() {
	highlightOnLoad();
	jQuery('#searchsubmit').click(function() { document.getElementById('searchform').submit(); });
	jQuery('#bannertext').click(function() { window.location.href = 'http://eriwen.com'; });
	jQuery.getScript('http://feeds.delicious.com/v2/json/urlinfo/data?url='+permalink+'&callback=displayDeliciousCount');
	jQuery.get('http://www.reddit.com/api/info.json?url=' + permalink, displayRedditScore);
	//jQuery.getScript('http://twitter.com/statuses/user_timeline/eriwen.json?callback=showTwitterStatus&count=1');
});
