/* 
 Copyright 2005-2010 Xmarks Inc.
 
 foxmarks-setup.js: implements behavior for the Xmarks Setup Wizard.
   
 */


var gError;
var gIsEmpty;
var gHasProfiles;
var gCanSyncPasswords;
var gSyncPasswords;
var pProfileNames;
var gHelpUrl;
var gPasswordsNeedUpload = false;
var gForgotPIN = false;
var gResetPIN;
var gConfirmResetPIN;

var gWizardMode = "normal";
var gWizardForgotPassword = false;

var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;

// List of sequenceFrame objects, where the position indicates the
// current item being executed this sequence.

var sequenceFrames = [];

var sequences = { 
    'normal': ['startup', 'passwords', 'tabs', 'history', 'profiles', 'sync'],

    'startup': ['transition', function() { return gError ? 
        ['errorPage', 'startup'] : null }],

    'profiles': function() { 
        if (gHasProfiles && !Xmarks.gSettings.haveSynced) 
            return 'selectProfile';
    },

    'passwords': function() {
        if (gCanSyncPasswords) {
            return ['syncPasswords', function() {
                Xmarks.LogWrite("Seq gSyncPasswords is " + gSyncPasswords);
                if (gSyncPasswords) {
                    return 'getpin';
                }
            }];
        }
    },

    'getpin': ['_passwordTransition', function() {
        if (gError) {
            return ['errorPage', 'getpin'];
        } else {
            return gPasswordsNeedUpload ? 'pinnew' : 'pinold';
        }
    }],

    'pinnew': ['pinNew', 'newpinVerified'],

    'pinold': ['pinOld', function() {
        if (gForgotPIN) {
            return 'forgotpin';
        } else {
            return ['pinVerify', 'pinVerified']
        }
    }],

    'forgotpin': ['forgotPIN', function() { 
        if (gResetPIN) {
            return 'pinreset';
        }
    }],

    'pinreset': ['resetPIN', function() { 
        if (gConfirmResetPIN) {
            return ['pinNew', 'resetpinVerified'];
        }
    }],

    'tabs': 'tabSync',

    'history': 'historySync',

    'sync': [function() {
        if (!gIsEmpty) {
            return 'selectSyncOption';
        }
    }, function() { 
        if (SetupIsMerging()) {
            return 'mergeOption';
        }
    }, 'execute', 'success']
};
    
function SequenceNext() {
    var frame = sequenceFrames[sequenceFrames.length-1];
    if (frame.position >= frame.sequence.length-1) {
        sequenceFrames.pop();
        if (sequenceFrames.length) {
            return SequenceNext();
        } else {
            // Done!
            return null;
        }
    }
    frame.position += 1
    return SequenceGetItem(frame.sequence[frame.position], false);
}

function SequencePrev() {
    var frame = sequenceFrames[sequenceFrames.length-1];
    if (frame.position <= 0) {
        if (sequenceFrames.length) {
            sequenceFrames.pop();
            return SequencePrev();
        } else {
            Xmarks.LogWrite("WizardError: Tried to move back before start");
            return;
        }
    }
    frame.position -= 1;
    return SequenceGetItem(frame.sequence[frame.position], true);
}

function SequenceGetItem(value, reverse) {
    if (typeof(value) == 'function') {
        return SequenceStart("function", [value()], reverse);
    } else if (value && typeof(value) == 'object') {
        // Assume list.
        return SequenceStart("list", value, reverse);
    } else if (typeof(value) == 'string') {
        if (sequences[value]) {
            return SequenceStart(value, sequences[value], reverse);
        } else {
            return value;
        }
    } else if (!value) {
        return reverse ? SequencePrev() : SequenceNext();
    } else {
    }
}

function SequenceIsLastItem() {
    // We're currently on the last item iff we're on the last item
    // within every frame. Note that we can't (yet) predict the future;
    // if the only item remaining on the list is a function that will
    // eventually evaluate to a no-op, we'll still report here that we're
    // not yet done.
    for (var i = sequenceFrames.length -1; i >= 0; --i) {
        var frame = sequenceFrames[i];
        if (frame.position < frame.sequence.length -1) {
            return false;
        }
    }

    return true;
}

