/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

function test() {
  /** Test for Bug 522545 **/

  waitForExplicitFinish();
  requestLongerTimeout(4);

  // This tests the following use case:
  // User opens a new tab which gets focus. The user types something into the
  // address bar, then crashes or quits.
  function test_newTabFocused() {
    let state = {
      windows: [{
        tabs: [
          { entries: [{ url: "about:mozilla", triggeringPrincipal_base64 }] },
          { entries: [], userTypedValue: "example.com", userTypedClear: 0 }
        ],
        selected: 2
      }]
    };

    waitForBrowserState(state, function() {
      let browser = gBrowser.selectedBrowser;
      is(browser.currentURI.spec, "about:blank",
         "No history entries still sets currentURI to about:blank");
      is(browser.userTypedValue, "example.com",
         "userTypedValue was correctly restored");
      ok(!browser.didStartLoadSinceLastUserTyping(),
         "We still know that no load is ongoing");
      is(gURLBar.value, "example.com",
         "Address bar's value correctly restored");

      // Change tabs to make sure address bar value gets updated.  If tab is
      // lazy, wait for SSTabRestored to ensure address bar has time to update.
      let tabToSelect = gBrowser.tabContainer.getItemAtIndex(0);
      if (tabToSelect.linkedBrowser.isConnected) {
        gBrowser.selectedTab = tabToSelect;
        is(gURLBar.value, "about:mozilla",
           "Address bar's value correctly updated");
        runNextTest();
      } else {
        gBrowser.tabContainer.addEventListener("SSTabRestored",
          function SSTabRestored(event) {
            if (event.target == tabToSelect) {
              gBrowser.tabContainer.removeEventListener("SSTabRestored", SSTabRestored, true);
                is(gURLBar.value, "about:mozilla",
                   "Address bar's value correctly updated");
              runNextTest();
            }
          }, true);
        gBrowser.selectedTab = tabToSelect;
      }
    });
  }

  // This tests the following use case:
  // User opens a new tab which gets focus. The user types something into the
  // address bar, switches back to the first tab, then crashes or quits.
  function test_newTabNotFocused() {
    let state = {
      windows: [{
        tabs: [
          { entries: [{ url: "about:mozilla", triggeringPrincipal_base64 }] },
          { entries: [], userTypedValue: "example.org", userTypedClear: 0 }
        ],
        selected: 1
      }]
    };

    waitForBrowserState(state, function() {
      let browser = gBrowser.getBrowserAtIndex(1);
      is(browser.currentURI.spec, "about:blank",
         "No history entries still sets currentURI to about:blank");
      is(browser.userTypedValue, "example.org",
         "userTypedValue was correctly restored");
      // didStartLoadSinceLastUserTyping does not exist on lazy tabs.
      if (browser.didStartLoadSinceLastUserTyping) {
        ok(!browser.didStartLoadSinceLastUserTyping(),
           "We still know that no load is ongoing");
      }
      is(gURLBar.value, "about:mozilla",
         "Address bar's value correctly restored");

      // Change tabs to make sure address bar value gets updated.  If tab is
      // lazy, wait for SSTabRestored to ensure address bar has time to update.
      let tabToSelect = gBrowser.tabContainer.getItemAtIndex(1);
      if (tabToSelect.linkedBrowser.isConnected) {
        gBrowser.selectedTab = tabToSelect;
        is(gURLBar.value, "example.org",
           "Address bar's value correctly updated");
        runNextTest();
      } else {
        gBrowser.tabContainer.addEventListener("SSTabRestored",
          function SSTabRestored(event) {
            if (event.target == tabToSelect) {
              gBrowser.tabContainer.removeEventListener("SSTabRestored", SSTabRestored, true);
                is(gURLBar.value, "example.org",
                   "Address bar's value correctly updated");
              runNextTest();
            }
          }, true);
        gBrowser.selectedTab = tabToSelect;
      }
    });
  }

  // This tests the following use case:
  // User is in a tab with session history, then types something in the
  // address bar, then crashes or quits.
  function test_existingSHEnd_noClear() {
    let state = {
      windows: [{
        tabs: [{
          entries: [{ url: "about:mozilla", triggeringPrincipal_base64},
                    { url: "about:config", triggeringPrincipal_base64 }],
          index: 2,
          userTypedValue: "example.com",
          userTypedClear: 0
        }]
      }]
    };

    waitForBrowserState(state, function() {
      let browser = gBrowser.selectedBrowser;
      is(browser.currentURI.spec, "about:config",
         "browser.currentURI set to current entry in SH");
      is(browser.userTypedValue, "example.com",
         "userTypedValue was correctly restored");
      ok(!browser.didStartLoadSinceLastUserTyping(),
         "We still know that no load is ongoing");
      is(gURLBar.value, "example.com",
         "Address bar's value correctly restored to userTypedValue");
      runNextTest();
    });
  }

  // This tests the following use case:
  // User is in a tab with session history, presses back at some point, then
  // types something in the address bar, then crashes or quits.
  function test_existingSHMiddle_noClear() {
    let state = {
      windows: [{
        tabs: [{
          entries: [{ url: "about:mozilla", triggeringPrincipal_base64 },
                    { url: "about:config", triggeringPrincipal_base64 }],
          index: 1,
          userTypedValue: "example.org",
          userTypedClear: 0
        }]
      }]
    };

    waitForBrowserState(state, function() {
      let browser = gBrowser.selectedBrowser;
      is(browser.currentURI.spec, "about:mozilla",
         "browser.currentURI set to current entry in SH");
      is(browser.userTypedValue, "example.org",
         "userTypedValue was correctly restored");
      ok(!browser.didStartLoadSinceLastUserTyping(),
         "We still know that no load is ongoing");
      is(gURLBar.value, "example.org",
         "Address bar's value correctly restored to userTypedValue");
      runNextTest();
    });
  }

  // This test simulates lots of tabs opening at once and then quitting/crashing.
  function test_getBrowserState_lotsOfTabsOpening() {
    gBrowser.stop();

    let uris = [];
    for (let i = 0; i < 25; i++)
      uris.push("http://example.com/" + i);

    // We're waiting for the first location change, which should indicate
    // one of the tabs has loaded and the others haven't. So one should
    // be in a non-userTypedValue case, while others should still have
    // userTypedValue and userTypedClear set.
    gBrowser.addTabsProgressListener({
      onLocationChange(aBrowser) {
        if (uris.indexOf(aBrowser.currentURI.spec) > -1) {
          gBrowser.removeTabsProgressListener(this);
          firstLocationChange();
        }
      }
    });

    function firstLocationChange() {
      let state = JSON.parse(ss.getBrowserState());
      let hasUTV = state.windows[0].tabs.some(function(aTab) {
        return aTab.userTypedValue && aTab.userTypedClear && !aTab.entries.length;
      });

      ok(hasUTV, "At least one tab has a userTypedValue with userTypedClear with no loaded URL");

      BrowserTestUtils.waitForMessage(gBrowser.selectedBrowser.messageManager, "SessionStore:update").then(firstLoad);
    }

    function firstLoad() {
      let state = JSON.parse(ss.getTabState(gBrowser.selectedTab));
      let hasSH = !("userTypedValue" in state) && state.entries[0].url;
      ok(hasSH, "The selected tab has its entry in SH");

      runNextTest();
    }

    gBrowser.loadTabs(uris);
  }

  // This simulates setting a userTypedValue and ensures that just typing in the
  // URL bar doesn't set userTypedClear as well.
  function test_getBrowserState_userTypedValue() {
    let state = {
      windows: [{
        tabs: [{ entries: [] }]
      }]
    };

    waitForBrowserState(state, function() {
      let browser = gBrowser.selectedBrowser;
      // Make sure this tab isn't loading and state is clear before we test.
      is(browser.userTypedValue, null, "userTypedValue is empty to start");
      ok(!browser.didStartLoadSinceLastUserTyping(),
         "Initially, no load should be ongoing");

      let inputText = "example.org";
      gURLBar.focus();
      gURLBar.value = inputText.slice(0, -1);
      EventUtils.synthesizeKey(inputText.slice(-1), {});

      executeSoon(function() {
        is(browser.userTypedValue, "example.org",
           "userTypedValue was set when changing URLBar value");
        ok(!browser.didStartLoadSinceLastUserTyping(),
           "No load started since changing URLBar value");

        // Now make sure ss gets these values too
        let newState = JSON.parse(ss.getBrowserState());
        is(newState.windows[0].tabs[0].userTypedValue, "example.org",
           "sessionstore got correct userTypedValue");
        is(newState.windows[0].tabs[0].userTypedClear, 0,
           "sessionstore got correct userTypedClear");
        runNextTest();
      });
    });
  }

  // test_getBrowserState_lotsOfTabsOpening tested userTypedClear in a few cases,
  // but not necessarily any that had legitimate URIs in the state of loading
  // (eg, "http://example.com"), so this test will cover that case.
  function test_userTypedClearLoadURI() {
    let state = {
      windows: [{
        tabs: [
          { entries: [], userTypedValue: "http://example.com", userTypedClear: 2 }
        ]
      }]
    };

    waitForBrowserState(state, function() {
      let browser = gBrowser.selectedBrowser;
      is(browser.currentURI.spec, "http://example.com/",
         "userTypedClear=2 caused userTypedValue to be loaded");
      is(browser.userTypedValue, null,
         "userTypedValue was null after loading a URI");
      ok(!browser.didStartLoadSinceLastUserTyping(),
         "We should have reset the load state when the tab loaded");
      is(gURLBar.textValue, gURLBar.trimValue("http://example.com/"),
         "Address bar's value set after loading URI");
      runNextTest();
    });
  }


  let tests = [test_newTabFocused, test_newTabNotFocused,
               test_existingSHEnd_noClear, test_existingSHMiddle_noClear,
               test_getBrowserState_lotsOfTabsOpening,
               test_getBrowserState_userTypedValue, test_userTypedClearLoadURI];
  let originalState = JSON.parse(ss.getBrowserState());
  let state = {
    windows: [{
      tabs: [{ entries: [{ url: "about:blank", triggeringPrincipal_base64 }] }]
    }]
  };
  function runNextTest() {
    if (tests.length) {
      waitForBrowserState(state, function() {
        gBrowser.selectedBrowser.userTypedValue = null;
        URLBarSetURI();
        (tests.shift())();
      });
    } else {
      waitForBrowserState(originalState, function() {
        gBrowser.selectedBrowser.userTypedValue = null;
        URLBarSetURI();
        finish();
      });
    }
  }

  // Run the tests!
  runNextTest();
}
