var changesets = {}; // map of csid -> array of revids
var revid2csid = {};
var revidsInIteration = {};
var repnameInUse = "";

function buildArrayParams(pars, key, arrValue){
    pars = pars ? pars + "&" : "";
    for (var i = 0; i < arrValue.length; i++) {
        if (arrValue[i]) {
            if (i > 0) {
                pars += "&";
            }
            pars = addParamValPair(pars, key, arrValue[i]);
        }
    }
    return pars;
}

function buildParams(pars, key, value) {
    pars = pars ? pars + "&" : "";
    pars = addParamValPair(pars, key, value);
    return pars;
}

function addParamValPair(pars, key, value) {
    pars += encodeURIComponent(key) + "=";
    pars += encodeURIComponent(value);
    return pars;
}

function addRevisionToIter(permaId, revid, sourceName) {
    addRemoveRevisionToIter(true, permaId, revid, sourceName);
}
function removeRevisionFromIter(permaId, revid, sourceName) {
    addRemoveRevisionToIter(false, permaId, revid, sourceName);
}
function addRemoveRevisionToIter(add, permaId, revid, sourceName) {
    var busyid = "busyRev" + revid;
    var nochangeid = "";
    var revPath = $("revPath" + revid);
    toggleNodeAndImage(busyid, true, false, true);
    if (add) {
        toggleNodeAndImage("addRev" + revid, false, true, true);
        nochangeid = "addRev" + revid;
        if (revPath) {
            revPath.style.textDecoration = "";
        }
    } else {
        toggleNodeAndImage("remRev" + revid, false, true, true);
        nochangeid = "remRev" + revid;
        if (revPath) {
            revPath.style.textDecoration = "line-through";
        }
    }
    var pars = buildParams(pars, "revid", revid);
    pars = buildParams(pars, "command", (add ? "add" : "remove"));
    pars = buildParams(pars, "sourceName", (sourceName ? sourceName : "FE:" + repnameInUse));
    pars = buildParams(pars, "diff", "lastrev");
    var url = fishEyePageContext + "/json/cru/" + permaId + "/editRevisionsAjax/";

    return doAddRemoveCall(url, pars, busyid, nochangeid);
}

function addRevisionsToIter(permaId, revIdArray, sourceName) {
    var pars;
    for (var i = 0; i < revIdArray.length; i++) {
        var revid = revIdArray[i];
        var revPath = $("revPath" + revid);
        if (revPath) {
            revPath.style.textDecoration = "";
        }
        pars = buildParams(pars, "revid", revid);
    }
    pars = buildParams(pars, "command", "add");
    pars = buildParams(pars, "sourceName", (sourceName ? sourceName : "FE:" + repnameInUse));
    pars = buildParams(pars, "diff", "lastrev");
    var url = fishEyePageContext + "/json/cru/" + permaId + "/editRevisionsAjax/";

    return doAddMultipleCall(url, pars);
}

function doAddMultipleCall(url, pars) {
    var done = function(req) {
        var resp = eval("(" + req.responseText + ")");
        if (checkError(resp)) {
            return false;
        }
        $("cart").innerHTML = resp.msgHtml;

        var updatedChangesets = {};

        for (var i = 0; i < resp.addedRevids.length; i++) {
            var addedRevid = resp.addedRevids[i];
            updatedChangesets[revid2csid[addedRevid]] = 1;
            revidsInIteration[addedRevid] = 1;
            toggleNodeAndImage("addRev" + addedRevid, false, true, true);
            toggleNodeAndImage("remRev" + addedRevid, true, false, true);
        }
        for (var csid in updatedChangesets) {
            updateChangesetAddRemove(csid);
        }
    };

    new Ajax.Request(url, {parameters: pars, onSuccess: done});
}

function checkError(resp) {
    if (!resp.worked) {
        window.alert(resp.errorMsg);
        return true;
    }
    return false;
}