function SequenceStart(name, seq, reverse ) {
    if (typeof(seq) != "object") {
        seq = [seq];
    }
    sequenceFrames.push( { 
            name: name, 
            sequence: seq, 
            position: reverse ? seq.length : -1});
    return reverse ? SequencePrev() : SequenceNext();
}

function SequenceEnd(name, reverse) {
    for (var i = sequenceFrames.length - 1; i >= 0; --i) {
        var frame = sequenceFrames[i];
        if (frame.name == name) {
            sequenceFrames.splice(i, sequenceFrames.length - i);
            return reverse ? SequencePrev() : SequenceEnd();
        }
        Xmarks.LogWrite("Wizard: couldn't pop stack to " + name);
    }
}

function OnWizardCancel() {
    if(gWizardMode == "normal"){
        var ps = Cc["@mozilla.org/embedcomp/prompt-service;1"]
            .getService(Ci.nsIPromptService);

        var checkResult = {};
        checkResult.value = Xmarks.gSettings.wizardSuppress;
        var sb = Xmarks.Bundle();

        var ret = ps.confirmCheck(window, 
                sb.GetStringFromName("title.cancelsetup"),
                sb.GetStringFromName("msg.cancelsetup"),
                sb.GetStringFromName("msg.nowizard"),
                checkResult);

        Xmarks.gSettings.wizardSuppress = checkResult.value;
        Xmarks.gSettings.majorVersion = 3;

        return ret;
    }
    else
        return true;
}

var gLoaded;

// Oh, poor xul wizard: we've hacked you to bits. Instead of calling
// wizard.advance, we split into two functions: the first sends all the
// notifications of the page advancing, including calling the onpageadvanced
// handlers for the current page. Once that's all done, we decide on our own
// which page we're heading toward, then call the second routine below to
// enact that. These two routines supplant entirely the built-in advance method.

function BeforeWizardAdvance() {
    if (!this.canAdvance)
        return false; 

    if (this.currentPage && !this._fireEvent(this.currentPage, "pagehide"))
        return false;

    if (this.currentPage && !this._fireEvent(this.currentPage, "pageadvanced"))
        return false;

    if (this.onLastPage) {
        if (this._fireEvent(this, "wizardfinish"))
            window.setTimeout(function() {window.close();}, 1);
    } else {
        if (!this._fireEvent(this, "wizardnext"))
            return false; 
    }
    return true;
}

function AfterWizardAdvance(aPageId) {
    var page;
    if (aPageId)
        page = this.getPageById(aPageId);
    else {
        if (this.currentPage) {
            if (this._accessMethod == "random")
                page = this.getPageById(this.currentPage.next);
            else
                page = this.wizardPages[this.currentPage.pageIndex+1];
        } else
        page = this.wizardPages[0];
    }

    if (page) {
        this._pageStack.push(page);
        this.setAttribute("pagestep", this._pageStack.length);

        this.currentPage = page;
    }
}

function WizardRewind() {
    if (!this.canRewind)
        return 0;

    if (this.currentPage && !this._fireEvent(this.currentPage, "pagehide"))
        return 0;

    if (this.currentPage && !this._fireEvent(this.currentPage, "pagerewound"))
        return 0;

    if (!this._fireEvent(this, "wizardback"))
        return 0;


    var pageid;
    // When rewinding, rewind past pages that start with "_".
    for (var count = 1; this._pageStack.length; ++count) {
        this._pageStack.pop();
        pageid = this._pageStack[this._pageStack.length-1].
            getAttribute("pageid");
        if (!pageid || pageid[0] != '_')
            break;
    }

    this.currentPage = this._pageStack[this._pageStack.length-1];
    this.setAttribute("pagestep", this._pageStack.length);
    return count;
}

