// ==UserScript==
// @namespace       http://afunamatata.com/greasemonkey/
// @name            LJSupport: synedit, synmerge automator
// @description     Automate certain steps for synedit and synmerge
// @include         http://www.livejournal.com/support/see_request.bml?id=*
// @tags            ljsupport
// ==/UserScript==

// TODO: visual indications:
//  - border around the blog name if it's not filled in 
//  - throbber
//  - number indicating how many urls left to process

// there's a bug where if you put in a link to an html page in provided rss/atom feed, the behavior between what's returned by the soap and what's available in the html page is inconsistent.
// make synedit button grayed out when not usable?
// want to make the parsing out of links a perl webservice, to solve problem with relative links, and to avoid loading the images/flash videos/etc into your browser
// need to work on merge
// link to status history
//a utodetect urls and feed names, and fill in appropriate boxes, or have a clicky-thingy
// feedname should change onchange, not onclick
// show date created, date last updated, any errors, and the number of subscribers
// compare date created withthe date that the request was filed?
// convert "feed" into "http"

function addInput(name, labelString, size) {
    var label = document.createElement("label");
    label.innerHTML = " <strong>"+labelString + ": </strong>";
    var input = document.createElement("input");
    input.setAttribute("name", name);
    input.setAttribute("id", name);
    input.setAttribute("size", size);

    form.appendChild(label);
    form.appendChild(input);
}

