'use strict'

/**
 * Definition for singly-linked list with a random pointer.
 * function RandomListNode(label) {
 *     this.label = label
 *     this.next = this.random = null
 * }
 */

function RandomListNode(label) {
    this.label = label
    this.next = this.random = null
}

/**
 * @param {RandomListNode} head
 * @return {RandomListNode}
 */
var copyRandomList = function (head) {
    if (head === null) return null
    const newHead = new RandomListNode(head.label)
    const map = new Map()
    if (head.random !== null) {
        if (map.has(head.random))
            map.get(head.random).push(newHead)
        else
            map.set(head.random, [newHead])
    }
    let prev = newHead
    let curr = head.next
    while (curr !== null) {
        const node = new RandomListNode(curr.label)
        prev.next = node
        if (curr.random !== null) {
            if (map.has(curr.random))
                map.get(curr.random).push(node)
            else
                map.set(curr.random, [node])
        }
        prev = node
        curr = curr.next
    }
    if (map.size != 0) {
        for (curr = head, prev = newHead; curr !== null; curr = curr.next, prev = prev.next) {
            if (map.has(curr))
                for (const n of map.get(curr)) n.random = prev
        }
    }
    return newHead
}

function __main__() {
    /* eslint no-console: ["error", {"allow": ["log"]}] */
    const logger = console.log.bind(console)
    const n5 = new RandomListNode(5)
    const n4 = new RandomListNode(4)
    const n3 = new RandomListNode(3)
    const n2 = new RandomListNode(2)
    const n1 = new RandomListNode(1)
    n1.next = n2
    n2.next = n3
    n3.next = n4
    n4.next = n5
    n1.random = n4
    n2.random = n1
    n3.random = n5
    n4.random = null
    n5.random = n3
    const n = copyRandomList(n1)
    logger(n)
    logger(n1)
}

__main__()