001/* Copyright (C) 2013 TU Dortmund
002 * This file is part of AutomataLib, http://www.automatalib.net/.
003 * 
004 * AutomataLib is free software; you can redistribute it and/or
005 * modify it under the terms of the GNU Lesser General Public
006 * License version 3.0 as published by the Free Software Foundation.
007 * 
008 * AutomataLib is distributed in the hope that it will be useful,
009 * but WITHOUT ANY WARRANTY; without even the implied warranty of
010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
011 * Lesser General Public License for more details.
012 * 
013 * You should have received a copy of the GNU Lesser General Public
014 * License along with AutomataLib; if not, see
015 * http://www.gnu.de/documents/lgpl.en.html.
016 */
017package net.automatalib.words.impl;
018
019import java.util.NoSuchElementException;
020import java.util.Objects;
021
022import net.automatalib.words.Word;
023
024public class ExtensionWord<I> extends Word<I> {
025        
026        private static final class Iterator<I> implements java.util.Iterator<I> {
027                private final java.util.Iterator<I> wordIt;
028                private final I letter;
029                private boolean next = true;
030                
031                public Iterator(java.util.Iterator<I> wordIt, I letter) {
032                        this.wordIt = wordIt;
033                        this.letter = letter;
034                }
035                
036                @Override
037                public boolean hasNext() {
038                        return next;
039                }
040                @Override
041                public I next() {
042                        if(wordIt.hasNext())
043                                return wordIt.next();
044                        if(!next)
045                                throw new NoSuchElementException();
046                        next = false;
047                        return letter;
048                }
049                
050                @Override
051                public void remove() {
052                        throw new UnsupportedOperationException();
053                }
054                
055                
056        }
057        
058        private final Word<I> word;
059        private final I letter;
060        
061        public ExtensionWord(Word<I> word, I letter) {
062                this.word = word;
063                this.letter = letter;
064        }
065
066        @Override
067        public I getSymbol(int index) {
068                if(index == word.length())
069                        return letter;
070                return word.getSymbol(index);
071        }
072
073        @Override
074        public int length() {
075                return word.length() + 1;
076        }
077
078        @Override
079        protected Word<I> _subWord(int fromIndex, int toIndex) {
080                int wLen = word.length();
081                if(fromIndex < wLen) {
082                        if(toIndex <= wLen)
083                                word.subWord(fromIndex, toIndex);
084                        return new ExtensionWord<>(word.subWord(fromIndex, wLen), letter);
085                }
086                else if(fromIndex == wLen)
087                        return Word.fromLetter(letter);
088                return Word.epsilon();
089        }
090
091        @Override
092        public java.util.Iterator<I> iterator() {
093                return new Iterator<I>(word.iterator(), letter);
094        }
095
096        @Override
097        public void writeToArray(int offset, Object[] array, int tgtOffset,
098                        int length) {
099                int wordLen = word.length();
100                boolean writeLetter = (offset + length > wordLen);
101                if(offset < wordLen) {
102                        if(writeLetter)
103                                length--;
104                        word.writeToArray(offset, array, tgtOffset, length);
105                }
106                if(writeLetter)
107                        array[tgtOffset+length] = letter;
108        }
109
110        @Override
111        public Word<I> prepend(I symbol) {
112                return new ExtensionWord<>(word.prepend(symbol), letter);
113        }
114
115        @Override
116        public boolean isPrefixOf(Word<I> other) {
117                int wordLen = word.length();
118                if(wordLen >= other.length())
119                        return false;
120                
121                if(!word.isPrefixOf(other))
122                        return false;
123                return Objects.equals(other.getSymbol(wordLen), letter);
124        }
125
126}