function doAddRemoveCall(url, pars, busyid, nochangeid) {
    var done = function(req) {
        var resp = eval("(" + req.responseText + ")");
        if (checkError(resp)) {
            toggleNodeAndImage(busyid, false, true, true);
            toggleNodeAndImage(nochangeid, true, false, true);
            return false;
        }
        $("cart").innerHTML = resp.msgHtml;

        var updatedChangesets = {};

        toggleNodeAndImage(busyid, false, true, true);
        toggleNodeAndImage(nochangeid, true, false, true);

        for (var i = 0; i < resp.addedRevids.length; i++) {
            var addedRevid = resp.addedRevids[i];
            updatedChangesets[revid2csid[addedRevid]] = 1;
            revidsInIteration[addedRevid] = 1;
            toggleNodeAndImage("addRev" + addedRevid, false, true, true);
            toggleNodeAndImage("remRev" + addedRevid, true, false, true);
        }
        for (i = 0; i < resp.removedRevids.length; i++) {
            var removedRevid = resp.removedRevids[i];
            updatedChangesets[revid2csid[removedRevid]] = 1;
            revidsInIteration[removedRevid] = 0;
            toggleNodeAndImage("addRev" + removedRevid, true, false, true);
            toggleNodeAndImage("remRev" + removedRevid, false, true, true);
        }

        for (var csid in updatedChangesets) {
            updateChangesetAddRemove(csid);
        }
    };

    new Ajax.Request(url, {parameters: pars, onSuccess: done}); // TODO on error
}

function updateChangesetAddRemove(csid) {
    var revids = changesets[csid];
    var inCount = 0;
    for (var i = 0; i < revids.length; i++) {
        var revid = revids[i];
        if (revidsInIteration[revid] == 1) {
            inCount++;
        }
    }
    var showAdd = inCount < revids.length;
    var showRemove = inCount > 0;
    var showSome = showAdd && showRemove;
    if (showSome) {
        showAdd = false;
        showRemove = false;
    }
    toggleNodeAndImage("addCs" + csid, showAdd, !showAdd, true);
    toggleNodeAndImage("remCs" + csid, showRemove, !showRemove, true);
    toggleNodeAndImage("containsSome" + csid, showSome, !showSome, true);
}

function addChangesetToIter(permaId, csid) {
    addRemoveChangesetToIter(true, permaId, csid);
}
function removeChangesetFromIter(permaId, csid) {
    addRemoveChangesetToIter(false, permaId, csid);
}
function addRemoveChangesetToIter(add, permaId, csid) {
    var busyid = "busyCs" + csid;
    var nochangeid = "";
    if (!add) {
        nochangeid = "remCs" + csid;
        toggleNodeAndImage("remCs" + csid, false, true, true);
    } else if ($("addCs" + csid).style.display == "none") {
        nochangeid = "containsSome" + csid;
        toggleNodeAndImage("containsSome" + csid, false, true, true);
    } else {
        nochangeid = "addCs" + csid;
        toggleNodeAndImage("addCs" + csid, false, true, true);
    }
    toggleNodeAndImage(busyid, true, false, true);
    var revids = changesets[csid];
    var pars = buildParams(pars, "command", (add ? "add" : "remove"));
    pars = buildParams(pars, "sourceName", "FE:" + repnameInUse);
    pars = buildParams(pars, "diff", "lastrev");
    pars = buildArrayParams(pars, "revid", revids);

    var url = fishEyePageContext + '/json/cru/' + permaId + '/editRevisionsAjax/';

    doAddRemoveCall(url, pars, busyid, nochangeid);
}

function removeAllRevs (permaId) {
    var pars = 'command=removeAll' + "&sourceName=" + "FE:"+repnameInUse;
    var url = fishEyePageContext + '/json/cru/' + permaId + '/editRevisionsAjax/';
    doAddRemoveCall(url, pars);
}

function addSearchFileRevToReview(permaId, revisionId, repName) {
    addRemoveRevisionToIter(true, permaId, revisionId, repName);
}

function removeSearchFileRevToReview(permaId, revisionId, repName) {
    addRemoveRevisionToIter(false, permaId, revisionId, repName);
}

var dirListRevs = new Array();
//this is for the file browse tab
function addFileRevisionToReview(permaId, latestRevId, sourceName) {
    var newSelectedRevId = document.forms["selectRevisionForm" + latestRevId].revId.value;
    addRemoveFileRevisionReview(true, permaId, newSelectedRevId, latestRevId, sourceName);
}

