001package org.maltparser.core.syntaxgraph;
002
003import java.util.LinkedHashSet;
004import java.util.Observable;
005import java.util.Set;
006
007import org.maltparser.core.exception.MaltChainedException;
008import org.maltparser.core.symbol.SymbolTable;
009
010/**
011*
012*
013* @author Johan Hall
014*/
015public abstract class GraphElement extends Observable implements Element {
016        private LabeledStructure belongsToGraph;
017        private LabelSet labelSet;
018
019        public GraphElement() {
020                belongsToGraph = null;
021                labelSet = null;
022        }
023        
024        /**
025         * Adds a label (a string value) to the symbol table and to the graph element. 
026         * 
027         * @param table the symbol table
028         * @param symbol a label symbol
029         * @throws MaltChainedException
030         */
031        public void addLabel(SymbolTable table, String symbol) throws MaltChainedException {
032                table.addSymbol(symbol);
033                addLabel(table, table.getSymbolStringToCode(symbol));
034        }
035        
036        /**
037         * Adds a label (an integer value) to the symbol table and to the graph element.
038         * 
039         * @param table the symbol table
040         * @param code a label code
041         * @throws MaltChainedException
042         */
043        public void addLabel(SymbolTable table, int code) throws MaltChainedException {
044                if (table.getSymbolCodeToString(code) != null) {                
045                        if (labelSet == null) {
046                                if (belongsToGraph == null) {
047                                        throw new SyntaxGraphException("The graph element doesn't belong to any graph. ");
048                                }
049                                labelSet = belongsToGraph.checkOutNewLabelSet();
050                        }
051                        labelSet.put(table, code);
052                        setChanged(); 
053                        notifyObservers(table);
054                }
055        }
056        
057        /**
058         * Adds the labels of the label set to the label set of the graph element.
059         * 
060         * @param labels a label set.
061         * @throws MaltChainedException
062         */
063        public void addLabel(LabelSet labels) throws MaltChainedException {
064                if (labels != null) {
065                        for (SymbolTable table : labels.keySet()) {
066                                addLabel(table, labels.get(table));
067                        }
068                }
069        }
070        
071        /**
072         * Returns <i>true</i> if the graph element has a label for the symbol table, otherwise <i>false</i>.
073         * 
074         * @param table the symbol table
075         * @return <i>true</i> if the graph element has a label for the symbol table, otherwise <i>false</i>.
076         * @throws MaltChainedException
077         */
078        public boolean hasLabel(SymbolTable table) throws MaltChainedException {
079                if (labelSet != null) {
080                        return labelSet.containsKey(table);
081                }
082                return false;
083        }
084        
085        /**
086         * Returns the label symbol(a string representation) of the symbol table if it exists, otherwise 
087         * an exception is thrown.
088         * 
089         * @param table the symbol table
090         * @return the label (a string representation) of the symbol table if it exists.
091         * @throws MaltChainedException
092         */
093        public String getLabelSymbol(SymbolTable table) throws MaltChainedException {
094                Integer code = labelSet.get(table);
095                if (code == null) {
096                        throw new SyntaxGraphException("No label symbol available for label '"+table.getName()+"'.");
097                }
098                return table.getSymbolCodeToString(code);
099        }
100        
101        /**
102         * Returns the label code (an integer representation) of the symbol table if it exists, otherwise 
103         * an exception is thrown.
104         * 
105         * @param table the symbol table
106         * @return the label code (an integer representation) of the symbol table if it exists
107         * @throws MaltChainedException
108         */
109        public int getLabelCode(SymbolTable table) throws MaltChainedException {
110                Integer code = labelSet.get(table);
111                if (code == null) {
112                        throw new SyntaxGraphException("No label symbol available for label '"+table.getName()+"'.");
113                }
114//              if (code != null) {
115//                      return -1;
116//              }
117                return code.intValue();
118        }
119        
120        /**
121         * Returns <i>true</i> if the graph element has one or more labels, otherwise <i>false</i>.
122         * 
123         * @return <i>true</i> if the graph element has one or more labels, otherwise <i>false</i>.
124         */
125        public boolean isLabeled() {
126                if (labelSet == null) {
127                        return false;
128                }
129                return labelSet.size() > 0;
130        }
131        
132        /**
133         * Returns the number of labels of the graph element.
134         * 
135         * @return the number of labels of the graph element.
136         */
137        public int nLabels() {
138                if (labelSet == null) {
139                        return 0;
140                }
141                return labelSet.size();
142        }
143        
144        /**
145         * Returns a set of symbol tables (labeling functions or label types) that labels the graph element.
146         * 
147         * @return a set of symbol tables (labeling functions or label types)
148         */
149        public Set<SymbolTable> getLabelTypes() {
150                if (labelSet == null) {
151                        return new LinkedHashSet<SymbolTable>();
152                }
153                return labelSet.keySet();
154        }
155        
156        /**
157         * Returns the label set.
158         * 
159         * @return the label set.
160         */
161        public LabelSet getLabelSet() {
162                return labelSet;
163        }
164        
165        public void removeLabel(SymbolTable table) throws MaltChainedException {
166                if (labelSet != null) {
167                        labelSet.remove(table);
168                }
169        }
170        
171        public void removeLabels() throws MaltChainedException {
172                if (labelSet != null && belongsToGraph != null) {
173                        belongsToGraph.checkInLabelSet(labelSet);
174                }
175                labelSet = null;
176        }
177        
178        /**
179         * Returns the graph (structure) in which the graph element belongs to. 
180         * 
181         * @return the graph (structure) in which the graph element belongs to. 
182         */
183        public LabeledStructure getBelongsToGraph() {
184                return belongsToGraph;
185        }
186        
187        /**
188         * Sets the graph (structure) in which the graph element belongs to. 
189         * 
190         * @param belongsToGraph a graph (structure).
191         */
192        public void setBelongsToGraph(LabeledStructure belongsToGraph) {
193                this.belongsToGraph = belongsToGraph;
194                addObserver((SyntaxGraph)belongsToGraph);
195        }
196        
197
198        /**
199         * Resets the graph element.
200         * 
201         * @throws MaltChainedException
202         */
203        public void clear() throws MaltChainedException {
204                if (labelSet != null && belongsToGraph != null) {
205                        belongsToGraph.checkInLabelSet(labelSet);
206                }
207                labelSet = null;
208                deleteObserver((SyntaxGraph)belongsToGraph);
209                belongsToGraph = null;
210        }
211        
212        public boolean equals(Object obj) {
213                GraphElement ge = (GraphElement)obj;
214                return belongsToGraph == ge.getBelongsToGraph() && labelSet == null ? ge.getLabelSet() == null : labelSet.equals(ge.getLabelSet()); 
215        }
216        
217        public int hashCode() {
218                int hash = 7;
219                hash = 31 * hash + (null == belongsToGraph ? 0 : belongsToGraph.hashCode());
220                return 31 * hash + (null == labelSet ? 0 : labelSet.hashCode());
221        }
222        
223        public int compareTo(GraphElement o) {
224                final int BEFORE = -1;
225            final int EQUAL = 0;
226            final int AFTER = 1;
227            if ( this == o ) return EQUAL;
228                
229            if (this.labelSet == null && o.labelSet != null) return BEFORE;
230            if (this.labelSet != null && o.labelSet == null) return AFTER;
231            if (this.labelSet == null && o.labelSet == null) return EQUAL;
232            
233            int comparison = EQUAL;
234                for (SymbolTable table : labelSet.keySet()) {
235                        Integer ocode = o.labelSet.get(table);
236                        Integer tcode = labelSet.get(table);
237                        if (ocode != null && tcode != null) {
238                                if (!ocode.equals(tcode)) {
239                                        try {
240                                                comparison = table.getSymbolCodeToString(tcode).compareTo(table.getSymbolCodeToString(ocode));
241                                                if ( comparison != EQUAL ) return comparison;
242                                        } catch (MaltChainedException e) { }
243                                }
244                        }
245                }
246                return EQUAL;
247        }
248        
249        public String toString() {
250                final StringBuilder sb = new StringBuilder();
251                if (labelSet != null) {
252                        for (SymbolTable table : labelSet.keySet()) {
253                                try {
254                                        sb.append(table.getName());
255                                        sb.append(':');
256                                        sb.append(getLabelSymbol(table));
257                                } catch (MaltChainedException e) {
258                                        System.err.println("Print error : "+e.getMessageChain());
259                                }
260                                sb.append(' ');
261                        }
262                }
263                return sb.toString();
264        }
265}