import {Algorithm} from '../../utils/algorithm'
import {GeomEdge} from '../core/geomEdge'
import {GeomGraph} from '../core/GeomGraph'
import {SingleSourceDistances} from './SingleSourceDistances'
//  An algorithm for computing the distances between a selected set of nodes and all nodes.
export class PivotDistances extends Algorithm {
  private graph: GeomGraph
  private length: (e: GeomEdge) => number
  private pivotArray: number[]
  private result: number[][]
  //  A square matrix with shortest path distances.
  get Result(): number[][] {
    return this.result
  }

  //  Computes distances between a selected set of nodes and all nodes.
  //  Pivot nodes are selected with maxmin strategy (first at random, later
  //  ones to maximize distances to all previously selected ones).
  constructor(graph: GeomGraph, pivotArray: number[], length: (e: GeomEdge) => number) {
    super(null) // todo: pass the canceltoken
    this.graph = graph
    this.pivotArray = pivotArray
    this.length = length
  }

  //  Executes the algorithm.
  run() {
    this.result = new Array(this.pivotArray.length)
    const nodes = Array.from(this.graph.shallowNodes())
    const min = new Array(this.graph.shallowNodeCount).fill(Number.POSITIVE_INFINITY)

    let pivot = nodes[0]
    this.pivotArray[0] = 0
    for (let i = 0; ; i++) {
      const ssd = new SingleSourceDistances(this.graph, pivot, this.length)
      ssd.run()
      this.Result[i] = ssd.Result
      if (i + 1 < this.pivotArray.length) {
        // looking for the next pivot
        let argmax = 0
        for (let j = 0; j < this.Result[i].length; j++) {
          min[j] = Math.min(min[j], this.Result[i][j])
          if (min[j] > min[argmax]) {
            argmax = j
          }
        }

        pivot = nodes[argmax]
        this.pivotArray[i + 1] = argmax
      } else {
        break
      }
    }
  }
}
