001    // This file is part of the Attempto Java Packages.
002    // Copyright 2008-2009, Attempto Group, University of Zurich (see http://attempto.ifi.uzh.ch).
003    //
004    // The Attempto Java Packages is free software: you can redistribute it and/or modify it under the
005    // terms of the GNU Lesser General Public License as published by the Free Software Foundation,
006    // either version 3 of the License, or (at your option) any later version.
007    //
008    // The Attempto Java Packages is distributed in the hope that it will be useful, but WITHOUT ANY
009    // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
010    // PURPOSE. See the GNU Lesser General Public License for more details.
011    //
012    // You should have received a copy of the GNU Lesser General Public License along with the Attempto
013    // Java Packages. If not, see http://www.gnu.org/licenses/.
014    
015    package ch.uzh.ifi.attempto.preditor.text;
016    
017    import java.util.ArrayList;
018    import java.util.Arrays;
019    import java.util.List;
020    
021    import ch.uzh.ifi.attempto.chartparser.Restriction;
022    import ch.uzh.ifi.attempto.chartparser.Terminal;
023    
024    /**
025     * This class describes a text element (a word or phrase) that is used by the
026     * predictive editor. Every text element contains a text and one or more grammatical categories.
027     * If a text element contains more than one categories then this means that it can stand
028     * for any of these categories.
029     * 
030     * @author Tobias Kuhn
031     */
032    public class TextElement {
033            
034            private String text;
035            private ArrayList<Terminal> categories = new ArrayList<Terminal>();
036            private TextContainer textContainer;
037            
038            /**
039             * Creates a new text element with one category.
040             * 
041             * @param text The text.
042             * @param category The category.
043             */
044            public TextElement(String text, Terminal category) {
045                    this.text = text;
046                    this.categories.add(category);
047            }
048            
049            /**
050             * Creates a new text element with the given categories.
051             * 
052             * @param text The text.
053             * @param categories The categories.
054             */
055            public TextElement(String text, List<Terminal> categories) {
056                    this.text = text;
057                    this.categories.addAll(categories);
058            }
059            
060            /**
061             * Creates a new text element.
062             * 
063             * @param text The text.
064             * @param categoryName The name of the category.
065             */
066            public TextElement(String text, String categoryName) {
067                    this(text, new Terminal(categoryName));
068            }
069            
070            /**
071             * Creates a new text element where the text is the name of the category.
072             * 
073             * @param category The category.
074             */
075            public TextElement(Terminal category) {
076                    this(category.getName(), category);
077            }
078            
079            /**
080             * Creates a new text element where the text is the name of the category.
081             * 
082             * @param categoryName The name of the category.
083             */
084            public TextElement(String categoryName) {
085                    this(categoryName, new Terminal(categoryName));
086            }
087            
088            /**
089             * Creates a text element with an empty string as its text and category of the same name.
090             */
091            public TextElement() {
092                    this("");
093            }
094            
095            /**
096             * Creates a new text element containing a number which is also the name of the category.
097             * 
098             * @param number The number.
099             */
100            public TextElement(int number) {
101                    this(number + "", new Terminal(number + ""));
102            }
103            
104            /**
105             * Returns the original text of this text element. This is the unchanged text before it is given
106             * to the context checker.
107             * 
108             * @return The original text (before the context checker).
109             */
110            public String getOriginalText() {
111                    return text;
112            }
113            
114            /**
115             * Returns the text of this text element. The text might have been changed by the context checker.
116             * 
117             * @return The text (after the context checker).
118             */
119            public String getText() {
120                    if (textContainer != null) {
121                            return textContainer.getTextElementText(this);
122                    }
123                    return getOriginalText();
124            }
125            
126            /**
127             * Returns the grammatical category of this text element.
128             * 
129             * @return The grammatical category.
130             */
131            public Terminal[] getCategories() {
132                    return (Terminal[]) categories.toArray(new Terminal[0]);
133            }
134            
135            void setTextContainer(TextContainer textContainer) {
136                    this.textContainer = textContainer;
137            }
138            
139            void removeTextContainer() {
140                    this.textContainer = null;
141            }
142            
143            /**
144             * Applies the given restriction by excluding all categories that are not fulfilled by the
145             * restriction. The return value indicates whether this text elements fulfills the
146             * restriction which is the case if and only if at least one category is left. 
147             * 
148             * @param restr The restriction to be applied.
149             * @return true if the restrictions is altogether fulfilled, i.e. if at least one category
150             *   fulfills the restriction.
151             */
152            public final boolean applyRestriction(Restriction restr) {
153                    List<Terminal> categories = new ArrayList<Terminal>(Arrays.asList(getCategories()));
154                    if (restr == null) return true;
155                    for (Terminal t : new ArrayList<Terminal>(categories)) {
156                            if (!restr.isFulfilledBy(t)) categories.remove(t);
157                    }
158                    return (!categories.isEmpty());
159            }
160            
161            /**
162             * Sets the feature "id" for all categories.
163             * 
164             * @param id The id value.
165             */
166            public void setID(int id) {
167                    for (Terminal t : categories) {
168                            t.setFeature("id", id + "");
169                    }
170            }
171            
172            /**
173             * Includes the categories of the given text element. This is only allowed if the two
174             * text elements are equal (accoring to the equals-method).
175             * 
176             * @param textElement The text element whose categories should be included.
177             */
178            public void include(TextElement textElement) {
179                    if (!equals(textElement)) {
180                            throw new RuntimeException("Only equal text elements can be included");
181                    }
182                    categories.addAll(textElement.categories);
183            }
184            
185            /**
186             * Two text elements are equals if they share the same text.
187             */
188            public boolean equals(Object obj) {
189                    if (obj instanceof TextElement) {
190                            TextElement other = (TextElement) obj;
191                            return (this.text.equals(other.text));
192                    }
193                    return false;
194            }
195            
196            public String toString() {
197                    return text;
198            }
199    
200    }