const ion = null
# don't depend on ion for this.

# the uniqueCounter and getId have to be defined outside of the MapShim constructor.
# otherwise some objects may end up with the same uniqueId if they are added to different Maps.
let uniqueCounter = 0
const idName = "_Map_id_"
const getId = (key) ->
    if not key?
        return String(key)
    if typeof key is 'string' or typeof key is 'number' or typeof key is 'boolean'
        return "_" + key
    let id = key[idName]
    if not id?
        # checking the definition shouldn't be necessary.
        # but nodejs has an object returning undefined
        # even though the definition says it has a value.
        let def = Object.getOwnPropertyDescriptor(key, idName)
        if def?
            id = def.value
        else
            id = ++uniqueCounter
            Object.defineProperty(key, idName, {value:id})
    return id

const MapShim(pairs) ->
    if pairs?
        throw new Error("Don't add items in the constructor, IE implementation of Set breaks this")
    let lookup = {}
    let keys = []
    const methods =
        get: (key) -> lookup[getId(key)]
        set: (key, value) ->
            let id = getId(key)
            if not lookup.hasOwnProperty(id)
                keys.push(key)
            lookup[id] = value
            return value
        has: (key) ->
            let id = getId(key)
            return lookup.hasOwnProperty(id)
        delete: (key) ->
            let id = getId(key)
            keys.remove(key)
            delete lookup[id]
        clear: ->
            lookup = {}
            keys = []
        forEach: (callback, thisArg) ->
            for key in keys
                let value = @get(key)
                callback.call(thisArg, value, key, @)
    for key, value of methods
        Object.defineProperty(@, key, {value})

# we will even replace Googles crap implementation of Map that doesn't yet have forEach
if not global.Map?.prototype.forEach?
    if global.window
        console.warn('Shimming Map')
    global.Map = MapShim

export const test = ->
    const Map = global.Map
    let map = new Map()
    map.set('a', 1)
    map.set('b', 2)
    assert Object.keys(map).length is 0
    assert map.has('a')
    assert not map.has('c')
    assert map.get('a') is 1
    assert map.get('b') is 2
    assert map.get('c') is undefined
    let mykey1 = {}
    map.set(mykey1, "one")
    assert Object.keys(mykey1).length is 0
    assert map.get(mykey1) is "one"
