text: // Copyright 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.
  
  cr.define('serviceworker', function() {
    'use strict';
  
    function initialize() {
      update();
    }
  
    function update() {
        chrome.send('GetOptions');
        chrome.send('getAllRegistrations');
    }
  
    function onOptions(options) {
      var template;
      var container = $('serviceworker-options');
      if (container.childNodes) {
        template = container.childNodes[0];
      }
      if (!template) {
        template = jstGetTemplate('serviceworker-options-template');
        container.appendChild(template);
      }
      jstProcess(new JsEvalContext(options), template);
      var inputs = container.querySelectorAll('input[type=\'checkbox\']');
      for (var i = 0; i < inputs.length; ++i) {
        if (!inputs[i].hasClickEvent) {
          inputs[i].addEventListener('click', (function(event) {
            chrome.send('SetOption',
                        [event.target.className, event.target.checked]);
          }).bind(this), false);
          inputs[i].hasClickEvent = true;
        }
      }
    }
  
    function progressNodeFor(link) {
      return link.parentNode.querySelector('.operation-status');
    }
  
    // All commands are completed with 'onOperationComplete'.
    var COMMANDS = ['stop', 'sync', 'push', 'inspect', 'unregister', 'start'];
    function commandHandler(command) {
      return function(event) {
        var link = event.target;
        progressNodeFor(link).style.display = 'inline';
        sendCommand(command, link.cmdArgs, (function(status) {
          progressNodeFor(link).style.display = 'none';
        }).bind(null, link));
        return false;
      };
    };
  
    var commandCallbacks = [];
    function sendCommand(command, args, callback) {
      var callbackId = 0;
      while (callbackId in commandCallbacks) {
        callbackId++;
      }
      commandCallbacks[callbackId] = callback;
      chrome.send(command, [callbackId, args]);
    }
  
    // Fired from the backend after the command call has completed.
    function onOperationComplete(status, callbackId) {
      var callback = commandCallbacks[callbackId];
      delete commandCallbacks[callbackId];
      if (callback) {
        callback(status);
      }
      update();
    }
  
    var allLogMessages = {};
    // Set log for a worker version.
    function fillLogForVersion(container, partition_id, version) {
      if (!version) {
        return;
      }
      if (!(partition_id in allLogMessages)) {
        allLogMessages[partition_id] = {};
      }
      var logMessages = allLogMessages[partition_id];
      if (version.version_id in logMessages) {
        version.log = logMessages[version.version_id];
      } else {
        version.log = '';
      }
      var logAreas = container.querySelectorAll('textarea.serviceworker-log');
      for (var i = 0; i < logAreas.length; ++i) {
        var logArea = logAreas[i];
        if (logArea.partition_id == partition_id &&
            logArea.version_id == version.version_id) {
          logArea.value = version.log;
        }
      }
    }
  
    // Get the unregistered workers.
    // |unregistered_registrations| will be filled with the registrations which
    // are in |live_registrations| but not in |stored_registrations|.
    // |unregistered_versions| will be filled with the versions which
    // are in |live_versions| but not in |stored_registrations| nor in
    // |live_registrations|.
    function getUnregisteredWorkers(stored_registrations,
                                    live_registrations,
                                    live_versions,
                                    unregistered_registrations,
                                    unregistered_versions) {
      var registration_id_set = {};
      var version_id_set = {};
      stored_registrations.forEach(function(registration) {
        registration_id_set[registration.registration_id] = true;
      });
      [stored_registrations, live_registrations].forEach(function(registrations) {
        registrations.forEach(function(registration) {
          [registration.active, registration.waiting].forEach(function(version) {
            if (version) {
              version_id_set[version.version_id] = true;
            }
          });
        });
      });
      live_registrations.forEach(function(registration) {
        if (!registration_id_set[registration.registration_id]) {
          registration.unregistered = true;
          unregistered_registrations.push(registration);
        }
      });
      live_versions.forEach(function(version) {
        if (!version_id_set[version.version_id]) {
          unregistered_versions.push(version);
        }
      });
    }
  
    // Fired once per partition from the backend.
    function onPartitionData(live_registrations,
                             live_versions,
                             stored_registrations,
                             partition_id,
                             partition_path) {
      var unregistered_registrations = [];
      var unregistered_versions = [];
      getUnregisteredWorkers(stored_registrations,
                             live_registrations,
                             live_versions,
                             unregistered_registrations,
                             unregistered_versions);
      var template;
      var container = $('serviceworker-list');
      // Existing templates are keyed by partition_id. This allows
      // the UI to be updated in-place rather than refreshing the
      // whole page.
      for (var i = 0; i < container.childNodes.length; ++i) {
        if (container.childNodes[i].partition_id == partition_id) {
          template = container.childNodes[i];
        }
      }
      // This is probably the first time we're loading.
      if (!template) {
        template = jstGetTemplate('serviceworker-list-template');
        container.appendChild(template);
      }
      var fillLogFunc = fillLogForVersion.bind(this, container, partition_id);
      stored_registrations.forEach(function(registration) {
        [registration.active, registration.waiting].forEach(fillLogFunc);
      });
      unregistered_registrations.forEach(function(registration) {
        [registration.active, registration.waiting].forEach(fillLogFunc);
      });
      unregistered_versions.forEach(fillLogFunc);
      jstProcess(new JsEvalContext({
                   stored_registrations: stored_registrations,
                   unregistered_registrations: unregistered_registrations,
                   unregistered_versions: unregistered_versions,
                   partition_id: partition_id,
                   partition_path: partition_path}),
                 template);
      for (var i = 0; i < COMMANDS.length; ++i) {
        var handler = commandHandler(COMMANDS[i]);
        var links = container.querySelectorAll('button.' + COMMANDS[i]);
        for (var j = 0; j < links.length; ++j) {
          if (!links[j].hasClickEvent) {
            links[j].addEventListener('click', handler, false);
            links[j].hasClickEvent = true;
          }
        }
      }
    }
  
    function onWorkerStarted(partition_id, version_id, process_id, thread_id) {
      update();
    }
  
    function onWorkerStopped(partition_id, version_id, process_id, thread_id) {
      update();
    }
  
    function onErrorReported(partition_id,
                             version_id,
                             process_id,
                             thread_id,
                             error_info) {
      outputLogMessage(partition_id,
                       version_id,
                       'Error: ' + JSON.stringify(error_info) + '\n');
    }
  
    function onConsoleMessageReported(partition_id,
                                      version_id,
                                      process_id,
                                      thread_id,
                                      message) {
      outputLogMessage(partition_id,
                       version_id,
                       'Console: ' + JSON.stringify(message) + '\n');
    }
  
    function onVersionStateChanged(partition_id, version_id) {
      update();
    }
  
    function onRegistrationStored(scope) {
      update();
    }
  
    function onRegistrationDeleted(scope) {
      update();
    }
  
    function outputLogMessage(partition_id, version_id, message) {
      if (!(partition_id in allLogMessages)) {
        allLogMessages[partition_id] = {};
      }
      var logMessages = allLogMessages[partition_id];
      if (version_id in logMessages) {
        logMessages[version_id] += message;
      } else {
        logMessages[version_id] = message;
      }
  
      var logAreas = document.querySelectorAll('textarea.serviceworker-log');
      for (var i = 0; i < logAreas.length; ++i) {
        var logArea = logAreas[i];
        if (logArea.partition_id == partition_id &&
            logArea.version_id == version_id) {
          logArea.value += message;
        }
      }
    }
  
    return {
      initialize: initialize,
      onOptions: onOptions,
      onOperationComplete: onOperationComplete,
      onPartitionData: onPartitionData,
      onWorkerStarted: onWorkerStarted,
      onWorkerStopped: onWorkerStopped,
      onErrorReported: onErrorReported,
      onConsoleMessageReported: onConsoleMessageReported,
      onVersionStateChanged: onVersionStateChanged,
      onRegistrationStored: onRegistrationStored,
      onRegistrationDeleted: onRegistrationDeleted,
    };
  });
  
  document.addEventListener('DOMContentLoaded', serviceworker.initialize);
  