function removeFileRevisionFromReview(permaId, latestRevId, sourceName) {
    var newSelectedRevId = document.forms["selectRevisionForm" + latestRevId].revId.value;
    addRemoveFileRevisionReview(false, permaId, newSelectedRevId, latestRevId, sourceName);
}

function addRemoveFileRevisionReview(add, permaId, revid, latestRevId, sourceName, onEval) {
    var busyid = "busyRev" + latestRevId;
    var nochangeid = "";
    toggleNodeAndImage(busyid, true, false, true);
    if (add) {
        toggleNodeAndImage("addRev" + latestRevId, false, true, true);
        nochangeid = "addRev" + latestRevId;
    } else {
        toggleNodeAndImage("remRev" + latestRevId, false, true, true);
        nochangeid = "remRev" + latestRevId;
    }
    var pars = buildParams(pars, "revid", revid);
    pars = buildParams(pars, "command", (add ? "add" : "remove"));
    pars = buildParams(pars, "sourceName", (sourceName ? sourceName : "FE:" + repnameInUse));
    pars = buildParams(pars, "diff", "lastrev");
    var url = fishEyePageContext + '/json/cru/' + permaId + '/editRevisionsAjax/';

    return doAddRemoveFRCall(url, pars, busyid, nochangeid, latestRevId, onEval);
}

function doAddRemoveFRCall(url, pars, busyid, nochangeid, latestRevId, onEval) {

    var done = function(req) {
        try {
            var resp = eval("(" + req.responseText + ")");
            // take out the spinner image regardless of what the response is
            toggleNodeAndImage(busyid, false, true, true);
            toggleNodeAndImage(nochangeid, true, false, true);
            if (checkError(resp)) {
                return false;
            }
            $("cart").innerHTML = resp.msgHtml;
            //todo fix this looks wrong
            for (var i = 0; i < resp.removedRevids.length; i++) {
                dirListRevs[latestRevId] = "";
                toggleNodeAndImage("addRev" + latestRevId, true, false, true);
                toggleNodeAndImage("remRev" + latestRevId, false, true, true);
            }
            for (i = 0; i < resp.addedRevids.length; i++) {
                dirListRevs[latestRevId] = resp.addedRevids[i];
                toggleNodeAndImage("addRev" + latestRevId, false, true, true);
                toggleNodeAndImage("remRev" + latestRevId, true, false, true);
            }
            if (onEval) {
                eval(onEval);
            }
        } catch (error) {
            window.alert(error);
        }
    };

    new Ajax.Request(url, {parameters: pars, onSuccess: done}); // TODO on error
}

function updateSelectedRev(permaId, latestRevId, repName) {
    var newSelectedRevId = document.forms["selectRevisionForm" + latestRevId].revId.value;
    var onEval = "addRemoveFileRevisionReview(true, \"" + permaId + "\"," + newSelectedRevId + "," + latestRevId + ");";
    addRemoveFileRevisionReview(false, permaId, dirListRevs[latestRevId], latestRevId, repName, onEval);
}

function removeFileFromReview(permaId, revisionId, sourceName, frxOuterId) {
    var pars = buildParams(pars, "revid", revisionId);
    pars = buildParams(pars, "command", "remove");
    pars = buildParams(pars, "sourceName", sourceName);
    pars = buildParams(pars, "diff", "lastrev");
    var url = fishEyePageContext + '/json/cru/' + permaId + '/editRevisionsAjax/';

    var done = function(req) {
        try {
            var resp = eval("(" + req.responseText + ")");
            if (checkError(resp)) {
                return false;
            }
            $("cart").innerHTML = resp.msgHtml;

            for (var i = 0; i < resp.removedRevids.length; i++) {
                var removedRevid = resp.removedRevids[i];
                dirListRevs[removedRevid] = "";
                $(frxOuterId).style.display = "none";
            }
        } catch (error) {
            window.alert(error);
        }
    };

    new Ajax.Request(url, {parameters: pars, onSuccess: done});
}

/* patch file revision functions */
var patches = new Array();
var patchesInc = new Array();
var patchRevs;
var incPatchRevs;

function addAllPatch(permaId, sourceName) {
    addRemoveAllPatch(true, permaId, sourceName); //todo fix me PATCH: is a kludge
}

