function start_pf() {
    var pfArea = document.createElement("div");
    pfArea.id = "pf-print-area";    
    pfArea.appendChild(getMainContent());
    var pnicerBody = document.getElementById('pnicer-body');
    pnicerBody.innerHTML = "";
    pnicerBody.appendChild(pfArea);
}

var log = function(s) {
    if(typeof console !== 'undefined') {
        console.log("PFLog: " + s);
    }
};

var pfspace = {
    bodyCache:  null, 
    flags: 0x1 | 0x2, 
    FLAG_STRIP_UNLIKELYS: 0x1,
    FLAG_WEIGHT_CLASSES:  0x2,

    regexps: {
        unlikelyCandidatesRe:   /combx|comment|disqus|foot|header|menu|meta|rss|shoutbox|sidebar|sponsor/i,
        okMaybeItsACandidateRe: /and|article|body|column|main/i,
        positiveRe:             /article|body|content|entry|hentry|page|pagination|post|text/i,
        negativeRe:             /combx|comment|contact|foot|footer|footnote|link|media|meta|promo|related|scroll|shoutbox|sponsor|tags|widget/i,
        divToPElementsRe:       /<(a|blockquote|dl|div|img|ol|p|pre|table|ul)/i,
        replaceBrsRe:           /(<br[^>]*>[ \n\r\t]*){2,}/gi,
        replaceFontsRe:         /<(\/?)font[^>]*>/gi,
        trimRe:                 /^\s+|\s+$/g,
        normalizeRe:            /\s{2,}/g,
        killBreaksRe:           /(<br\s*\/?>(\s|&nbsp;?)*){1,}/g,
        videoRe:                /http:\/\/(www\.)?(youtube|vimeo)\.com/i
    },

    initializeNode: function (node) {
        node.pfspace = {"contentScore": 0};         

        switch(node.tagName) {
        case 'DIV':
            node.pfspace.contentScore += 5;
            break;
        
        case 'PRE':
        case 'TD':
        case 'BLOCKQUOTE':
            node.pfspace.contentScore += 3;
        break;
        
        case 'ADDRESS':
        case 'OL':
        case 'UL':
        case 'DL':
        case 'DD':
        case 'DT':
        case 'LI':
        case 'FORM':
            node.pfspace.contentScore -= 3;
        break;
        
        case 'H1':
        case 'H2':
        case 'H3':
        case 'H4':
        case 'H5':
        case 'H6':
        case 'TH':
            node.pfspace.contentScore -= 5;
        break;
        }
        node.pfspace.contentScore += pfspace.getClassWeight(node);
    },

    getCharCount: function (e,s) {
        s = s || ",";
        return pfspace.getInnerText(e).split(s).length-1;
    },

    getLinkDensity: function (e) {
        var links      = e.getElementsByTagName("a");
        var textLength = pfspace.getInnerText(e).length;
        var linkLength = 0;
        for(var i=0, il=links.length; i<il;i++) {
            linkLength += pfspace.getInnerText(links[i]).length;
        }       

        return linkLength / textLength;
    },

    getClassWeight: function (e) {
        if(!pfspace.flagIsActive(pfspace.FLAG_WEIGHT_CLASSES)) {
            return 0;
        }

        var weight = 0;

        /* Look for a special classname */
        if (e.className != "")
        {
            if(e.className.search(pfspace.regexps.negativeRe) !== -1) {
                weight -= 25; }

            if(e.className.search(pfspace.regexps.positiveRe) !== -1) {
                weight += 25; }
        }

        /* Look for a special ID */
        if (typeof(e.id) == 'string' && e.id != "")
        {
            if(e.id.search(pfspace.regexps.negativeRe) !== -1) {
                weight -= 25; }

            if(e.id.search(pfspace.regexps.positiveRe) !== -1) {
                weight += 25; }
        }

        return weight;
    },

    killBreaks: function (e) {
        try {
            e.innerHTML = e.innerHTML.replace(pfspace.regexps.killBreaksRe,'<br />');       
        }
        catch (eBreaks) {
            log("KillBreaks failed - this is an IE bug. Ignoring.: " + eBreaks);
        }
    },

    cleanStyles: function (e) {
        e = e || document;
        var cur = e.firstChild;

        if(!e) { return; }

        // Go until there are no more child nodes
        while ( cur !== null ) {
            if ( cur.nodeType == 1 ) {
                // Remove style attribute(s) :
                if(cur.className != "pf-print-area") {
                    cur.removeAttribute("style");                   
                }
                pfspace.cleanStyles( cur );
            }
            cur = cur.nextSibling;
        }       
    },

    clean: function (e, tag) {
        var targetList = e.getElementsByTagName( tag );
        var isEmbed    = (tag == 'object' || tag == 'embed');
        
        for (var y=targetList.length-1; y >= 0; y--) {
            if(isEmbed) {
                var attributeValues = "";
                for (var i=0, il=targetList[y].attributes.length; i < il; i++) {
                    attributeValues += targetList[y].attributes[i].value + '|';
                }
                
                if (attributeValues.search(pfspace.regexps.videoRe) !== -1) {
                    continue;
                }

                if (targetList[y].innerHTML.search(pfspace.regexps.videoRe) !== -1) {
                    continue;
                }
                
            }

            targetList[y].parentNode.removeChild(targetList[y]);
        }
    },

    cleanHeaders: function (e) {
        for (var headerIndex = 1; headerIndex < 7; headerIndex++) {
            var headers = e.getElementsByTagName('h' + headerIndex);
            for (var i=headers.length-1; i >=0; i--) {
                if (pfspace.getClassWeight(headers[i]) < 0 || pfspace.getLinkDensity(headers[i]) > 0.33) {
                    headers[i].parentNode.removeChild(headers[i]);
                }
            }
        }
    },

    cleanConditionally: function (e, tag) {
        var tagsList      = e.getElementsByTagName(tag);
        var curTagsLength = tagsList.length;

        for (var i=curTagsLength-1; i >= 0; i--) {
            var weight = pfspace.getClassWeight(tagsList[i]);
            var contentScore = (typeof tagsList[i].pfspace != 'undefined') ? tagsList[i].pfspace.contentScore : 0;
            
            if(weight+contentScore < 0) {
                tagsList[i].parentNode.removeChild(tagsList[i]);
            }
            else if (pfspace.getCharCount(tagsList[i],',') < 10) {
                var p      = tagsList[i].getElementsByTagName("p").length;
                var img    = tagsList[i].getElementsByTagName("img").length;
                var li     = tagsList[i].getElementsByTagName("li").length-100;
                var input  = tagsList[i].getElementsByTagName("input").length;

                var embedCount = 0;
                var embeds     = tagsList[i].getElementsByTagName("embed");
                
                for(var ei=0,il=embeds.length; ei < il; ei++) {
                    if (embeds[ei].src.search(pfspace.regexps.videoRe) == -1) {
                        embedCount++; 
                    }
                }

                var linkDensity   = pfspace.getLinkDensity(tagsList[i]);
                var contentLength = pfspace.getInnerText(tagsList[i]).length;
                var toRemove      = false;

                if ( img > p ) {
                    toRemove = true;
                } else if(li > p && tag != "ul" && tag != "ol") {
                    toRemove = true;
                } else if( input > Math.floor(p/3) ) {
                    toRemove = true; 
                } else if(contentLength < 25 && (img === 0 || img > 2) ) {
                    toRemove = true;
                } else if(weight < 25 && linkDensity > 0.2) {
                    toRemove = true;
                } else if(weight >= 25 && linkDensity > 0.5) {
                    toRemove = true;
                } else if((embedCount == 1 && contentLength < 75) || embedCount > 1) {
                    toRemove = true;
                }

                if(toRemove) {
                    tagsList[i].parentNode.removeChild(tagsList[i]);
                }
            }
        }
    },

    prepArticle: function (articleContent) {
        pfspace.cleanStyles(articleContent);
        pfspace.killBreaks(articleContent);

        /* Clean out junk from the article content */
        pfspace.clean(articleContent, "form");
        pfspace.clean(articleContent, "object");
        pfspace.clean(articleContent, "h1");
        /**
         * If there is only one h2, they are probably using it
         * as a header and not a subheader, so remove it since we already have a header.
        ***/
        if(articleContent.getElementsByTagName('h2').length == 1) {
            pfspace.clean(articleContent, "h2"); }
        pfspace.clean(articleContent, "iframe");

        pfspace.cleanHeaders(articleContent);

        /* Do these last as the previous stuff may have removed junk that will affect these */
        pfspace.cleanConditionally(articleContent, "table");
        pfspace.cleanConditionally(articleContent, "ul");
        pfspace.cleanConditionally(articleContent, "div");

        /* Remove extra paragraphs */
        var articleParagraphs = articleContent.getElementsByTagName('p');
        for(var i = articleParagraphs.length-1; i >= 0; i--) {
            var imgCount    = articleParagraphs[i].getElementsByTagName('img').length;
            var embedCount  = articleParagraphs[i].getElementsByTagName('embed').length;
            var objectCount = articleParagraphs[i].getElementsByTagName('object').length;
            
            if(imgCount === 0 && embedCount === 0 && objectCount === 0 && pfspace.getInnerText(articleParagraphs[i], false) == '') {
                articleParagraphs[i].parentNode.removeChild(articleParagraphs[i]);
            }
        }

        try {
            articleContent.innerHTML = articleContent.innerHTML.replace(/<br[^>]*>\s*<p/gi, '<p');      
        }
        catch (e) {
            log("Cleaning innerHTML of breaks failed. This is an IE strict-block-elements bug. Ignoring.: " + e);
        }
    },

    getInnerText: function (e, normalizeSpaces) {
        var textContent    = "";

        normalizeSpaces = (typeof normalizeSpaces == 'undefined') ? true : normalizeSpaces;

        if (navigator.appName == "Microsoft Internet Explorer") {
            textContent = e.innerText.replace( pfspace.regexps.trimRe, "" ); }
        else {
            textContent = e.textContent.replace( pfspace.regexps.trimRe, "" ); }

        if(normalizeSpaces) {
            return textContent.replace( pfspace.regexps.normalizeRe, " "); }
        else {
            return textContent; }
    },

    flagIsActive: function(flag) {
        return (pfspace.flags & flag) > 0;
    },
    
    addFlag: function(flag) {
        pfspace.flags = pfspace.flags | flag;
    },
    
    removeFlag: function(flag) {
        pfspace.flags = pfspace.flags & ~flag;
    }    
};


