001    /*
002     *  www.ti.bfh.ch
003     *
004     *  Copyright 2007, Berne University of Applied Sciences, 
005     *  School of Engineering and Information Technology
006     *  and individual contributors as indicated by the @authors tag.
007     *
008     *  This is free software; you can redistribute it and/or modify it under the terms of the 
009     *  GNU Lesser General Public License as published by the Free Software Foundation; 
010     *  either version 3 of the License, or (at your option) any later version.
011     *
012     *  This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
013     *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
014     *  See the GNU Lesser General Public License for more details.
015     *
016     *  You should have received a copy of the GNU Lesser General Public License along with this software; 
017     *  if not, see <http://www.gnu.org/licenses/>.
018     *
019     */
020    package ch.bfh.algo.core.sequence;
021    
022    
023    import java.util.AbstractSequentialList;
024    import java.util.ListIterator;
025    
026    import ch.bfh.algo.BoundaryViolationException;
027    import ch.bfh.algo.EmptySequenceException;
028    import ch.bfh.algo.InvalidAccessorException;
029    import ch.bfh.algo.Position;
030    import ch.bfh.algo.core.GenericSequence;
031    import ch.bfh.algo.core.position.PositionIterator;
032    import ch.bfh.algo.core.position.PositionListIterator;
033    import ch.bfh.algo.sequence.SequenceFactory;
034    
035    
036    public class GenericLinkedSequence<E,P extends GenericLinkedPosition<E,P>> extends AbstractSequentialList<E> implements GenericSequence<E,P>{
037    
038            private int size;
039            final private P head,tail;
040            final private SequenceFactory<P> factory;
041                    
042            public GenericLinkedSequence(SequenceFactory<P> factory){
043                    this.factory=factory;
044                    this.head=this.factory.createPosition();
045                    this.tail=this.factory.createPosition();
046                    this.head.setNext(this.tail);
047                    this.tail.setPrevious(this.head);
048                    this.size=0;
049            }
050            
051            public int size() {
052                    return this.size;
053            }
054            
055            protected P head(){
056                    return this.head;
057            }
058    
059            protected P tail(){
060                    return this.tail;
061            }
062    
063            public P first() throws EmptySequenceException{
064                    if(this.isEmpty()) throw new EmptySequenceException();
065                    else return this.head.getNext();
066            }
067    
068            public P last() throws EmptySequenceException{
069                    if(this.isEmpty()) throw new EmptySequenceException();
070                    else return this.tail.getPrevious();
071            }
072    
073            public P before(Position<?> position) throws InvalidAccessorException, BoundaryViolationException {
074                    try{return this.before(this.factory.cast(position));}
075                    catch(ClassCastException e){throw new InvalidAccessorException();}
076            }
077    
078        public P before(P position) throws InvalidAccessorException, BoundaryViolationException{
079            this.validate(position);
080            position=position.getPrevious();
081            if(position==this.head) throw new BoundaryViolationException();
082            else return position;
083        }
084    
085            public P after(Position<?> position) throws InvalidAccessorException, BoundaryViolationException {
086                    try{return this.after(this.factory.cast(position));}
087                    catch(ClassCastException e){throw new InvalidAccessorException();}
088            }
089    
090        public P after(P position) throws InvalidAccessorException, BoundaryViolationException{
091            this.validate(position);
092            position=position.getNext();
093                    if(position==this.tail) throw new BoundaryViolationException();
094                    else return position;
095            }
096            
097            protected P insertBetween(P previous, P next, E element){
098                    return this.insertBetween(previous,next,element,this.factory.createPosition());
099            }
100            
101            protected synchronized P insertBetween(P previous, P next, E element, P position){
102                    ConcreteLocator<E,P> locator=new ConcreteLocator<E,P>();
103                    locator.setElement(element);
104                    locator.setPosition(position);
105                    position.setContainer(this);
106                    position.setLocator(locator);
107                    position.setNext(next);
108                    position.setPrevious(previous);
109                    previous.setNext(position);
110                    next.setPrevious(position);
111                    this.size++;
112                    next.notifyBefore();
113                    return position;
114            }
115            
116            public P insertBefore(Position<?> position, E element) throws InvalidAccessorException {
117                    try{return this.insertBefore(this.factory.cast(position),element);}
118                    catch(ClassCastException e){throw new InvalidAccessorException();}
119            }
120    
121        public P insertBefore(P position, E element) throws InvalidAccessorException{
122            this.validate(position);
123                    return this.insertBetween(position.getPrevious(),position,element);
124            }
125    
126            public P insertAfter(Position<?> position, E element) throws InvalidAccessorException {
127                    try{return this.insertAfter(this.factory.cast(position),element);}
128                    catch(ClassCastException e){throw new InvalidAccessorException();}
129            }
130    
131        public P insertAfter(P position, E element) throws InvalidAccessorException{
132            this.validate(position);
133                    return this.insertBetween(position,position.getNext(),element);
134            }
135    
136        public P insert(E element){
137                    return this.insert(element,this.factory.createPosition());
138            }
139    
140        protected P insert(E element, P newPosition){
141                    return this.insertBetween(this.tail.getPrevious(),this.tail,element,newPosition);
142            }
143    
144            public E replace(Position<?> position, E element) throws InvalidAccessorException{
145                    try{return this.replace(this.factory.cast(position),element);}
146                    catch(ClassCastException e){throw new InvalidAccessorException();}
147            }
148    
149            public E replace(P position, E element) throws InvalidAccessorException{
150                    this.validate(position);
151                    return position.replace(position,element);
152            }
153            
154            public E delete(Position<?> position) throws InvalidAccessorException {
155                    try{return this.delete(this.factory.cast(position));}
156                    catch(ClassCastException e){throw new InvalidAccessorException();}
157            }
158    
159        public synchronized E delete(P position) throws InvalidAccessorException{
160            this.validate(position);
161            E element=position.element();
162            P p0=position.getPrevious(), p1=position.getNext();
163            p0.setNext(p1);
164            p1.setPrevious(p0);
165            this.size--;
166            position.notifyAfter();
167            position.notifyBefore();
168            position.locator().setPosition(null);
169            position.setLocator(null);
170            position.setContainer(null);
171            return element;
172        }
173    
174            public void swap(Position<?> position0, Position<?> position1) throws InvalidAccessorException {
175                    try{this.swap(this.factory.cast(position0),this.factory.cast(position1));}
176                    catch(ClassCastException e){throw new InvalidAccessorException();}
177            }
178    
179        public void swap(P position0, P position1) throws InvalidAccessorException{
180            this.validate(position0);
181            this.validate(position1);
182            position0.swap(position0,position1);
183        }
184        
185            public boolean encloses(Position<?> position) {
186                    try{return this.encloses(this.factory.cast(position));}
187                    catch(ClassCastException e){return false;}
188            }
189    
190        public boolean encloses(P position){
191            try{this.validate(position); return true;}
192            catch(InvalidAccessorException e){return false;}
193        }    
194    
195            public E element(Position<?> position){
196                    try{return this.element(this.factory.cast(position));}
197                    catch(ClassCastException e){throw new InvalidAccessorException();}
198            }
199            
200            public E element(P position){
201                    this.validate(position);
202                    return position.element();
203            }
204            
205        protected void validate(P position) throws InvalidAccessorException{
206            if(position==null || this!=position.container()) throw new InvalidAccessorException();
207        }
208        
209            public P position(int rank) throws IndexOutOfBoundsException{
210                    if(rank<0 || this.size<=rank) throw new IndexOutOfBoundsException();
211                    P p=this.head;
212                    for(int i=0;i<=rank;i++) p=p.getNext();
213                    return p;
214            }
215    
216            public int rank(Position<?> position) {
217                    try{return this.rank(this.factory.cast(position));}
218                    catch(ClassCastException e){return -1;}
219            }
220    
221            public int rank(P position){
222            P tmp=this.head.getNext();
223                    for(int rank=0; rank<this.size; rank++,tmp=tmp.getNext()){
224                if(position==tmp) return rank;
225            }
226                    return -1;
227            }
228        
229        public PositionListIterator<E,P> positionListIterator(int rank){
230                    P position;
231                    try{position=this.position(rank);}
232                    catch(IndexOutOfBoundsException e){
233                            if(rank==0 || rank==this.size) position=this.tail;
234                            else throw new IndexOutOfBoundsException();
235                    }
236            return new LinkedPositionIterator<E,P>(this,position.getPrevious(),position);
237        }
238        
239        public PositionListIterator<E,P> positionListIterator(){
240            return this.positionListIterator(0);
241        }
242    
243        public ListIterator<E> listIterator(int index) throws IndexOutOfBoundsException{
244                    P position;
245                    try{position=this.position(index);}
246                    catch(IndexOutOfBoundsException e){
247                            if(index==0 || index==this.size) position=this.tail;
248                            else throw new IndexOutOfBoundsException();
249                    }
250                    return new LinkedElementIterator<E,P>(this,position.getPrevious(),position);
251            }
252    
253            public PositionIterator<E,P> positionIterator(){
254                    return this.positionListIterator();
255            }
256    }
257