module Webglimpse { export class SortedMultimap < K , V > { private _tree : BinaryTree < Container < K , V > > ; private _idFn : IdFunction < V > ; constructor ( comparator , idFn = getObjectId ) { this . _tree = new BinaryTree < Container < K , V > > ( this . createContainerComparator < V > ( comparator ) ) ; this . _idFn = idFn ; } private createContainerComparator < V > ( comparator ) { return { compare : function ( container1 , container2 ) : number { return comparator . compare ( container1 . key , container2 . key ) ; } } ; } insert ( key , value ) { var wrappedKey = new Container < K , V > ( key ) ; var values = this . _tree . getValue ( wrappedKey ) ; if ( values === null ) { values = wrappedKey ; this . _tree . insert ( values ) ; } values . add ( value , this . _idFn ) ; } remove ( key , value ) { var wrappedKey = new Container < K , V > ( key ) ; var values = this . _tree . getValue ( wrappedKey ) ; if ( values === null ) return ; values . remove ( value , this . _idFn ) ; if ( values . size === 0 ) { this . _tree . remove ( values ) ; } } contains ( key , value ) { var wrappedKey = new Container < K , V > ( key ) ; var values = this . _tree . getValue ( wrappedKey ) ; if ( values === null ) { return false ; } else { return values . contains ( value , this . _idFn ) ; } } ceiling ( key ) { return this . unwrap ( this . _tree . ceiling ( this . wrap ( key ) ) ) ; } floor ( key ) { return this . unwrap ( this . _tree . floor ( this . wrap ( key ) ) ) ; } lower ( key ) { return this . unwrap ( this . _tree . lower ( this . wrap ( key ) ) ) ; } higher ( key ) { return this . unwrap ( this . _tree . higher ( this . wrap ( key ) ) ) ; } headSet ( key , inclusive = true ) { return this . unwrapArray ( this . _tree . headSet ( this . wrap ( key ) , inclusive ) ) ; } tailSet ( key , inclusive = false ) { return this . unwrapArray ( this . _tree . tailSet ( this . wrap ( key ) , inclusive ) ) ; } subSet ( low , high , lowInclusive = true , highInclusive = false ) { var wrappedLow = new Container < K , V > ( low ) ; var wrappedHigh = new Container < K , V > ( high ) ; var values = this . _tree . subSet ( wrappedLow , wrappedHigh , lowInclusive , highInclusive ) ; return this . unwrapArray ( values ) ; } toArray ( ) { return this . unwrapArray ( this . _tree . toArray ( ) ) ; } iterator ( ) { var iter = this . _tree . iterator ( ) ; var currentArray = null ; var currentIndex = 0 ; return { next : function ( ) : V { var value ; if ( currentArray == null || currentIndex >= currentArray . length ) { currentArray = iter . next ( ) . toArray ( ) ; currentIndex = 0 ; value = currentArray [ currentIndex ] ; } else { value = currentArray [ currentIndex ] ; } currentIndex += 1 ; return value ; } , hasNext : function ( ) : boolean { return iter . hasNext ( ) || ( currentArray != null && currentIndex < currentArray . length ) ; } } ; } private wrap ( key ) { return new Container < K , V > ( key ) ; } private unwrap ( values ) { if ( values === null ) { return [ ] ; } else { return values . toArray ( ) ; } } private unwrapArray ( values ) { var unwrappedValues = new Array < V > ( ) ; values . forEach ( function ( value ) { value . toArray ( ) . forEach ( function ( value ) { unwrappedValues . push ( value ) ; } ) ; } ) ; return unwrappedValues ; } } export class SortedStringMultimap < K > extends SortedMultimap < K , string > { constructor ( comparator ) { super ( comparator , ( value ) => value ) ; } } class Container < K , V > { private _key : K ; private _values : StringMap < V > ; constructor ( key ) { this . _key = key ; this . _values = { } ; } get size ( ) : number { return this . toArray ( ) . length ; } get key ( ) : K { return this . _key ; } get values ( ) : StringMap < V > { return this . _values ; } toArray ( ) { return Object . keys ( this . _values ) . map ( key => this . _values [ key ] ) ; } contains ( value , idFn ) { return Object . prototype . hasOwnProperty . call ( this . _values , idFn ( value ) ) ; } add ( value , idFn ) { this . _values [ idFn ( value ) ] = value ; } remove ( value , idFn ) { delete this . _values [ idFn ( value ) ] ; } } }