module Webglimpse { function requireString ( s ) { if ( isString ( s ) ) { return s ; } else { throw new Error ( 'Expected a string, but value is ' + s ) ; } } export class OrderedSet < V > { private _idOf : IdFunction < V > ; private _ids : string [ ] ; private _indexes : StringMap < number > ; private _valuesArray : V [ ] ; private _valuesMap : StringMap < V > ; private _valueAdded : Notification2 < V , number > ; private _valueMoved : Notification3 < V , number , number > ; private _valueRemoved : Notification2 < V , number > ; constructor ( values = [ ] , idFn = getObjectId , useNotifications = true ) { this . _idOf = idFn ; this . _valuesArray = copyArray ( values ) ; this . _ids = [ ] ; this . _indexes = { } ; this . _valuesMap = { } ; for ( var n = 0 ; n < this . _valuesArray . length ; n ++ ) { var value = this . _valuesArray [ n ] ; var id = requireString ( this . _idOf ( value ) ) ; this . _ids [ n ] = id ; this . _indexes [ id ] = n ; this . _valuesMap [ id ] = value ; } if ( useNotifications ) { this . _valueAdded = new Notification2 < V , number > ( ) ; this . _valueMoved = new Notification3 < V , number , number > ( ) ; this . _valueRemoved = new Notification2 < V , number > ( ) ; } } get valueAdded ( ) : Notification2 < V , number > { return this . _valueAdded ; } get valueMoved ( ) : Notification3 < V , number , number > { return this . _valueMoved ; } get valueRemoved ( ) : Notification2 < V , number > { return this . _valueRemoved ; } get length ( ) : number { return this . _valuesArray . length ; } get isEmpty ( ) : boolean { return ( this . _valuesArray . length === 0 ) ; } toArray ( ) { return copyArray ( this . _valuesArray ) ; } /**
         * The callback should not modify its array arg; if it does, the subsequent behavior
         * of this OrderedSet is undefined.
         */ every ( callbackFn , thisArg ? ) { return this . _valuesArray . every ( callbackFn , thisArg ) ; } /**
         * The callback should not modify its array arg; if it does, the subsequent behavior
         * of this OrderedSet is undefined.
         */ some ( callbackFn , thisArg ? ) { return this . _valuesArray . some ( callbackFn , thisArg ) ; } /**
         * The callback should not modify its array arg; if it does, the subsequent behavior
         * of this OrderedSet is undefined.
         */ forEach ( callbackFn , thisArg ? ) { this . _valuesArray . forEach ( callbackFn , thisArg ) ; } /**
         * The callback should not modify its array arg; if it does, the subsequent behavior
         * of this OrderedSet is undefined.
         */ map < U > ( callbackFn , thisArg ? ) { return this . _valuesArray . map ( callbackFn , thisArg ) ; } /**
         * The callback should not modify its array arg; if it does, the subsequent behavior
         * of this OrderedSet is undefined.
         */ filter ( callbackFn , thisArg ? ) { return this . _valuesArray . filter ( callbackFn , thisArg ) ; } /**
         * The callback should not modify its array arg; if it does, the subsequent behavior
         * of this OrderedSet is undefined.
         */ reduce < U > ( callbackFn , initialValue ) { return this . _valuesArray . reduce ( callbackFn , initialValue ) ; } /**
         * The callback should not modify its array arg; if it does, the subsequent behavior
         * of this OrderedSet is undefined.
         */ reduceRight < U > ( callbackFn , initialValue ) { return this . _valuesArray . reduceRight ( callbackFn , initialValue ) ; } idAt ( index ) { return this . _ids [ index ] ; } valueAt ( index ) { return this . _valuesArray [ index ] ; } indexFor ( id ) { return ( isString ( id ) ? this . _indexes [ id ] : undefined ) ; } valueFor ( id ) { return ( isString ( id ) ? this . _valuesMap [ id ] : undefined ) ; } idOf ( value ) { return requireString ( this . _idOf ( value ) ) ; } indexOf ( value ) { return this . _indexes [ requireString ( this . _idOf ( value ) ) ] ; } hasValue ( value ) { return this . hasId ( requireString ( this . _idOf ( value ) ) ) ; } hasValues ( values ) { for ( var n = 0 ; n < values . length ; n ++ ) { if ( ! this . hasValue ( values [ n ] ) ) { return false ; } } return true ; } hasId ( id ) { return ( isString ( id ) && hasval ( this . _valuesMap [ id ] ) ) ; } hasIds ( ids ) { for ( var n = 0 ; n < ids . length ; n ++ ) { if ( ! this . hasId ( ids [ n ] ) ) { return false ; } } return true ; } add ( value , index ? , moveIfExists ? ) { var index = ( hasval ( index ) ? index : this . _valuesArray . length ) ; if ( ! hasval ( moveIfExists ) ) moveIfExists = false ; this . _add ( value , index , moveIfExists ) ; } addAll ( values , index ? , moveIfExists ? ) { var index = ( hasval ( index ) ? index : this . _valuesArray . length ) ; if ( ! hasval ( moveIfExists ) ) moveIfExists = false ; for ( var n = 0 ; n < values . length ; n ++ ) { var actualIndex = this . _add ( values [ n ] , index , moveIfExists ) ; index = actualIndex + 1 ; } } private _add ( value , newIndex , moveIfExists ) { var id = requireString ( this . _idOf ( value ) ) ; var oldIndex = this . _indexes [ id ] ; if ( ! hasval ( oldIndex ) ) { this . _ids . splice ( newIndex , 0 , id ) ; this . _valuesArray . splice ( newIndex , 0 , value ) ; this . _valuesMap [ id ] = value ; for ( var n = newIndex ; n < this . _ids . length ; n ++ ) { this . _indexes [ this . _ids [ n ] ] = n ; } if ( this . _valueAdded ) { this . _valueAdded . fire ( value , newIndex ) ; } } else if ( newIndex !== oldIndex && moveIfExists ) { this . _ids . splice ( oldIndex , 1 ) ; this . _valuesArray . splice ( oldIndex , 1 ) ; if ( newIndex > oldIndex ) { newIndex -- ; this . _ids . splice ( newIndex , 0 , id ) ; this . _valuesArray . splice ( newIndex , 0 , value ) ; for ( var n = oldIndex ; n <= newIndex ; n ++ ) { this . _indexes [ this . _ids [ n ] ] = n ; } } else { this . _ids . splice ( newIndex , 0 , id ) ; this . _valuesArray . splice ( newIndex , 0 , value ) ; for ( var n = newIndex ; n <= oldIndex ; n ++ ) { this . _indexes [ this . _ids [ n ] ] = n ; } } if ( this . _valueMoved ) { this . _valueMoved . fire ( value , oldIndex , newIndex ) ; } } else { newIndex = oldIndex ; } return newIndex ; } removeValue ( value ) { this . removeId ( requireString ( this . _idOf ( value ) ) ) ; } removeId ( id ) { if ( isString ( id ) ) { var index = this . _indexes [ id ] ; if ( hasval ( index ) ) { this . _remove ( id , index ) ; } } } removeIndex ( index ) { var id = this . _ids [ index ] ; if ( isString ( id ) ) { this . _remove ( id , index ) ; } } removeAll ( ) { for ( var n = this . _valuesArray . length - 1 ; n >= 0 ; n -- ) { var id = this . _ids [ n ] ; this . _remove ( id , n ) ; } } retainValues ( values ) { var idsToRetain = { } ; for ( var n = 0 ; n < values . length ; n ++ ) { var id = this . _idOf ( values [ n ] ) ; if ( isString ( id ) ) { idsToRetain [ id ] = true ; } } this . _retain ( idsToRetain ) ; } retainIds ( ids ) { var idsToRetain = { } ; for ( var n = 0 ; n < ids . length ; n ++ ) { var id = ids [ n ] ; if ( isString ( id ) ) { idsToRetain [ id ] = true ; } } this . _retain ( idsToRetain ) ; } retainIndices ( indices ) { var idsToRetain = { } ; for ( var n = 0 ; n < indices . length ; n ++ ) { var id = this . _ids [ indices [ n ] ] ; idsToRetain [ id ] = true ; } this . _retain ( idsToRetain ) ; } private _retain ( ids ) { for ( var n = this . _valuesArray . length - 1 ; n >= 0 ; n -- ) { var id = this . _ids [ n ] ; if ( ! ids . hasOwnProperty ( id ) ) { this . _remove ( id , n ) ; } } } private _remove ( id , index ) { var value = this . _valuesArray [ index ] ; this . _ids . splice ( index , 1 ) ; this . _valuesArray . splice ( index , 1 ) ; delete this . _indexes [ id ] ; delete this . _valuesMap [ id ] ; for ( var n = index ; n < this . _ids . length ; n ++ ) { this . _indexes [ this . _ids [ n ] ] = n ; } if ( this . _valueRemoved ) { this . _valueRemoved . fire ( value , index ) ; } } } export class OrderedStringSet { private _indexes : StringMap < number > ; private _valuesArray : string [ ] ; private _valueAdded : Notification2 < string , number > ; private _valueMoved : Notification3 < string , number , number > ; private _valueRemoved : Notification2 < string , number > ; constructor ( values = [ ] , useNotifications = true ) { this . _valuesArray = [ ] ; this . _indexes = { } ; for ( var n = 0 ; n < values . length ; n ++ ) { var value = requireString ( values [ n ] ) ; this . _valuesArray [ n ] = value ; this . _indexes [ value ] = n ; } if ( useNotifications ) { this . _valueAdded = new Notification2 < string , number > ( ) ; this . _valueMoved = new Notification3 < string , number , number > ( ) ; this . _valueRemoved = new Notification2 < string , number > ( ) ; } } get valueAdded ( ) : Notification2 < string , number > { return this . _valueAdded ; } get valueMoved ( ) : Notification3 < string , number , number > { return this . _valueMoved ; } get valueRemoved ( ) : Notification2 < string , number > { return this . _valueRemoved ; } get length ( ) : number { return this . _valuesArray . length ; } get isEmpty ( ) : boolean { return ( this . _valuesArray . length === 0 ) ; } toArray ( ) { return copyArray ( this . _valuesArray ) ; } /**
         * The callback should not modify its array arg; if it does, the subsequent behavior
         * of this OrderedStringSet is undefined.
         */ every ( callbackFn , thisArg ? ) { return this . _valuesArray . every ( callbackFn , thisArg ) ; } /**
         * The callback should not modify its array arg; if it does, the subsequent behavior
         * of this OrderedStringSet is undefined.
         */ some ( callbackFn , thisArg ? ) { return this . _valuesArray . some ( callbackFn , thisArg ) ; } /**
         * The callback should not modify its array arg; if it does, the subsequent behavior
         * of this OrderedStringSet is undefined.
         */ forEach ( callbackFn , thisArg ? ) { this . _valuesArray . forEach ( callbackFn , thisArg ) ; } /**
         * The callback should not modify its array arg; if it does, the subsequent behavior
         * of this OrderedStringSet is undefined.
         */ map < U > ( callbackFn , thisArg ? ) { return this . _valuesArray . map ( callbackFn , thisArg ) ; } /**
         * The callback should not modify its array arg; if it does, the subsequent behavior
         * of this OrderedStringSet is undefined.
         */ filter ( callbackFn , thisArg ? ) { return this . _valuesArray . filter ( callbackFn , thisArg ) ; } /**
         * The callback should not modify its array arg; if it does, the subsequent behavior
         * of this OrderedStringSet is undefined.
         */ reduce < U > ( callbackFn , initialValue ) { return this . _valuesArray . reduce ( callbackFn , initialValue ) ; } /**
         * The callback should not modify its array arg; if it does, the subsequent behavior
         * of this OrderedStringSet is undefined.
         */ reduceRight < U > ( callbackFn , initialValue ) { return this . _valuesArray . reduceRight ( callbackFn , initialValue ) ; } valueAt ( index ) { return this . _valuesArray [ index ] ; } indexOf ( value ) { return ( isString ( value ) ? this . _indexes [ value ] : undefined ) ; } hasValue ( value ) { return ( isString ( value ) && hasval ( this . _indexes [ value ] ) ) ; } hasValues ( values ) { for ( var n = 0 ; n < values . length ; n ++ ) { if ( ! this . hasValue ( values [ n ] ) ) { return false ; } } return true ; } add ( value , index ? , moveIfExists ? ) { var index = ( hasval ( index ) ? index : this . _valuesArray . length ) ; if ( ! hasval ( moveIfExists ) ) moveIfExists = false ; this . _add ( value , index , moveIfExists ) ; } addAll ( values , index ? , moveIfExists ? ) { var index = ( hasval ( index ) ? index : this . _valuesArray . length ) ; if ( ! hasval ( moveIfExists ) ) moveIfExists = false ; for ( var n = 0 ; n < values . length ; n ++ ) { var actualIndex = this . _add ( values [ n ] , index , moveIfExists ) ; index = actualIndex + 1 ; } } private _add ( value , newIndex , moveIfExists ) { requireString ( value ) ; var oldIndex = this . _indexes [ value ] ; if ( ! hasval ( oldIndex ) ) { this . _valuesArray . splice ( newIndex , 0 , value ) ; for ( var n = newIndex ; n < this . _valuesArray . length ; n ++ ) { this . _indexes [ this . _valuesArray [ n ] ] = n ; } if ( this . _valueAdded ) { this . _valueAdded . fire ( value , newIndex ) ; } } else if ( newIndex !== oldIndex && moveIfExists ) { this . _valuesArray . splice ( oldIndex , 1 ) ; if ( newIndex > oldIndex ) { newIndex -- ; this . _valuesArray . splice ( newIndex , 0 , value ) ; for ( var n = oldIndex ; n <= newIndex ; n ++ ) { this . _indexes [ this . _valuesArray [ n ] ] = n ; } } else { this . _valuesArray . splice ( newIndex , 0 , value ) ; for ( var n = newIndex ; n <= oldIndex ; n ++ ) { this . _indexes [ this . _valuesArray [ n ] ] = n ; } } if ( this . _valueMoved ) { this . _valueMoved . fire ( value , oldIndex , newIndex ) ; } } else { newIndex = oldIndex ; } return newIndex ; } removeValue ( value ) { if ( isString ( value ) ) { var index = this . _indexes [ value ] ; if ( hasval ( index ) ) { this . _remove ( value , index ) ; } } } removeIndex ( index ) { var value = this . _valuesArray [ index ] ; if ( isString ( value ) ) { this . _remove ( value , index ) ; } } removeAll ( ) { for ( var n = this . _valuesArray . length - 1 ; n >= 0 ; n -- ) { var value = this . _valuesArray [ n ] ; this . _remove ( value , n ) ; } } retainValues ( values ) { var valuesToRetain = { } ; for ( var n = 0 ; n < values . length ; n ++ ) { var value = values [ n ] ; if ( isString ( value ) ) { valuesToRetain [ value ] = true ; } } this . _retain ( valuesToRetain ) ; } retainIndices ( indices ) { var valuesToRetain = { } ; for ( var n = 0 ; n < indices . length ; n ++ ) { var value = this . _valuesArray [ indices [ n ] ] ; valuesToRetain [ value ] = true ; } this . _retain ( valuesToRetain ) ; } private _retain ( values ) { for ( var n = this . _valuesArray . length - 1 ; n >= 0 ; n -- ) { var value = this . _valuesArray [ n ] ; if ( ! values . hasOwnProperty ( value ) ) { this . _remove ( value , n ) ; } } } private _remove ( value , index ) { this . _valuesArray . splice ( index , 1 ) ; delete this . _indexes [ value ] ; for ( var n = index ; n < this . _valuesArray . length ; n ++ ) { this . _indexes [ this . _valuesArray [ n ] ] = n ; } if ( this . _valueRemoved ) { this . _valueRemoved . fire ( value , index ) ; } } } }