function OnWizardLoad(){
    // Protect against this running multiple times.
    if (gLoaded) return;
    gLoaded = true;

    var wizard = document.documentElement;
    var sb = Xmarks.Bundle();
    if(window.arguments[1] !== undefined)
        gWizardMode = window.arguments[1];
    else
        gWizardMode = "normal";

    // Hook the our sequence engine into the wizard
    wizard.advance = function() {
        if (!BeforeWizardAdvance.apply(wizard))
            return;
        var nextPageId = SequenceNext();
        if (nextPageId)
            AfterWizardAdvance.apply(wizard, [nextPageId]);
    }

    wizard.rewind = function() {
        var pagesBack = WizardRewind.apply(wizard);
        var prevPageId = null;
        while (pagesBack--)
            prevPageId = SequencePrev();
    }

    wizard.__defineGetter__("onLastPage", function() { 
            var isLast = SequenceIsLastItem(); 
            return isLast;
    });

    if(gWizardMode == "getpin"){
        wizard.title = sb.GetStringFromName("wizard.newtitle");
    }
    
    // ... and then launch the appropriate sequence
    sequenceFrames = []
    wizard.goTo(SequenceStart(gWizardMode, sequences[gWizardMode]));
}

function OnErrorPageShow() {
    var wizard = document.documentElement;
    document.getElementById("errormsg").value = gError.msg;
    var errmsg = gError.msg.replace(/ /g, "_");
    gHelpUrl = Xmarks.Bundle().formatStringFromName("url.error", 
        [errmsg], 1);
    wizard.canAdvance = true;
}


function OnTransitionPageShow() {
    /*

    We've just gained control back from the web-based setup wizard.
    1) Confirm that we can log in.
    2) Determine whether there are profiles.
    3) Determine whether there are server-side bookmarks.

    */
    Xmarks.LogWrite("Entered OnTransitionPageShow()");

    gError = null;

    // There is a timing issue; sometimes this doesn't get called first
    OnWizardLoad();
    if(gWizardMode != "normal")
        return;

    var spinner = document.getElementById("spinner");
    var status = document.getElementById("statusLabel");
    var wizard = document.documentElement;
    wizard.canAdvance = false;
    document.getElementById("profileMenuList").value = 
        String(Xmarks.gSettings.viewId);

    Xmarks.FetchAccountStatus("bookmarks", status, spinner, function(response) {
        wizard.canAdvance = true;
        if (response.status != 0) {
            gError = response;
            wizard.advance();
            return;
        }

        gIsEmpty = response.isreset;
        gCanSyncPasswords = "@mozilla.org/login-manager;1" in Cc;
        Xmarks.LogWrite("gCanSyncPasswords is " + gCanSyncPasswords);

        Xmarks.FetchProfileNames(status, spinner,
            document.getElementById("profileMenuPopup"), function(response) {

            if (response.status != 0) {
                gError = response;
                return;
            }

            gHasProfiles = (response.count > 0);
            gProfileNames = response.profiles;
            // TODO: what should we do with this haveSynced
            wizard.canAdvance = true;
            if(gWizardMode == "normal") {
                Xmarks.LogWrite("Calling wizard.advance()");
                wizard.advance();
            }
        });
    });
}


function ForgotPIN(){
    var wizard = document.documentElement;
    gForgotPIN = true;
    wizard.advance();
}

function ForgotPINAdvance(){
    var wizard = document.documentElement;
    gResetPIN  = document.getElementById("forgotpinradio").selectedItem.
        value == "reset";
    return true;
}

function ResetPINLoad(){
}

function SyncPasswordsLoad(){
    var wizard = document.documentElement;
    wizard.canRewind = false;
}