function processLinks() {
    var links = syndicatedFrom.evaluate("//link[@rel='alternate'][@type='application/rss+xml' or @type='application/atom+xml']", syndicatedFrom, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
    var preferredURL = document.getElementById("edit_feed").value;
    var link = links.iterateNext();
    while (link) {
        // TODO: need to handle relative links (but this is hard! I wanna move a big chunk of this script into a Perl webservice since that has a module)
        if(link.href != preferredURL) {
            feedLinks.push(link.href);
        }
        link = links.iterateNext();
    }
    
    for(i in feedLinks) {
        // TODO: play nice and use setTimeout?
        validate(feedLinks[i])();
        
    }
}

function detectFeeds() {
    var fromURL = document.getElementById("edit_from").value;
    if(window == top) {
        if(fromURL) {
            GM_xmlhttpRequest({
                method: "GET",
                url: fromURL,
                onload: function(details) {
                  var iframe = document.createElement("iframe");
                  iframe.style.visibility = "hidden";
                  iframe.style.width = "0";
                  iframe.style.height = "0";
                  iframe.style.overflow="hidden";
                  iframe.style.position = "absolute";
                  document.body.appendChild(iframe);
            
                  if(iframe)
                  {
                      iframe.contentWindow.location.href = location.href;                        
                      iframe.contentDocument.open("text/html");
                      iframe.contentDocument.write(details.responseText);
                      iframe.contentDocument.close();
               
                      syndicatedFrom = iframe.contentDocument;
                      iframe.contentDocument.addEventListener("DOMContentLoaded", processLinks, false);
                  }
                }
            });        
        }
        else {
            for(i in feedLinks) {
                validate(feedLinks[i])();
            }

        }
    }
}

function nsResolver() {
    return "http://www.w3.org/2005/10/feed-validator";
}
function validate(arg) {
    var url = arg;       

    return function() {
        GM_xmlhttpRequest({ 
            method: "GET",
            url:    "http://validator.w3.org/feed/check.cgi?output=soap12&url=" + encodeURIComponent(url),
            onerror: function(details) {
                if(details.readyState == 4) {
                    results.appendChild(document.createTextNode( "Error looking up validator for " +url + ": " + details.responseText));

                }
            },
            onload: function(details){   
                if(details.readyState == 4) {
                    if(details.status != 200 ) {
                        results.appendChild(document.createTextNode( "Error looking up validator for " +url+ ". Please try again."));
                        results.appendChild(document.createElement("br"));                    
                        return;
                    }
                    
                    var response =  new DOMParser().parseFromString(details.responseText,
    "application/xml");
                                        
                    var errorCount = response.evaluate("//m:errorcount", response, nsResolver, XPathResult.NUMBER_TYPE, null).numberValue;
                    var errors = response.evaluate("//m:errorlist/error/type", response, nsResolver, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
                    
                    var warningCount = response.evaluate("//m:warningcount", response, nsResolver,  XPathResult.NUMBER_TYPE, null).numberValue;
                    var warnings = response.evaluate("//m:warninglist/warning/type", response, nsResolver, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
                    
                    var link = document.createElement("a");
                    link.setAttribute("href", url);
                    link.textContent = url;
                    
                    var valLink = document.createElement("a");
                    valLink.setAttribute("href", 'http://validator.w3.org/feed/check.cgi?url=' + encodeURIComponent(url));
                    valLink.textContent = "validator";
                    

                    var checkbox = document.createElement("input");
                    checkbox.setAttribute("type", "checkbox");
                    checkbox.setAttribute("name", "url");
                    checkbox.setAttribute("value", url);
                    
                    var li = document.createElement("li");
                    li.appendChild(checkbox);
                    if(url == document.getElementById("edit_feed").value) {    
                        li.appendChild(document.createTextNode("* "));
                        if(errorCount == 0 ){ checkbox.setAttribute("checked", "true");}
                    }
                    li.appendChild(link);
                    li.appendChild(document.createTextNode(" "));
                    li.appendChild(valLink);
                    li.appendChild(document.createElement("br"))
                    
                    // errors
                    if(isNaN(errorCount)) {
                        li.appendChild(document.createTextNode("Validator results could not be XML-parsed. Please check manually using the URL above ^"));
                    }
                    else {
                        if(errorCount == 0 ){       
                            li.appendChild(document.createTextNode("Validates with "));
                        } else {      
                            var errorList = new Array();
                            while((error = errors.iterateNext())) {
                                errorList.push(error.textContent);
                            }
                            li.appendChild(document.createTextNode("Not valid: " +
                                errorCount + ((errorCount == 1) ? " error " : " errors ") 
                                + "(" + errorList.join(", ")+") and "
                            ));
                        }
                        
                        if(warningCount == 0 ) {
                            li.appendChild(document.createTextNode("no warnings."));
                         } else {
                            var warningList = new Array();
                            while((warning = warnings.iterateNext())) {
                                warningList.push(warning.textContent);
                            }
                            li.appendChild(document.createTextNode(
                                warningCount + ((warningCount == 1 ) ? " warning " : " warnings ")
                                + "(" + warningList.join(", ") + ")"
                            ));
                         }
                     }       
                    resultsList.appendChild(li);
                    checkOnLJ(url, li)();
                    
                }
            }
        });
    }
}

function checkOnLJ(arg1, arg2) {
    var url = arg1;
    var li = arg2;
    return function() {
        GM_xmlhttpRequest({
            method: "GET",
            url: "http://www.livejournal.com/syn/?url=" + encodeURIComponent(url),
            onload: function(details) {
                if(details.readyState == 4) {
                    if(details.status != 200 ) {
                        results.appendChild(document.createTextNode( "Error looking up validator for " +url+ ". Please try again."));
                        results.appendChild(document.createElement("br"));                    
                        return;
                    }                
                }
                var output = details.responseText;
                li.appendChild(document.createElement("br"));
                if(out = /<input type='hidden' name="user" value="([^"]+)" \/>/.exec(output)) {
                    if(out)
                    {
                        var synname = out[1];
                        var span = document.createElement("span");
                        span.innerHTML = "This feed is being syndicated on LJ under the name <a href='http://syndicated.livejournal.com/"+synname+"/profile' title='[info]' alt='[info]'><img src='http://stat.livejournal.com/img/syndicated.gif' height='14px' width='14px' border='0'/></a> <a href='http://syndicated.livejournal.com/"+synname+"/'><strong>"+synname+"</strong></a>"
                        li.appendChild(span);
                     }
                } else if(/The URL you have entered is not currently being syndicated on this site/.test(output)) {
                    li.appendChild(document.createTextNode("This feed is not currently syndicated on LJ."));
                } else if(/You can't add RSS feeds from this site\./.test(output)) {
                    li.appendChild(document.createTextNode("This is already a LiveJournal feed."));
                } else {
                    li.appendChild(document.createTextNode("I couldn't work out if this feed is syndicated on LJ or not - try again."));
                }
                            
            }
        });
    }
}

function check() {
    // TODO: need some sort of way to indicate that it's still being processed
    feedLinks = new Array();
    resultsList.innerHTML = ""; // crappy way to reset

    var syn = document.getElementById("edit_account").value.replace(/^\s+|\s+$/g, "");
    document.getElementById("synaccount").innerHTML = "<a href='http://syndicated.livejournal.com/"+syn+"/profile' title='[info]' alt='[info]'><img src='http://stat.livejournal.com/img/syndicated.gif' height='14px' width='14px' border='0'/></a> <a href='http://syndicated.livejournal.com/"+syn+"/'><strong>"+syn+"</strong></a> <a href='view-source:http://syndicated.livejournal.com/"+syn+"/data/rss'>(current feed)</a>";
    
    var preferredURL = document.getElementById("edit_feed").value;
    if(preferredURL != "") {
        feedLinks.push(preferredURL);
    }

    detectFeeds();          
}

function doSetReplyType(type) {
    var replytypeBox = document.getElementById('replytype');
    if (! replytypeBox) return false;

    replytypeBox.value = type;
    return false;
}

function doSynedit() {

    if(document.getElementById("replytype").length == 4     // SH+
      && document.getElementById("console") != undefined) { // has the console GM script installed
        var textarea = document.getElementById("console");
    } else {
        var textarea = document.getElementById("body");
        doSetReplyType('internal');                                
    }

    var urls = document.getElementsByName("url");
    for(var i = 0; i < urls.length; ++i)  {
        if(urls[i].checked) {
            var account = document.getElementById("edit_account").value;
            textarea.value += "syn_editurl "
                    + account
                    + " " + urls[i].value + "\n";
            document.getElementById("body").value += "Thank you for your report. The feed URL for " 
                    + account
                    + " has now been updated to use " + urls[i].value + ".\n";
        }
    }

}
function doSynmerge() {
    var textarea =  
          (document.getElementById("replytype").length == 4
          && document.getElementById("console") != undefined) 
        ? document.getElementById("console") 
        : document.getElementById("body");
    
    textarea.value += "syn_merge A to B using URL\n";
    doSetReplyType('internal');
}


var changecat = document.getElementsByName("changecat")[0];
var selected = changecat[changecat.selectedIndex].textContent;
if(window==top && changecat && (selected.indexOf('RSS') != -1 || selected.indexOf('Russian') != -1 )) {
    GM_addStyle("#automator {border: 3px black solid; padding: 2px; margin: 10px 0;} \n\
    #edit_results {border-right: 1px gray solid; border-bottom: 1px gray solid; background-color: #eee;}\n\
    #edit_results li, #synaccount {font-size: 0.8em;}");
    insertionPoint = document.evaluate("//a[@name]|//p[@style]", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.previousSibling;

    var div = document.createElement("div");
    div.setAttribute("id", "automator");
    
    var synAccount = document.createElement("div");
    synAccount.setAttribute("id", "synaccount");
    
    var feedLinks;
    
    // SYNEDIT
    var form = document.createElement("form");
    form.setAttribute("id", "edit_form");
    
    addInput("edit_account", "Account", 15);
    addInput("edit_feed", "Provided RSS/Atom Feed", 50);
    form.appendChild(document.createElement("br"));
    addInput("edit_from", "Auto-detect from Page (experimental; detect possible synmerge)", 30);
    var input = document.createElement("input");
    input.setAttribute("type", "button");
    input.setAttribute("value", "Check");
    input.addEventListener("click", check, false);
    form.appendChild(input);
    
    var warning = document.createElement("div");
    warning.innerHTML="<small>autodetect is a work in progress. Tends to hang on some pages, and it loads the entire page into browser memory, which is Not Good. I'll try to fix it soon!</small>";    
    form.appendChild(warning);    
    
    var editResults = document.createElement("div");
    editResults.setAttribute("id", "edit_results");

    var resultsList = document.createElement("ul");

    var controls = document.createElement("div");
    var synedit = document.createElement("input");
    synedit.setAttribute("type", "button");
    synedit.setAttribute("value", "synedit");   
    synedit.addEventListener("click", doSynedit, false);

    var synmerge = document.createElement("input");
    synmerge.setAttribute("type", "button");
    synmerge.setAttribute("value", "synmerge");
    synmerge.addEventListener("click", doSynmerge, false);
    
    controls.appendChild(synedit)
    controls.appendChild(synmerge);
    // URL of the syndicated account and of the blog and of the preferred URL
    // autodetect the blog's url? check the page...
    // auto-detect the blog's feeds 
    // for each feed URL (NEED TO INDICATE HOW MANY LEFT)
    //   provide the link
    //   validates?
    //   syndicated onto livejournal?
    
    
    // SYNMERGE
    // names of the syndicated accounts, blog URL, preferred URL
    
    editResults.appendChild(resultsList);
    editResults.appendChild(controls);
    form.appendChild(synAccount);    
    form.appendChild(editResults);
    div.appendChild(form);
    insertionPoint.appendChild(div);
    
    // TODO: want to prefill values
//    document.getElementById("edit_from").value = "http://afuna.livejournal.com";
//    document.getElementById("edit_feed").value="http://afuna.livejournal.com/data/rss";
}
