package goja

import (
	
)

type mapEntry struct {
	key, value Value

	iterPrev, iterNext *mapEntry
	hNext              *mapEntry
}

type orderedMap struct {
	hash                *maphash.Hash
	hashTable           map[uint64]*mapEntry
	iterFirst, iterLast *mapEntry
	size                int
}

type orderedMapIter struct {
	m   *orderedMap
	cur *mapEntry
}

func ( *orderedMap) ( Value) ( uint64, ,  *mapEntry) {
	if  == _negativeZero {
		 = intToValue(0)
	}
	 = .hash(.hash)
	for  = .hashTable[];  != nil && !.key.SameAs(); ,  = , .hNext {
	}
	return
}

func ( *orderedMap) (,  Value) {
	, ,  := .lookup()
	if  != nil {
		.value = 
	} else {
		if  == _negativeZero {
			 = intToValue(0)
		}
		 = &mapEntry{key: , value: }
		if  == nil {
			.hashTable[] = 
		} else {
			.hNext = 
		}
		if .iterLast != nil {
			.iterPrev = .iterLast
			.iterLast.iterNext = 
		} else {
			.iterFirst = 
		}
		.iterLast = 
		.size++
	}
}

func ( *orderedMap) ( Value) Value {
	, ,  := .lookup()
	if  != nil {
		return .value
	}

	return nil
}

func ( *orderedMap) ( Value) bool {
	, ,  := .lookup()
	if  != nil {
		.key = nil
		.value = nil

		// remove from the doubly-linked list
		if .iterPrev != nil {
			.iterPrev.iterNext = .iterNext
		} else {
			.iterFirst = .iterNext
		}
		if .iterNext != nil {
			.iterNext.iterPrev = .iterPrev
		} else {
			.iterLast = .iterPrev
		}

		// remove from the hashTable
		if  == nil {
			if .hNext == nil {
				delete(.hashTable, )
			} else {
				.hashTable[] = .hNext
			}
		} else {
			.hNext = .hNext
		}

		.size--
		return true
	}

	return false
}

func ( *orderedMap) ( Value) bool {
	, ,  := .lookup()
	return  != nil
}

func ( *orderedMapIter) () *mapEntry {
	if .m == nil {
		// closed iterator
		return nil
	}

	 := .cur
	// if the current item was deleted, track back to find the latest that wasn't
	for  != nil && .key == nil {
		 = .iterPrev
	}

	if  != nil {
		 = .iterNext
	} else {
		 = .m.iterFirst
	}

	if  == nil {
		.close()
	} else {
		.cur = 
	}

	return 
}

func ( *orderedMapIter) () {
	.m = nil
	.cur = nil
}

func newOrderedMap( *maphash.Hash) *orderedMap {
	return &orderedMap{
		hash:      ,
		hashTable: make(map[uint64]*mapEntry),
	}
}

func ( *orderedMap) () *orderedMapIter {
	 := &orderedMapIter{
		m: ,
	}
	return 
}

func ( *orderedMap) () {
	for  := .iterFirst;  != nil;  = .iterNext {
		.key = nil
		.value = nil
		if .iterPrev != nil {
			.iterPrev.iterNext = nil
		}
	}
	.iterFirst = nil
	.iterLast = nil
	.hashTable = make(map[uint64]*mapEntry)
	.size = 0
}