function ResetPINAdvance(){
    var wizard = document.documentElement;
    gConfirmResetPIN =
        document.getElementById("resetpinradio").selectedItem.value == "1";
    if(gConfirmResetPIN){
        Xmarks.gSettings.setMustUpload("passwords", true);
        gWizardForgotPassword = true;
        wizard.currentPage.next = "pinNew";
    } else {
        if(gWizardMode == "normal"){
            Xmarks.gSettings.setSyncEnabled("passwords", false);
            wizard.currentPage.next = gIsEmpty ? 
                "execute" : "selectSyncOption"; 
        }
        else {
            wizard.cancel();
        }
    }
    return true;

}
function SyncPasswordAdvance() {
    var wizard = document.documentElement;
    gSyncPasswords = document.getElementById("syncpasswordradio").
        selectedItem.value == "1";

    if (!gSyncPasswords) {
        Xmarks.gSettings.setSyncEnabled("passwords", false);
    }

    Xmarks.LogWrite("gSyncPasswords is " + gSyncPasswords);
    return true;
}

function OnPasswordTransitionPageShow() {
    var spinner = document.getElementById("pin_spinner");
    var status = document.getElementById("pin_statusLabel");
    var wizard = document.documentElement;
    wizard.canAdvance = false;

    Xmarks.FetchAccountExtStatus("passwords", status, spinner,
        function(response){ 
            if (response.status != 0) {
                gError = response;
                return;
            }

            gPasswordsNeedUpload = response.isreset || response.ispurged;
            wizard.canAdvance = true;
            wizard.advance();
        });
}

function OldPinLoad(){
    gForgotPIN = false;
    if(gWizardMode == "askforPIN"){
        var wizard = document.documentElement;
        wizard.canRewind = false;
    }
}
function NewOrResetPassword(){
    var wizard = document.documentElement;
    var currpin = Xmarks.gSettings.pinNoPrompt;
    if(currpin){
        wizard.currentPage.label =
            Xmarks.Bundle().GetStringFromName("wizard.newpintitle");
        wizard.currentPage.next = "resetpinVerified";
    } else if(gWizardMode == "askforPIN"){
        wizard.canRewind = false;
    }
}

function NewPasswordAdvance(){
    var wizard = document.documentElement;
    var pin = document.getElementById("newpin").value;
    var pin2 = document.getElementById("newpin2").value;

    if(!pin || pin.length < 4 || pin.length > 255){
        Xmarks.Alert(Xmarks.Bundle().GetStringFromName("error.pinWrongSize"));
        return false;
    }

    if(!pin2 || pin != pin2){
        Xmarks.Alert(Xmarks.Bundle().GetStringFromName("error.pinNoMatch"));
        return false;
    }

    if(pin == Xmarks.gSettings.passwordNoPrompt){
        Xmarks.Alert(Xmarks.Bundle().
            GetStringFromName("error.pinEqualsPassword"));
        return false;
    }

    Xmarks.gSettings.pin = pin;
    Xmarks.gSettings.rememberPin = 
        document.getElementById("rememberPin").checked;

    Xmarks.gSettings.setSyncEnabled("passwords", true);
    if(gPasswordsNeedUpload){
        Xmarks.gSettings.setMustUpload("passwords", true);
    }
    gWizardForgotPassword = false;       
    return true;
}

function OldPinAdvance(){
    Xmarks.gSettings.rememberPin = document.getElementById("rememberPinOld").
        checked;
    return true;
}
function VerifyPIN(){
    var spinner = document.getElementById("vpin_spinner");
    var status = document.getElementById("vpin_statusLabel");
    var wizard = document.documentElement;
    var pin = document.getElementById("oldpin").value;
    wizard.canAdvance = false;

    if(!pin || pin.length < 4 || pin.length > 255){
        Xmarks.Alert(Xmarks.Bundle().GetStringFromName("error.pinWrongSize"));
        wizard.canAdvance = true;
        wizard.rewind();
        return;
    }

    Xmarks.VerifyPINStatus(pin, status, spinner,function(response){ 
        if (response.status != 0) {
            Xmarks.Alert(Xmarks.Bundle().GetStringFromName("error.pinInvalid"));
            wizard.canAdvance = true;
            wizard.rewind();
            return;
        }

        Xmarks.gSettings.pin = pin;

        var lm = Date.now();
        if (!this.lastModified || lm > this.lastModified) {
            this.lastModified = lm;
            var os = Cc["@mozilla.org/observer-service;1"]
                .getService(Ci.nsIObserverService);
            os.notifyObservers(null, "foxmarks-datasourcechanged", 
                lm + ";passwords");
        }

        wizard.canAdvance = true;
        wizard.advance();
    });
}