function getMainContent() {  
    var topDiv = document.createElement("DIV");
    var articleContent = document.createElement("DIV");
    var articleTitle = document.createElement("H1");
	
    // Grab the title from the <title> tag and inject it as the title.
    articleTitle.innerHTML = document.title;
    articleContent.appendChild(articleTitle);

    // heart of the algo:
    var stripJunk = pfspace.flagIsActive(pfspace.FLAG_STRIP_UNLIKELYS);
    var node = null;
    var nodesToScore = [];

    for(var nodeIndex = 0; (node = document.getElementsByTagName("*")[nodeIndex]); nodeIndex++) {
        /* Remove unlikely candidates */
        if (stripJunk) {
            var unlikelyMatchString = node.className + node.id;
            if (unlikelyMatchString.search(pfspace.regexps.unlikelyCandidatesRe) !== -1 && unlikelyMatchString.search(pfspace.regexps.okMaybeItsACandidateRe) == -1 && node.tagName !== "BODY") {
                node.parentNode.removeChild(node);
                nodeIndex--;
                continue;
            }               
        }

        if (node.tagName === "P" || node.tagName === "TD") {
            nodesToScore[nodesToScore.length] = node;
        }
        
        if (node.tagName === "DIV") {
            if (node.innerHTML.search(pfspace.regexps.divToPElementsRe) === -1) {
                var newNode = document.createElement('p');
                try {
                    newNode.innerHTML = node.innerHTML;             
                    node.parentNode.replaceChild(newNode, node);
                    nodeIndex--;
                }
                catch(e) {
                    log("Could not alter div to p, probably an IE restriction, reverting back to div.: " + e);
                }
            }
            else {
                for(var i = 0, il = node.childNodes.length; i < il; i++) {
                    var childNode = node.childNodes[i];
                    if(childNode.nodeType == 3) { // Node.TEXT_NODE
                        var p = document.createElement('p');
                        p.innerHTML = childNode.nodeValue;
                        p.style.display = 'inline';
                        childNode.parentNode.replaceChild(p, childNode);
                    }
                }
            }
        }
    }

    var candidates = [];
    for (var pt=0; pt < nodesToScore.length; pt++) {
        var parentNode      = nodesToScore[pt].parentNode;
        var grandParentNode = parentNode.parentNode;
        var innerText       = pfspace.getInnerText(nodesToScore[pt]);

        if(innerText.length < 25) {
            continue; 
        }

        if(typeof parentNode.pfspace == 'undefined') {
            pfspace.initializeNode(parentNode);
            candidates.push(parentNode);
        }

        if(typeof grandParentNode.pfspace == 'undefined') {
            pfspace.initializeNode(grandParentNode);
            candidates.push(grandParentNode);
        }

        var contentScore = 0;

        contentScore++;
        contentScore += innerText.split(',').length;            
        contentScore += Math.min(Math.floor(innerText.length / 100), 3);
        parentNode.pfspace.contentScore += contentScore;
        grandParentNode.pfspace.contentScore += contentScore/2;
    }

    var topCandidate = null;
    for(var c=0, cl=candidates.length; c < cl; c++) {
        candidates[c].pfspace.contentScore = candidates[c].pfspace.contentScore * (1-pfspace.getLinkDensity(candidates[c]));

        if(!topCandidate || candidates[c].pfspace.contentScore > topCandidate.pfspace.contentScore) {
            topCandidate = candidates[c]; }
    }

    if (topCandidate === null || topCandidate.tagName == "BODY") {
        topCandidate = document.createElement("DIV");
        topCandidate.innerHTML = pfspace.bodyCache.innerHTML;
        pfspace.initializeNode(topCandidate);
    }

    var siblingScoreThreshold = Math.max(10, topCandidate.pfspace.contentScore * 0.2);
    var siblingNodes          = topCandidate.parentNode.childNodes;
    for(var s=0, sl=siblingNodes.length; s < sl; s++) {
        var siblingNode = siblingNodes[s];
        var append      = false;

        if(siblingNode === topCandidate) {
            append = true;
        }
            
        if(typeof siblingNode.pfspace != 'undefined' && siblingNode.pfspace.contentScore >= siblingScoreThreshold) {
            append = true;
        }
            
        if(siblingNode.nodeName == "P") {
            var linkDensity = pfspace.getLinkDensity(siblingNode);
            var nodeContent = pfspace.getInnerText(siblingNode);
            var nodeLength  = nodeContent.length;
                
            if(nodeLength > 80 && linkDensity < 0.25) {
                append = true;
            }
            else if(nodeLength < 80 && linkDensity === 0 && nodeContent.search(/\.( |$)/) !== -1) {
                append = true;
            }
        }

        if(append) {
            var nodeToAppend = null;
            if(siblingNode.nodeName != "DIV" && siblingNode.nodeName != "P") {
                nodeToAppend = document.createElement('div');
                try {
                    nodeToAppend.id = siblingNode.id;
                    nodeToAppend.innerHTML = siblingNode.innerHTML;
                }
                catch(e) {
                    nodeToAppend = siblingNode;
                    s--;
                    sl--;
                }
            } else {
                nodeToAppend = siblingNode;
                s--;
                sl--;
            }

            nodeToAppend.className = "";            
            topDiv.appendChild(nodeToAppend);
        }
    }

    pfspace.prepArticle(topDiv);
    for (i = 0; (link = topDiv.getElementsByTagName('a')[i]) ; ++i) {
        link.onclick = function() {
            return false;
        };
    }
    articleContent.appendChild(topDiv);
    
    return articleContent;
}

