// PROMPT: Track the mode of stored values
// Want constant-time insertValue and getMode
// Faster method is using binary heap

class Node {
  constructor(value) {
    this.value = value
    this.count = 1
    this.next = null
    this.prev = null
  }
}

class SortedDeque {
  constructor() {
    this.head = null
    this.tail = null
  }

  getMax() {
    return (this.head === null ? null : this.head.value)
  }

  append(value) {
    const node = new Node(value)

    if (this.head === null) {
      this.head = node
      this.tail = node

    } else {
      this.tail.prev = node
      node.next = this.tail
      this.tail = node
    }
    return node
  }

  bubbleUp(node) {
    while (node.next !== null && node.count > node.next.count) {
      const nodeNext = node.next
      node.next = nodeNext.next
      if (nodeNext.next !== null) {
        nodeNext.next.prev = node
      }
      nodeNext.next = node

      nodeNext.prev = node.prev
      if (node.prev !== null) {
        node.prev.next = nodeNext
      }
      node.prev = nodeNext

      if (node === this.tail) {
        this.tail = nodeNext
      }

      if (nodeNext === this.head) {
        this.head = node
      }
    }
  }

  print() {
    let curr = this.head
    while (curr !== null) {
      console.log(curr.value, curr.count)
      curr = curr.prev
    }
  }
}

class WeatherStats {
  constructor() {
    this.temperatures = {}
    this.frequencies = new SortedDeque()
  }

  insert(temperature) {
    if (!(temperature in this.temperatures)) {
      const node = this.frequencies.append(temperature)
      this.temperatures[temperature] = node
      return
    }

    const node = this.temperatures[temperature]
    node.count += 1

    this.frequencies.bubbleUp(node)
  }

  getMode() {
    //this.frequencies.print()
    return this.frequencies.getMax()
  }
  
}

function repeat(n, callback) {
  for (let i = 0; i < n; i++) {
    callback()
  }
}


function main() {
  const w = new WeatherStats()

  repeat(3, () => w.insert(33))
  repeat(7, () => w.insert(77))
  repeat(5, () => w.insert(55))

  repeat(9, () => w.insert(44))
  repeat(7, () => w.insert(70))
  repeat(5, () => w.insert(55))

  console.log(w.getMode())
}

main()
