text: /*
   * Copyright (C) 2018 Apple Inc. All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in the
   *    documentation and/or other materials provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   * THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  WI.AuditTestGroupContentView = class AuditTestGroupContentView extends WI.AuditTestContentView
  {
      constructor(representedObject)
      {
          console.assert(representedObject instanceof WI.AuditTestGroup || representedObject instanceof WI.AuditTestGroupResult);
  
          super(representedObject);
  
          this.element.classList.add("audit-test-group");
          this.element.classList.toggle("contains-test-case", this._subobjects().some((test) => test instanceof WI.AuditTestCase || test instanceof WI.AuditTestCaseResult));
          this.element.classList.toggle("contains-test-group", this._subobjects().some((test) => test instanceof WI.AuditTestGroup || test instanceof WI.AuditTestGroupResult));
  
          this._levelScopeBar = null;
      }
  
      // Protected
  
      initialLayout()
      {
          super.initialLayout();
  
          let informationContainer = this.headerView.element.appendChild(document.createElement("div"));
          informationContainer.classList.add("information");
  
          let nameElement = informationContainer.appendChild(document.createElement("h1"));
          nameElement.textContent = this.representedObject.name;
  
          if (this.representedObject.description) {
              let descriptionElement = informationContainer.appendChild(document.createElement("p"));
              descriptionElement.textContent = this.representedObject.description;
          }
  
          this._levelNavigationBar = new WI.NavigationBar(document.createElement("nav"));
          this._levelNavigationBar.element.dataset.prefix = WI.UIString("Showing:");
          this.headerView.addSubview(this._levelNavigationBar);
  
          this._percentageContainer = this.headerView.element.appendChild(document.createElement("div"));
          this._percentageContainer.classList.add("percentage-pass");
          this._percentageContainer.hidden = true;
  
          this._percentageTextElement = document.createElement("span");
  
          const format = WI.UIString("%s%%", "Percentage (of audits)", "The number of tests that passed expressed as a percentage, followed by a literal %.");
          String.format(format, [this._percentageTextElement], String.standardFormatters, this._percentageContainer, (a, b) => {
              a.append(b);
              return a;
          });
      }
  
      layout()
      {
          if (this.layoutReason !== WI.View.LayoutReason.Dirty)
              return;
  
          super.layout();
  
          let result = this.representedObject.result;
          if (!result) {
              if (this._levelScopeBar) {
                  this._levelNavigationBar.removeNavigationItem(this._levelScopeBar);
                  this._levelScopeBar = null;
              }
  
              this._percentageContainer.hidden = true;
              this._percentageTextElement.textContent = "";
  
              if (this.representedObject.runningState === WI.AuditManager.RunningState.Inactive)
                  this.showNoResultPlaceholder();
              else if (this.representedObject.runningState === WI.AuditManager.RunningState.Active)
                  this.showRunningPlaceholder();
              else if (this.representedObject.runningState === WI.AuditManager.RunningState.Stopping)
                  this.showStoppingPlaceholder();
  
              return;
          }
  
          let levelCounts = result.levelCounts;
          let totalCount = Object.values(levelCounts).reduce((accumulator, current) => accumulator + current);
          this._percentageTextElement.textContent = Math.floor(100 * levelCounts[WI.AuditTestCaseResult.Level.Pass] / totalCount);
          this._percentageContainer.hidden = false;
  
          if (!this._levelScopeBar) {
              let scopeBarItems = [];
  
              let addScopeBarItem = (level, labelSingular, labelPlural) => {
                  let count = levelCounts[level];
                  if (isNaN(count) || count <= 0)
                      return;
  
                  let label = (labelPlural && count !== 1) ? labelPlural : labelSingular;
                  let scopeBarItem = new WI.ScopeBarItem(level, label.format(count), {
                      className: level,
                      exclusive: false,
                      independent: true,
                  });
                  scopeBarItem.selected = true;
  
                  scopeBarItem.element.insertBefore(document.createElement("img"), scopeBarItem.element.firstChild);
  
                  scopeBarItems.push(scopeBarItem);
              };
  
              addScopeBarItem(WI.AuditTestCaseResult.Level.Pass, WI.UIString("%d Passed", "%d Passed (singular)", ""), WI.UIString("%d Passed", "%d Passed (plural)", ""));
              addScopeBarItem(WI.AuditTestCaseResult.Level.Warn, WI.UIString("%d Warning"), WI.UIString("%d Warnings"));
              addScopeBarItem(WI.AuditTestCaseResult.Level.Fail, WI.UIString("%d Failed", "%d Failed (singular)", ""), WI.UIString("%d Failed", "%d Failed (plural)", ""));
              addScopeBarItem(WI.AuditTestCaseResult.Level.Error, WI.UIString("%d Error"), WI.UIString("%d Errors"));
              addScopeBarItem(WI.AuditTestCaseResult.Level.Unsupported, WI.UIString("%d Unsupported", "%d Unsupported (singular)", ""), WI.UIString("%d Unsupported", "%d Unsupported (plural)", ""));
  
              this._levelScopeBar = new WI.ScopeBar(null, scopeBarItems);
              this._levelScopeBar.addEventListener(WI.ScopeBar.Event.SelectionChanged, this._handleLevelScopeBarSelectionChanged, this);
              this._levelNavigationBar.addNavigationItem(this._levelScopeBar);
          }
  
          if (this.applyFilter())
              this.hidePlaceholder();
          else
              this.showFilteredPlaceholder();
      }
  
      shown()
      {
          super.shown();
  
          if (this.representedObject instanceof WI.AuditTestGroup) {
              this.representedObject.addEventListener(WI.AuditTestBase.Event.Progress, this._handleTestGroupProgress, this);
              this.representedObject.addEventListener(WI.AuditTestBase.Event.Scheduled, this._handleTestGroupScheduled, this);
          }
  
          for (let subobject of this._subobjects()) {
              if (subobject instanceof WI.AuditTestBase && subobject.disabled)
                  continue;
  
              let view = WI.ContentView.contentViewForRepresentedObject(subobject);
              this.contentView.addSubview(view);
              view.shown();
          }
      }
  
      hidden()
      {
          for (let view of this.contentView.subviews)
              view.hidden();
  
          this.contentView.removeAllSubviews();
  
          super.hidden();
      }
  
      applyFilter(levels)
      {
          if (this._levelScopeBar && !levels)
              levels = this._levelScopeBar.selectedItems.map((item) => item.id);
  
          this._updateLevelScopeBar(levels);
  
          return super.applyFilter(levels);
      }
  
      resetFilter()
      {
          this._updateLevelScopeBar(Object.values(WI.AuditTestCaseResult.Level));
  
          super.resetFilter();
      }
  
      showRunningPlaceholder()
      {
          if (!this.placeholderElement || !this.placeholderElement.__placeholderRunning) {
              this.placeholderElement = WI.createMessageTextView(WI.UIString("Running the \u201C%s\u201D audit").format(this.representedObject.name));
              this.placeholderElement.__placeholderRunning = true;
  
              this.placeholderElement.__progress = document.createElement("progress");
              this.placeholderElement.__progress.value = 0;
              this.placeholderElement.appendChild(this.placeholderElement.__progress);
          }
  
          super.showRunningPlaceholder();
      }
  
      // Private
  
      _subobjects()
      {
          if (this.representedObject instanceof WI.AuditTestGroup)
              return this.representedObject.tests;
  
          if (this.representedObject instanceof WI.AuditTestGroupResult)
              return this.representedObject.results;
  
          console.error("Unknown representedObject", this.representedObject);
          return [];
      }
  
      _updateLevelScopeBar(levels)
      {
          if (!this._levelScopeBar)
              return;
  
          for (let item of this._levelScopeBar.items)
              item.selected = levels.includes(item.id);
  
          for (let view of this.contentView.subviews) {
              if (view instanceof WI.AuditTestGroupContentView)
                  view._updateLevelScopeBar(levels);
          }
      }
  
      _handleTestGroupProgress(event)
      {
          let {index, count} = event.data;
          if (this.placeholderElement && this.placeholderElement.__progress)
              this.placeholderElement.__progress.value = (index + 1) / count;
      }
  
      _handleTestGroupScheduled(event)
      {
          if (this.placeholderElement && this.placeholderElement.__progress)
              this.placeholderElement.__progress.value = 0;
      }
  
      _handleLevelScopeBarSelectionChanged(event)
      {
          this.needsLayout();
      }
  };
  