// Copyright (c) 2012 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.

/**
 * HSTS is HTTPS Strict Transport Security: a way for sites to elect to always
 * use HTTPS. See http://dev.chromium.org/sts
 *
 * This UI allows a user to query and update the browser's list of HSTS domains.
 * It also allows users to query and update the browser's list of public key
 * pins.
 */

var HSTSView = (function() {
  'use strict';

  // We inherit from DivView.
  var superClass = DivView;

  /**
   * @constructor
   */
  function HSTSView() {
    assertFirstConstructorCall(HSTSView);

    // Call superclass's constructor.
    superClass.call(this, HSTSView.MAIN_BOX_ID);

    this.addInput_ = $(HSTSView.ADD_INPUT_ID);
    this.addStsCheck_ = $(HSTSView.ADD_STS_CHECK_ID);
    this.addPkpCheck_ = $(HSTSView.ADD_PKP_CHECK_ID);
    this.addPins_ = $(HSTSView.ADD_PINS_ID);
    this.deleteInput_ = $(HSTSView.DELETE_INPUT_ID);
    this.queryInput_ = $(HSTSView.QUERY_INPUT_ID);
    this.queryOutputDiv_ = $(HSTSView.QUERY_OUTPUT_DIV_ID);

    var form = $(HSTSView.ADD_FORM_ID);
    form.addEventListener('submit', this.onSubmitAdd_.bind(this), false);

    form = $(HSTSView.DELETE_FORM_ID);
    form.addEventListener('submit', this.onSubmitDelete_.bind(this), false);

    form = $(HSTSView.QUERY_FORM_ID);
    form.addEventListener('submit', this.onSubmitQuery_.bind(this), false);

    g_browser.addHSTSObserver(this);
  }

  HSTSView.TAB_ID = 'tab-handle-hsts';
  HSTSView.TAB_NAME = 'HSTS';
  HSTSView.TAB_HASH = '#hsts';

  // IDs for special HTML elements in hsts_view.html
  HSTSView.MAIN_BOX_ID = 'hsts-view-tab-content';
  HSTSView.ADD_INPUT_ID = 'hsts-view-add-input';
  HSTSView.ADD_STS_CHECK_ID = 'hsts-view-check-sts-input';
  HSTSView.ADD_PKP_CHECK_ID = 'hsts-view-check-pkp-input';
  HSTSView.ADD_PINS_ID = 'hsts-view-add-pins';
  HSTSView.ADD_FORM_ID = 'hsts-view-add-form';
  HSTSView.ADD_SUBMIT_ID = 'hsts-view-add-submit';
  HSTSView.DELETE_INPUT_ID = 'hsts-view-delete-input';
  HSTSView.DELETE_FORM_ID = 'hsts-view-delete-form';
  HSTSView.DELETE_SUBMIT_ID = 'hsts-view-delete-submit';
  HSTSView.QUERY_INPUT_ID = 'hsts-view-query-input';
  HSTSView.QUERY_OUTPUT_DIV_ID = 'hsts-view-query-output';
  HSTSView.QUERY_FORM_ID = 'hsts-view-query-form';
  HSTSView.QUERY_SUBMIT_ID = 'hsts-view-query-submit';

  cr.addSingletonGetter(HSTSView);

  HSTSView.prototype = {
    // Inherit the superclass's methods.
    __proto__: superClass.prototype,

    onSubmitAdd_: function(event) {
      g_browser.sendHSTSAdd(this.addInput_.value,
                            this.addStsCheck_.checked,
                            this.addPkpCheck_.checked,
                            this.addPins_.value);
      g_browser.sendHSTSQuery(this.addInput_.value);
      this.queryInput_.value = this.addInput_.value;
      this.addStsCheck_.checked = false;
      this.addPkpCheck_.checked = false;
      this.addInput_.value = '';
      this.addPins_.value = '';
      event.preventDefault();
    },

    onSubmitDelete_: function(event) {
      g_browser.sendHSTSDelete(this.deleteInput_.value);
      this.deleteInput_.value = '';
      event.preventDefault();
    },

    onSubmitQuery_: function(event) {
      g_browser.sendHSTSQuery(this.queryInput_.value);
      event.preventDefault();
    },

    onHSTSQueryResult: function(result) {
      if (result.error != undefined) {
        this.queryOutputDiv_.innerHTML = '';
        var s = addNode(this.queryOutputDiv_, 'span');
        s.textContent = result.error;
        s.style.color = '#e00';
        yellowFade(this.queryOutputDiv_);
        return;
      }

      if (result.result == false) {
        this.queryOutputDiv_.innerHTML = '<b>Not found</b>';
        yellowFade(this.queryOutputDiv_);
        return;
      }

      this.queryOutputDiv_.innerHTML = '';

      var s = addNode(this.queryOutputDiv_, 'span');
      s.innerHTML = '<b>Found</b>: mode: ';

      // TODO(palmer): Combine these 2-line pairs into 1:
      // addNodeWithText(this.queryOutputDiv_, 'tt', results.sts_observed);
      var t = addNode(this.queryOutputDiv_, 'tt');
      t.textContent = modeToString(result.mode);

      addTextNode(this.queryOutputDiv_, ' sts_include_subdomains:');

      t = addNode(this.queryOutputDiv_, 'tt');
      t.textContent = result.sts_subdomains;

      addTextNode(this.queryOutputDiv_, ' pkp_include_subdomains:');

      t = addNode(this.queryOutputDiv_, 'tt');
      t.textContent = result.pkp_subdomains;

      addTextNode(this.queryOutputDiv_, ' sts_observed:');

      t = addNode(this.queryOutputDiv_, 'tt');
      t.textContent = result.sts_observed;

      addTextNode(this.queryOutputDiv_, ' pkp_observed:');

      t = addNode(this.queryOutputDiv_, 'tt');
      t.textContent = result.pkp_observed;

      addTextNode(this.queryOutputDiv_, ' domain:');

      t = addNode(this.queryOutputDiv_, 'tt');
      t.textContent = result.domain;

      addTextNode(this.queryOutputDiv_, ' pubkey_hashes:');

      t = addNode(this.queryOutputDiv_, 'tt');

      // |public_key_hashes| is an old synonym for what is now
      // |preloaded_spki_hashes|, which in turn is a legacy synonym for
      // |static_spki_hashes|. Look for all three, and also for
      // |dynamic_spki_hashes|.
      if (typeof result.public_key_hashes === 'undefined')
        result.public_key_hashes = '';
      if (typeof result.preloaded_spki_hashes === 'undefined')
        result.preloaded_spki_hashes = '';
      if (typeof result.static_spki_hashes === 'undefined')
        result.static_spki_hashes = '';
      if (typeof result.dynamic_spki_hashes === 'undefined')
        result.dynamic_spki_hashes = '';

      var hashes = [];
      if (result.public_key_hashes)
        hashes.push(result.public_key_hashes);
      if (result.preloaded_spki_hashes)
        hashes.push(result.preloaded_spki_hashes);
      if (result.static_spki_hashes)
        hashes.push(result.static_spki_hashes);
      if (result.dynamic_spki_hashes)
        hashes.push(result.dynamic_spki_hashes);

      t.textContent = hashes.join(',');
      yellowFade(this.queryOutputDiv_);
    }
  };

  function modeToString(m) {
    // These numbers must match those in
    // TransportSecurityState::DomainState::UpgradeMode.
    if (m == 0) {
      return 'STRICT';
    } else if (m == 1) {
      return 'OPPORTUNISTIC';
    } else {
      return 'UNKNOWN';
    }
  }

  function yellowFade(element) {
    element.style.webkitTransitionProperty = 'background-color';
    element.style.webkitTransitionDuration = '0';
    element.style.backgroundColor = '#fffccf';
    setTimeout(function() {
      element.style.webkitTransitionDuration = '1000ms';
      element.style.backgroundColor = '#fff';
    }, 0);
  }

  return HSTSView;
})();