text: /*
   Copyright 2012-2015, Yahoo Inc.
   Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
   */
  "use strict";
  
  const coverage = require("istanbul-lib-coverage");
  const Path = require("./path");
  const { BaseNode, BaseTree } = require("./tree");
  
  class ReportNode extends BaseNode {
    constructor(path, fileCoverage) {
      super();
  
      this.path = path;
      this.parent = null;
      this.fileCoverage = fileCoverage;
      this.children = [];
    }
  
    static createRoot(children) {
      const root = new ReportNode(new Path([]));
  
      children.forEach((child) => {
        root.addChild(child);
      });
  
      return root;
    }
  
    addChild(child) {
      child.parent = this;
      this.children.push(child);
    }
  
    asRelative(p) {
      if (p.substring(0, 1) === "/") {
        return p.substring(1);
      }
      return p;
    }
  
    getQualifiedName() {
      return this.asRelative(this.path.toString());
    }
  
    getRelativeName() {
      const parent = this.getParent();
      const myPath = this.path;
      let relPath;
      let i;
      const parentPath = parent ? parent.path : new Path([]);
      if (parentPath.ancestorOf(myPath)) {
        relPath = new Path(myPath.elements());
        for (i = 0; i < parentPath.length; i += 1) {
          relPath.shift();
        }
        return this.asRelative(relPath.toString());
      }
      return this.asRelative(this.path.toString());
    }
  
    getParent() {
      return this.parent;
    }
  
    getChildren() {
      return this.children;
    }
  
    isSummary() {
      return !this.fileCoverage;
    }
  
    getFileCoverage() {
      return this.fileCoverage;
    }
  
    getCoverageSummary(filesOnly) {
      const cacheProp = `c_${filesOnly ? "files" : "full"}`;
      let summary;
  
      if (Object.prototype.hasOwnProperty.call(this, cacheProp)) {
        return this[cacheProp];
      }
  
      if (!this.isSummary()) {
        summary = this.getFileCoverage().toSummary();
      } else {
        let count = 0;
        summary = coverage.createCoverageSummary();
        this.getChildren().forEach((child) => {
          if (filesOnly && child.isSummary()) {
            return;
          }
          count += 1;
          summary.merge(child.getCoverageSummary(filesOnly));
        });
        if (count === 0 && filesOnly) {
          summary = null;
        }
      }
      this[cacheProp] = summary;
      return summary;
    }
  }
  
  class ReportTree extends BaseTree {
    constructor(root, childPrefix) {
      super(root);
  
      const maybePrefix = (node) => {
        if (childPrefix && !node.isRoot()) {
          node.path.unshift(childPrefix);
        }
      };
      this.visit({
        onDetail: maybePrefix,
        onSummary(node) {
          maybePrefix(node);
          node.children.sort((a, b) => {
            const astr = a.path.toString();
            const bstr = b.path.toString();
            return astr < bstr
              ? -1
              : astr > bstr
              ? 1
              : /* istanbul ignore next */ 0;
          });
        },
      });
    }
  }
  
  function findCommonParent(paths) {
    return paths.reduce(
      (common, path) => common.commonPrefixPath(path),
      paths[0] || new Path([]),
    );
  }
  
  function findOrCreateParent(parentPath, nodeMap, created = () => {}) {
    let parent = nodeMap[parentPath.toString()];
  
    if (!parent) {
      parent = new ReportNode(parentPath);
      nodeMap[parentPath.toString()] = parent;
      created(parentPath, parent);
    }
  
    return parent;
  }
  
  function toDirParents(list) {
    const nodeMap = Object.create(null);
    list.forEach((o) => {
      const parent = findOrCreateParent(o.path.parent(), nodeMap);
      parent.addChild(new ReportNode(o.path, o.fileCoverage));
    });
  
    return Object.values(nodeMap);
  }
  
  function addAllPaths(topPaths, nodeMap, path, node) {
    const parent = findOrCreateParent(
      path.parent(),
      nodeMap,
      (parentPath, parent) => {
        if (parentPath.hasParent()) {
          addAllPaths(topPaths, nodeMap, parentPath, parent);
        } else {
          topPaths.push(parent);
        }
      },
    );
  
    parent.addChild(node);
  }
  
  function foldIntoOneDir(node, parent) {
    const { children } = node;
    if (children.length === 1 && !children[0].fileCoverage) {
      children[0].parent = parent;
      return foldIntoOneDir(children[0], parent);
    }
    node.children = children.map((child) => foldIntoOneDir(child, node));
    return node;
  }
  
  function pkgSummaryPrefix(dirParents, commonParent) {
    if (!dirParents.some((dp) => dp.path.length === 0)) {
      return;
    }
  
    if (commonParent.length === 0) {
      return "root";
    }
  
    return commonParent.name();
  }
  
  class SummarizerFactory {
    constructor(coverageMap, defaultSummarizer = "pkg") {
      this._coverageMap = coverageMap;
      this._defaultSummarizer = defaultSummarizer;
      this._initialList = coverageMap.files().map((filePath) => ({
        filePath,
        path: new Path(filePath),
        fileCoverage: coverageMap.fileCoverageFor(filePath),
      }));
      this._commonParent = findCommonParent(
        this._initialList.map((o) => o.path.parent()),
      );
      if (this._commonParent.length > 0) {
        this._initialList.forEach((o) => {
          o.path.splice(0, this._commonParent.length);
        });
      }
    }
  
    get defaultSummarizer() {
      return this[this._defaultSummarizer];
    }
  
    get flat() {
      if (!this._flat) {
        this._flat = new ReportTree(
          ReportNode.createRoot(
            this._initialList.map(
              (node) => new ReportNode(node.path, node.fileCoverage),
            ),
          ),
        );
      }
  
      return this._flat;
    }
  
    _createPkg() {
      const dirParents = toDirParents(this._initialList);
      if (dirParents.length === 1) {
        return new ReportTree(dirParents[0]);
      }
  
      return new ReportTree(
        ReportNode.createRoot(dirParents),
        pkgSummaryPrefix(dirParents, this._commonParent),
      );
    }
  
    get pkg() {
      if (!this._pkg) {
        this._pkg = this._createPkg();
      }
  
      return this._pkg;
    }
  
    _createNested() {
      const nodeMap = Object.create(null);
      const topPaths = [];
      this._initialList.forEach((o) => {
        const node = new ReportNode(o.path, o.fileCoverage);
        addAllPaths(topPaths, nodeMap, o.path, node);
      });
  
      const topNodes = topPaths.map((node) => foldIntoOneDir(node));
      if (topNodes.length === 1) {
        return new ReportTree(topNodes[0]);
      }
  
      return new ReportTree(ReportNode.createRoot(topNodes));
    }
  
    get nested() {
      if (!this._nested) {
        this._nested = this._createNested();
      }
  
      return this._nested;
    }
  }
  
  module.exports = SummarizerFactory;
  