function removeAllPatch(permaId, sourceName) {
    addRemoveAllPatch(false, permaId, sourceName); //todo fix me PATCH: is a kludge
}

function addRemoveAllPatch(add, permaId, sourceName) {
    var patchID = sourceName.split(":")[1];
    var incRevs = patchesInc[sourceName];
    var revs = patches[sourceName]
    $("addAll" + patchID).style.display = "none";
    $("remAll" + patchID).style.display = "none";
    $("containsSome" + patchID).style.display = "none";
    $("busy" + patchID).style.display = "inline";

    var pars = buildParams(pars, "command", (add ? "add" : "remove"));
    pars = buildParams(pars, "sourceName", sourceName);
    pars = buildArrayParams(pars, "revid", patches[sourceName]);

    var url = fishEyePageContext + '/json/cru/' + permaId + '/editRevisionsAjax/';

    var onComplete = function(resp) {
        var remRev = function(revId) {
            incRevs[revId] = "";
        }
        var addRev = function(revId) {
            incRevs[revId] = revId;
        }
        updateRespMsgBusy(resp, "busy" + patchID);
        updateRemovedRevTicks(resp.removedRevids, remRev);
        updateAddedRevTicks(resp.addedRevids, addRev);
        setAddRemAll(patchID, incRevs, revs);
    }

    ajaxDo(url, pars, onComplete);
}

function setAddRemAll(patchID, incRevs, revs) {
    $("addAll" + patchID).style.display = "none";
    $("remAll" + patchID).style.display = "none";
    $("containsSome" + patchID).style.display = "none";

    var count = countSelected(incRevs);
    if (count == 0) {
        $("addAll" + patchID).style.display = "inline";
        return;
    }
    if (count < revs.length) {
        $("containsSome" + patchID).style.display = "inline";
        return;
    }
    $("remAll" + patchID).style.display = "inline";

}

function countSelected(incRevs) {
    var count = 0;
    for (var i = 0; i < incRevs.length; i++) {
        if (incRevs[i]) {
            count++;
        }
    }
    return count;
}

function updateRespMsgBusy(resp, busyId) {
    $("cart").innerHTML = resp.msgHtml;
    $(busyId).style.display = "none";
}

function updateRemovedRevTicks(removedRevids, forEachFunc) {
    for (var i = 0; i < removedRevids.length; i++) {
        var removedRevid = removedRevids[i];
        $("addRev" + removedRevid).style.display = "inline";
        $("remRev" + removedRevid).style.display = "none";
        if (forEachFunc) {
            forEachFunc(removedRevid);
        }
    }
}

function updateAddedRevTicks(addedRevids, forEachFunc) {
    for (var i = 0; i < addedRevids.length; i++) {
        var addedRevid = addedRevids[i];
        $("addRev" + addedRevid).style.display = "none";
        $("remRev" + addedRevid).style.display = "inline";
        if (forEachFunc) {
            forEachFunc(addedRevid);
        }
    }
}

function addRemoveFileRevision(add, permaId, revid, imgPostfix, sourceName) {
    var patchID = sourceName.split(":")[1];
    var incRevs = patchesInc[sourceName];
    var revs = patches[sourceName]
    var busyId = "busyRev" + imgPostfix;
    $("addRev" + imgPostfix).style.display = "none";
    $("remRev" + imgPostfix).style.display = "none";
    $(busyId).style.display = "inline";

    var pars = buildParams(pars, "revid", revid);
    pars = buildParams(pars, "command", (add ? "add" : "remove"));
    pars = buildParams(pars, "sourceName", sourceName);
    pars = buildParams(pars, "diff", "lastrev");
    var url = fishEyePageContext + "/json/cru/" + permaId + "/editRevisionsAjax/";

    var onComplete = function(resp) {
        var remRev = function(revId) {
            incRevs[revId] = "";
        }
        var addRev = function(revId) {
            incRevs[revId] = revId;
        }
        updateRespMsgBusy(resp, busyId);
        updateRemovedRevTicks(resp.removedRevids, remRev);
        updateAddedRevTicks(resp.addedRevids, addRev);
        setAddRemAll(patchID, incRevs, revs);
    }

    ajaxDo(url, pars, onComplete);
}