<!DOCTYPE html>
<!--
Copyright (c) 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/base.html">
<script>
'use strict';

/**
 * @fileoverview Provides the Settings object.
 */
tr.exportTo('tr.b', function() {
  /**
   * Settings is a simple wrapper around local storage, to make it easier
   * to test classes that have settings.
   *
   * May be called as new tr.b.Settings() or simply tr.b.Settings()
   * @constructor
   */
  function Settings() {
    return Settings;
  };

  if (tr.b.unittest && tr.b.unittest.TestRunner) {
    tr.b.unittest.TestRunner.addEventListener(
        'tr-unittest-will-run',
        function() {
          if (tr.isHeadless)
            Settings.setAlternativeStorageInstance(new HeadlessStorage());
          else
            Settings.setAlternativeStorageInstance(global.sessionStorage);
        });
  }

  function SessionSettings() {
    return SessionSettings;
  }

  function AddStaticStorageFunctionsToClass_(input_class, storage) {
    input_class.storage_ = storage;

    /**
     * Get the setting with the given name.
     *
     * @param {string} key The name of the setting.
     * @param {string=} opt_default The default value to return if not set.
     * @param {string=} opt_namespace If set, the setting name will be prefixed
     * with this namespace, e.g. "categories.settingName". This is useful for
     * a set of related settings.
     */
    input_class.get = function(key, opt_default, opt_namespace) {
      key = input_class.namespace_(key, opt_namespace);
      var rawVal = input_class.storage_.getItem(key);
      if (rawVal === null || rawVal === undefined)
        return opt_default;

      // Old settings versions used to stringify objects instead of putting them
      // into JSON. If those are encountered, parse will fail. In that case,
      // "upgrade" the setting to the default value.
      try {
        return JSON.parse(rawVal).value;
      } catch (e) {
        input_class.storage_.removeItem(key);
        return opt_default;
      }
    };

    /**
     * Set the setting with the given name to the given value.
     *
     * @param {string} key The name of the setting.
     * @param {string} value The value of the setting.
     * @param {string=} opt_namespace If set, the setting name will be prefixed
     * with this namespace, e.g. "categories.settingName". This is useful for
     * a set of related settings.
     */
    input_class.set = function(key, value, opt_namespace) {
      if (value === undefined)
        throw new Error('Settings.set: value must not be undefined');
      var v = JSON.stringify({value: value});
      input_class.storage_.setItem(
          input_class.namespace_(key, opt_namespace), v);
    };

    /**
     * Return a list of all the keys, or all the keys in the given namespace
     * if one is provided.
     *
     * @param {string=} opt_namespace If set, only return settings which
     * begin with this prefix.
     */
    input_class.keys = function(opt_namespace) {
      var result = [];
      opt_namespace = opt_namespace || '';
      for (var i = 0; i < input_class.storage_.length; i++) {
        var key = input_class.storage_.key(i);
        if (input_class.isnamespaced_(key, opt_namespace))
          result.push(input_class.unnamespace_(key, opt_namespace));
      }
      return result;
    };

    input_class.isnamespaced_ = function(key, opt_namespace) {
      return key.indexOf(input_class.normalize_(opt_namespace)) == 0;
    };

    input_class.namespace_ = function(key, opt_namespace) {
      return input_class.normalize_(opt_namespace) + key;
    };

    input_class.unnamespace_ = function(key, opt_namespace) {
      return key.replace(input_class.normalize_(opt_namespace), '');
    };

    /**
     * All settings are prefixed with a global namespace to avoid collisions.
     * input_class may also be namespaced with an additional prefix passed into
     * the get, set, and keys methods in order to group related settings.
     * This method makes sure the two namespaces are always set properly.
     */
    input_class.normalize_ = function(opt_namespace) {
      return input_class.NAMESPACE + (opt_namespace ? opt_namespace + '.' : '');
    };

    input_class.setAlternativeStorageInstance = function(instance) {
      input_class.storage_ = instance;
    };

    input_class.getAlternativeStorageInstance = function() {
      if (!tr.isHeadless && input_class.storage_ === localStorage)
        return undefined;
      return input_class.storage_;
    };

    input_class.NAMESPACE = 'trace-viewer';
  };

  function HeadlessStorage() {
    this.length = 0;
    this.hasItem_ = {};
    this.items_ = {};
    this.itemsAsArray_ = undefined;
  }
  HeadlessStorage.prototype = {
    key: function(index) {
      return this.itemsAsArray[index];
    },

    get itemsAsArray() {
      if (this.itemsAsArray_ !== undefined)
        return this.itemsAsArray_;
      var itemsAsArray = [];
      for (var k in this.items_)
        itemsAsArray.push(k);
      this.itemsAsArray_ = itemsAsArray;
      return this.itemsAsArray_;
    },

    getItem: function(key) {
      if (!this.hasItem_[key])
        return null;
      return this.items_[key];
    },

    removeItem: function(key) {
      if (!this.hasItem_[key])
        return;
      var value = this.items_[key];
      delete this.hasItem_[key];
      delete this.items_[key];
      this.length--;
      this.itemsAsArray_ = undefined;
      return value;
    },

    setItem: function(key, value) {
      if (this.hasItem_[key]) {
        this.items_[key] = value;
        return;
      }
      this.items_[key] = value;
      this.hasItem_[key] = true;
      this.length++;
      this.itemsAsArray_ = undefined;
      return value;
    }
  };

  if (tr.isHeadless) {
    AddStaticStorageFunctionsToClass_(Settings, new HeadlessStorage());
    AddStaticStorageFunctionsToClass_(SessionSettings, new HeadlessStorage());
  } else {
    AddStaticStorageFunctionsToClass_(Settings, localStorage);
    AddStaticStorageFunctionsToClass_(SessionSettings, sessionStorage);
  }

  return {
    Settings: Settings,
    SessionSettings: SessionSettings
  };
});
</script>
