export abstract class WatchedList < T > { public currentItems : T [ ] ; private initial : T [ ] ; private new : T [ ] ; private removed : T [ ] ; constructor ( initialItems ? ) { this . currentItems = initialItems || [ ] ; this . initial = initialItems || [ ] ; this . new = [ ] ; this . removed = [ ] ; } abstract compareItems ( a , b ) ; public getItems ( ) { return this . currentItems ; } public getNewItems ( ) { return this . new ; } public getRemovedItems ( ) { return this . removed ; } private isCurrentItem ( item ) { return ( this . currentItems . filter ( ( v ) => this . compareItems ( item , v ) ) . length !== 0 ) ; } private isNewItem ( item ) { return this . new . filter ( ( v ) => this . compareItems ( item , v ) ) . length !== 0 ; } private isRemovedItem ( item ) { return ( this . removed . filter ( ( v ) => this . compareItems ( item , v ) ) . length !== 0 ) ; } private removeFromNew ( item ) { this . new = this . new . filter ( ( v ) => ! this . compareItems ( v , item ) ) ; } private removeFromCurrent ( item ) { this . currentItems = this . currentItems . filter ( ( v ) => ! this . compareItems ( item , v ) ) ; } private removeFromRemoved ( item ) { this . removed = this . removed . filter ( ( v ) => ! this . compareItems ( item , v ) ) ; } private wasAddedInitially ( item ) { return ( this . initial . filter ( ( v ) => this . compareItems ( item , v ) ) . length !== 0 ) ; } public exists ( item ) { return this . isCurrentItem ( item ) ; } public add ( item ) { if ( this . isRemovedItem ( item ) ) { this . removeFromRemoved ( item ) ; } if ( ! this . isNewItem ( item ) && ! this . wasAddedInitially ( item ) ) { this . new . push ( item ) ; } if ( ! this . isCurrentItem ( item ) ) { this . currentItems . push ( item ) ; } } public remove ( item ) { this . removeFromCurrent ( item ) ; if ( this . isNewItem ( item ) ) { this . removeFromNew ( item ) ; return ; } if ( ! this . isRemovedItem ( item ) ) { this . removed . push ( item ) ; } } }