function PinVerifiedAdvance(){
    Xmarks.gSettings.setSyncEnabled("passwords", true);
    if(gPasswordsNeedUpload){
        Xmarks.gSettings.setMustUpload("passwords", true);
    }
    if(gWizardMode != "normal")
        window.arguments[2].doSync = true;
    return true;
}

function NewPinVerifiedAdvance(){
    if(gWizardMode != "normal")
        window.arguments[2].doSync = true;
    return true;
}

function tabSyncShow() {
    var check = document.getElementById("tabSyncEnabled");
    var div = document.getElementById("tabSyncDiv");
    var text = document.getElementById("tabSyncClientName");

    check.checked = Xmarks.gSettings.isSyncEnabled("tabs");
    text.value = Xmarks.gSettings.clientName;
    tabSyncHideShow();
}

function tabSyncAdvanced() {
    var check = document.getElementById("tabSyncEnabled");
    var text = document.getElementById("tabSyncClientName");

    Xmarks.gSettings.setSyncEnabled("tabs",check.checked);
    if (check.checked) {
        Xmarks.gSettings.clientName = text.value;
    }    
}

function tabSyncHideShow(focus) {
    var checked = document.getElementById("tabSyncEnabled").checked;
    document.getElementById("tabSyncDiv").hidden = !checked;
    if (checked && focus) {
        var text = document.getElementById("tabSyncClientName");
        text.select();
        text.focus();
    }
}

function historySyncShow() {
    var check = document.getElementById("historySyncEnabled");
    var div = document.getElementById("historySyncDiv");
    var text = document.getElementById("historySyncClientName");

    check.checked = Xmarks.gSettings.isSyncEnabled("history");
    text.value = Xmarks.gSettings.clientName;
    historySyncHideShow();
}

function historySyncAdvanced() {
    var check = document.getElementById("historySyncEnabled");
    var text = document.getElementById("historySyncClientName");

    Xmarks.gSettings.setSyncEnabled("history", check.checked);
    if (check.checked) {
        Xmarks.gSettings.clientName = text.value;
    }    
}

function historySyncHideShow(focus) {
    var checked = document.getElementById("historySyncEnabled").checked;
    document.getElementById("historySyncDiv").hidden = !checked;
    if (checked && focus) {
        var text = document.getElementById("historySyncClientName");
        text.select();
        text.focus();
    }
}

function SetProfileValue() {
    Xmarks.LogWrite("Setting profile value...");
    Xmarks.gSettings.viewId = document.getElementById("profileMenuList").value;
    Xmarks.gSettings.viewName = 
        document.getElementById("profileMenuList").label;
    Xmarks.LogWrite("Profle value is now " + Xmarks.gSettings.viewId);
}

function FoxmarksSetupHelp() {
    if (gHelpUrl) {
        Xmarks.OpenInNewWindow(gHelpUrl);
    }
}

function SetupIsMerging() {
    return !gIsEmpty && 
        document.getElementById("localOrRemote").selectedItem.value == "merge";
}

