001package org.maltparser.parser.history.container;
002
003import java.util.List;
004
005import org.maltparser.core.exception.MaltChainedException;
006import org.maltparser.core.symbol.Table;
007import org.maltparser.core.symbol.TableHandler;
008/**
009*
010* @author Johan Hall
011**/
012public class CombinedTableContainer extends TableContainer implements Table {
013        private final TableHandler tableHandler;
014        private final char separator;
015        private final TableContainer[] containers;
016        private final StringBuilder[] cachedSymbols;
017        private final int[] cachedCodes;
018        
019        public CombinedTableContainer(TableHandler _tableHandler, String _separator, List<TableContainer> _containers, char decisionSeparator) throws MaltChainedException {
020                super(null, null, decisionSeparator);
021                this.tableHandler = _tableHandler;
022                if (_separator.length() > 0) {
023                        this.separator = _separator.charAt(0);
024                } else {
025                        this.separator = '~';
026                };
027                this.containers = new TableContainer[_containers.size()];
028                for (int i = 0; i < _containers.size(); i++) {
029                        this.containers[i] = _containers.get(i);
030                }
031                
032                final StringBuilder sb = new StringBuilder();
033                for (int i = 0; i < this.containers.length; i++) {
034                        sb.append(this.containers[i].getTableContainerName());
035                        sb.append('+');
036                }
037                sb.setLength(sb.length()-1);
038                setTable((Table)tableHandler.addSymbolTable(sb.toString())); 
039                setName(sb.toString());
040                
041                cachedSymbols = new StringBuilder[containers.length];
042                cachedCodes = new int[containers.length];
043                for (int i = 0; i < containers.length; i++) {
044                        cachedCodes[i] = -1;
045                        cachedSymbols[i] = new StringBuilder();
046                };
047        }
048        
049        public void clearCache() {
050                super.clearCache();
051                for (int i = 0; i < cachedCodes.length; i++) {
052                        cachedCodes[i] = -1;
053                }
054                for (int i = 0; i < cachedSymbols.length; i++) {
055                        cachedSymbols[i].setLength(0);
056                }
057        }
058        
059        public int addSymbol(String value) throws MaltChainedException {
060                return table.addSymbol(value);
061        }
062
063        public String getName() {
064                return table.getName();
065        }
066
067        public String getSymbolCodeToString(int code)
068                        throws MaltChainedException {
069                return table.getSymbolCodeToString(code);
070        }
071
072        public int getSymbolStringToCode(String symbol) throws MaltChainedException {
073                return table.getSymbolStringToCode(symbol);
074        }
075        
076        public int getNumberContainers() {
077                return containers.length;
078        }
079        
080        
081        /* override TableContainer */
082        public String getSymbol(int code) throws MaltChainedException {
083                if (code < 0 && !containCode(code)) {
084                        clearCache();
085                        return null;
086                }
087                if (cachedCode != code) {
088                        clearCache();
089                        cachedCode = code;
090                        cachedSymbol.append(table.getSymbolCodeToString(cachedCode));
091                        split();
092                }
093                return cachedSymbol.toString();
094        }
095        
096        public int getCode(String symbol) throws MaltChainedException {
097                if (cachedSymbol == null || !cachedSymbol.equals(symbol)) {
098                        clearCache();
099                        cachedSymbol.append(symbol);
100                        cachedCode = table.getSymbolStringToCode(symbol);
101                        split();
102                }
103                return cachedCode;
104        }
105        
106        public boolean containCode(int code) throws MaltChainedException {
107                if (cachedCode != code) {
108                        clearCache();
109                        cachedSymbol.append(table.getSymbolCodeToString(code));
110                        if (cachedSymbol == null && cachedSymbol.length() == 0) {
111                                return false;
112                        }
113                        cachedCode = code;
114                        split();
115                }
116                return true;
117        }
118        
119        public boolean containSymbol(String symbol) throws MaltChainedException {
120                if (cachedSymbol == null || !cachedSymbol.equals(symbol)) {
121                        clearCache();
122                        cachedCode = table.getSymbolStringToCode(symbol);
123                        if (cachedCode < 0) {
124                                return false;
125                        }
126                        cachedSymbol.append(symbol);
127                        split();
128                }
129                return true;
130        }
131        
132        public int getCombinedCode(List<ActionContainer> codesToCombine) throws MaltChainedException {
133                boolean cachedUsed = true;
134                if (containers.length != codesToCombine.size()) {
135                        clearCache();
136                        return -1;
137                }
138                
139                for (int i = 0; i < containers.length; i++) {
140                        if (codesToCombine.get(i).getActionCode() != cachedCodes[i]) {
141                                cachedUsed = false;
142                                if (codesToCombine.get(i).getActionCode() >= 0 && containers[i].containCode(codesToCombine.get(i).getActionCode())) {
143                                        cachedSymbols[i].setLength(0);
144                                        cachedSymbols[i].append(containers[i].getSymbol(codesToCombine.get(i).getActionCode()));
145                                        cachedCodes[i] = codesToCombine.get(i).getActionCode(); 
146                                } else {
147                                        cachedSymbols[i].setLength(0);
148                                        cachedCodes[i] = -1;
149                                }
150                        }
151                }
152        
153                if (!cachedUsed) {
154                        cachedSymbol.setLength(0);
155                        for (int i = 0; i < containers.length; i++) {
156                                if (cachedSymbols[i].length() != 0) {
157                                        cachedSymbol.append(cachedSymbols[i]);
158                                        cachedSymbol.append(separator);
159                                }
160                        }
161                        if (cachedSymbol.length() > 0) {
162                                cachedSymbol.setLength(cachedSymbol.length()-1);
163                        }
164                        if (cachedSymbol.length() > 0) {
165                                cachedCode = table.addSymbol(cachedSymbol.toString());
166                        } else {
167                                cachedCode = -1;
168                        }
169                }
170                return cachedCode; 
171        }
172        
173        public int getCombinedCode(ActionContainer[] codesToCombine, int start) throws MaltChainedException {
174                boolean cachedUsed = true;
175                if (start < 0 || containers.length > (codesToCombine.length - start)) {
176                        clearCache();
177                        return -1;
178                }
179                
180                for (int i = 0; i < containers.length; i++) {
181                        int code = codesToCombine[i+start].getActionCode();
182                        if (code != cachedCodes[i]) {
183                                cachedUsed = false;
184                                if (code >= 0 && containers[i].containCode(code)) {
185                                        cachedSymbols[i].setLength(0);
186                                        cachedSymbols[i].append(containers[i].getSymbol(code));
187                                        cachedCodes[i] = code; 
188                                } else {
189                                        cachedSymbols[i].setLength(0);
190                                        cachedCodes[i] = -1;
191                                }
192                        }
193                }
194        
195                if (!cachedUsed) {
196                        cachedSymbol.setLength(0);
197                        for (int i = 0; i < containers.length; i++) {
198                                if (cachedSymbols[i].length() != 0) {
199                                        cachedSymbol.append(cachedSymbols[i]);
200                                        cachedSymbol.append(separator);
201                                }
202                        }
203                        if (cachedSymbol.length() > 0) {
204                                cachedSymbol.setLength(cachedSymbol.length()-1);
205                        }
206                        if (cachedSymbol.length() > 0) {
207                                cachedCode = table.addSymbol(cachedSymbol.toString());
208                        } else {
209                                cachedCode = -1;
210                        }
211                }
212                return cachedCode; 
213        }
214        
215        
216        public void setActionContainer(List<ActionContainer> actionContainers, int decision) throws MaltChainedException {
217                if (decision != cachedCode) {
218                        clearCache();
219                        if (decision != -1) {
220                                cachedSymbol.append(table.getSymbolCodeToString(decision));
221                                cachedCode = decision;
222                        }
223                        split();
224                }
225
226                for (int i = 0; i < containers.length; i++) {
227                        if (cachedSymbols[i].length() != 0) {
228                                cachedCodes[i] = actionContainers.get(i).setAction(cachedSymbols[i].toString());
229                        } else {
230                                cachedCodes[i] = actionContainers.get(i).setAction(null);
231                        }
232                }
233        }
234        
235        public void setActionContainer(ActionContainer[] actionContainers, int start, int decision) throws MaltChainedException {
236                if (decision != cachedCode) {
237                        clearCache();
238                        if (decision != -1) {
239                                cachedSymbol.append(table.getSymbolCodeToString(decision));
240                                cachedCode = decision;
241                        }
242                        split();
243                }
244
245                for (int i = 0; i < containers.length; i++) {
246                        if (cachedSymbols[i].length() != 0) {
247                                cachedCodes[i] = actionContainers[i+start].setAction(cachedSymbols[i].toString());
248                        } else {
249                                cachedCodes[i] = actionContainers[i+start].setAction(null);
250                        }
251                }
252        }
253        
254        protected void split() throws MaltChainedException {
255                int j = 0;
256                for (int i = 0; i < containers.length; i++) {
257                        cachedSymbols[i].setLength(0);
258                }
259                for (int i = 0; i < cachedSymbol.length(); i++) {
260                        if (cachedSymbol.charAt(i) == separator) {
261                                j++;
262                        } else {
263                                cachedSymbols[j].append(cachedSymbol.charAt(i));
264                        }
265                }
266                for (int i = j+1; i < containers.length; i++) {
267                        cachedSymbols[i].setLength(0);
268                }
269                for (int i = 0; i < containers.length; i++) {
270                        if (cachedSymbols[i].length() != 0) {
271                                cachedCodes[i] = containers[i].getCode(cachedSymbols[i].toString());
272                        } else {
273                                cachedCodes[i] = -1;
274                        }
275                }
276        }
277
278        public char getSeparator() {
279                return separator;
280        }
281        
282        protected void initSymbolTable() throws MaltChainedException {
283
284        }
285}