function SetupShowExecutePage() {
    var op;
    var a = document.getElementById("localOrRemote").selectedItem.value;
    var b = document.getElementById("mergeStart").selectedItem.value;
    var desc = document.getElementById("readydesc");

    if(Xmarks.gSettings.isSyncEnabled("passwords"))
        desc.setAttribute("value", Xmarks.Bundle().
        GetStringFromName("label.syncinitial"));

    if (gIsEmpty) {
        op = "msg.upload2";
    } else {
        if (a == "local") {
            op = "msg.upload2";
        } else if (a == "remote") {
            op = "msg.download2";
        } else {
            if (b == "local") {
                op = "msg.mergelocal";
            } else {
                op = "msg.mergeremote";
            }
        }
    }
    var datatype = "";
    
    if(Xmarks.gSettings.isSyncEnabled("bookmarks") &&
            Xmarks.gSettings.isSyncEnabled("passwords")){
        datatype = Xmarks.Bundle().GetStringFromName("msg.merge.alldata");
    } else if(Xmarks.gSettings.isSyncEnabled("bookmarks")){
        datatype = Xmarks.Bundle().GetStringFromName("msg.merge.bookmarks");
    } else {
        datatype = Xmarks.Bundle().GetStringFromName("msg.merge.passwords");
    }
    document.getElementById("operation").value =
        Xmarks.Bundle().formatStringFromName(op,[datatype],1);
    var warning = document.getElementById("warning");
    if (!gIsEmpty && a != "merge") {
        if(warning.childNodes.length > 0){
            warning.removeChild(warning.firstChild);
        }

        var wtext = document.createTextNode(
             Xmarks.Bundle().formatStringFromName(op + ".warning",
                [datatype], 1)
        );
        warning.appendChild(wtext)
        warning.hidden = false;
    } else {
        warning.hidden = true
    }
    var profileMsg = document.getElementById("profileMsg");
    if (gHasProfiles && Xmarks.gSettings.viewId) {
        profileMsg.value = Xmarks.Bundle().formatStringFromName(
            "msg.profilemsg", [gProfileNames[String(Xmarks.gSettings.viewId)]],
            1);
        profileMsg.hidden = false;
    } else {
        profileMsg.hidden = true;
    }
}

function SetupPerformSync() {
    var retval = {}
    var args = {};

    var a = document.getElementById("localOrRemote").selectedItem.value;
    var b = document.getElementById("mergeStart").selectedItem.value;

    args.merge = SetupIsMerging();
    args.remoteIsMaster = gIsEmpty ? false :
        (args.merge ? (b == "remote") : (a == "remote"));

    SetupPerformAction("initialSync", retval, args);

    if (!retval.status) {
        return true;
    } else {
        Xmarks.Alert(Xmarks.Bundle().formatStringFromName("msg.syncfailed",
                [retval.msg], 1));
    }

    return false;
}

function SetupPerformAction(action, retval, args) {
    var win = window.
            openDialog("chrome://foxmarks/content/foxmarks-progress.xul",
            "_blank", "chrome,dialog,modal,centerscreen", action, retval, args);

    if (retval.helpurl) {
        openDialog("chrome://browser/content/browser.xul", "_blank",
            "chrome,all,dialog=no", retval.helpurl);
        retval.status = -1;
        retval.msg = Xmarks.Bundle().GetStringFromname("msg.cancelled");
    }

    return;
}

function SetupOnWizardFinish() {
    Xmarks.gSettings.majorVersion = 3;
    if (gWizardMode == 'normal') {
        Cu.import("resource://xmarks/service.jsm", Xmarks);
        var fms = Xmarks.fms;
        fms.launchSuccessPage();
    }
    return true;
}

function OnPageShow(pageId, blur) {
    var attrs = [];
    attrs.push("app="       + "jezebel");
    attrs.push("mid="       + Xmarks.gSettings.machineId);
    attrs.push("sess="      + Xmarks.gSettings.sessionID);
    attrs.push("page="      + pageId);
    attrs.push("username="  + Xmarks.gSettings.username);
    attrs.push("no_cache="  + Date.now().toString(36));
    attrs.push("manual="    + window.arguments[0]);

    var query = attrs.join("&");
    var img = document.getElementById(pageId + "Ping");
    img.src = Xmarks.gSettings.httpProtocol + 
        "tr.xmarks.com/tracking/impressions.gif?" + query;

    if (blur) {
        document.getElementById(blur).blur();
    }
}

function FoxmarksMoreSecurityInfo(){
    window.openDialog(
        "chrome://foxmarks/content/foxmarks-moresecurityinfo.xul",
        "_blank",
        "chrome,dialog,modal,centerscreen"
    );
}
