001package org.maltparser.core.feature.map;
002
003
004import org.maltparser.core.exception.MaltChainedException;
005import org.maltparser.core.feature.FeatureException;
006import org.maltparser.core.feature.function.FeatureFunction;
007import org.maltparser.core.feature.function.FeatureMapFunction;
008import org.maltparser.core.feature.value.FeatureValue;
009import org.maltparser.core.feature.value.SingleFeatureValue;
010import org.maltparser.core.io.dataformat.ColumnDescription;
011import org.maltparser.core.symbol.SymbolTable;
012import org.maltparser.core.symbol.SymbolTableHandler;
013/**
014*
015*
016* @author Johan Hall
017*/
018public final class MergeFeature implements FeatureMapFunction {
019        public final static Class<?>[] paramTypes = { org.maltparser.core.feature.function.FeatureFunction.class, org.maltparser.core.feature.function.FeatureFunction.class };
020        private FeatureFunction firstFeature;
021        private FeatureFunction secondFeature;
022        private final SymbolTableHandler tableHandler;
023        private SymbolTable table;
024        private final SingleFeatureValue singleFeatureValue;
025        private int type;
026        
027        
028        public MergeFeature(SymbolTableHandler tableHandler) throws MaltChainedException {
029                this.tableHandler = tableHandler;
030                this.singleFeatureValue = new SingleFeatureValue(this);
031        }
032        
033        public void initialize(Object[] arguments) throws MaltChainedException {
034                if (arguments.length != 2) {
035                        throw new FeatureException("Could not initialize MergeFeature: number of arguments are not correct. ");
036                }
037                if (!(arguments[0] instanceof FeatureFunction)) {
038                        throw new FeatureException("Could not initialize MergeFeature: the first argument is not a feature. ");
039                }
040                if (!(arguments[1] instanceof FeatureFunction)) {
041                        throw new FeatureException("Could not initialize MergeFeature: the second argument is not a feature. ");
042                }
043                setFirstFeature((FeatureFunction)arguments[0]);
044                setSecondFeature((FeatureFunction)arguments[1]);
045
046                if (firstFeature.getType() != secondFeature.getType()) {
047                        throw new FeatureException("Could not initialize MergeFeature: the first and the second arguments are not of the same type.");
048                }
049                this.type = firstFeature.getType();
050                setSymbolTable(tableHandler.addSymbolTable("MERGE2_"+firstFeature.getMapIdentifier()+"_"+secondFeature.getMapIdentifier(), ColumnDescription.INPUT, ColumnDescription.STRING, "One"));
051        }
052        
053        public void update() throws MaltChainedException {
054                singleFeatureValue.reset();
055                firstFeature.update();
056                secondFeature.update();
057                FeatureValue firstValue = firstFeature.getFeatureValue();
058                FeatureValue secondValue = secondFeature.getFeatureValue();
059                if (firstValue.isMultiple() || secondValue.isMultiple()) {
060                        throw new FeatureException("It is not possible to merge Split-features. ");
061                }
062
063                String firstSymbol = ((SingleFeatureValue)firstValue).getSymbol();
064                if (firstValue.isNullValue() && secondValue.isNullValue()) {
065                        singleFeatureValue.setIndexCode(firstFeature.getSymbolTable().getSymbolStringToCode(firstSymbol));
066                        singleFeatureValue.setSymbol(firstSymbol);
067                        singleFeatureValue.setNullValue(true);
068                        return;
069                } 
070                if (getType() == ColumnDescription.STRING) { 
071                        StringBuilder mergedValue = new StringBuilder();
072                        mergedValue.append(firstSymbol);
073                        mergedValue.append('~');
074                        mergedValue.append(((SingleFeatureValue)secondValue).getSymbol());
075                        singleFeatureValue.setIndexCode(table.addSymbol(mergedValue.toString()));
076                        singleFeatureValue.setSymbol(mergedValue.toString());
077                        singleFeatureValue.setNullValue(false);
078                        singleFeatureValue.setValue(1);
079                } else {
080                        if (firstValue.isNullValue() || secondValue.isNullValue()) {
081                                singleFeatureValue.setValue(0);
082                                table.addSymbol("#null#");
083                                singleFeatureValue.setSymbol("#null#");
084                                singleFeatureValue.setNullValue(true);
085                                singleFeatureValue.setIndexCode(1);
086                        } else {
087                                if (getType() == ColumnDescription.BOOLEAN) {
088                                        boolean result = false;
089                                        int dotIndex = firstSymbol.indexOf('.');
090                                        result = firstSymbol.equals("1") || firstSymbol.equals("true") ||  firstSymbol.equals("#true#") || (dotIndex != -1 && firstSymbol.substring(0,dotIndex).equals("1"));
091                                        if (result == true) {
092                                                String secondSymbol = ((SingleFeatureValue)secondValue).getSymbol();
093                                                dotIndex = secondSymbol.indexOf('.');
094                                                result = secondSymbol.equals("1") || secondSymbol.equals("true") ||  secondSymbol.equals("#true#") || (dotIndex != -1 && secondSymbol.substring(0,dotIndex).equals("1"));
095                                        }
096                                        if (result) {
097                                                singleFeatureValue.setValue(1);
098                                                table.addSymbol("true");
099                                                singleFeatureValue.setSymbol("true");
100                                        } else {
101                                                singleFeatureValue.setValue(0);
102                                                table.addSymbol("false");
103                                                singleFeatureValue.setSymbol("false");
104                                        }
105                                } else if (getType() == ColumnDescription.INTEGER) {
106                                        Integer firstInt = 0;
107                                        Integer secondInt = 0;
108                                        
109                                        int dotIndex = firstSymbol.indexOf('.');
110                                        try {
111                                                if (dotIndex == -1) {
112                                                        firstInt = Integer.parseInt(firstSymbol);
113                                                } else {
114                                                        firstInt = Integer.parseInt(firstSymbol.substring(0,dotIndex));
115                                                }
116                                        } catch (NumberFormatException e) {
117                                                throw new FeatureException("Could not cast the feature value '"+firstSymbol+"' to integer value.", e);
118                                        }
119                                        String secondSymbol = ((SingleFeatureValue)secondValue).getSymbol();
120                                        dotIndex = secondSymbol.indexOf('.');
121                                        try {
122                                                if (dotIndex == -1) {
123                                                        secondInt = Integer.parseInt(secondSymbol);
124                                                } else {
125                                                        secondInt = Integer.parseInt(secondSymbol.substring(0,dotIndex));
126                                                }
127                                        } catch (NumberFormatException e) {
128                                                throw new FeatureException("Could not cast the feature value '"+secondSymbol+"' to integer value.", e);
129                                        }
130                                        Integer result = firstInt*secondInt;
131                                        singleFeatureValue.setValue(result);
132                                        table.addSymbol(result.toString());
133                                        singleFeatureValue.setSymbol(result.toString());
134                                } else if (getType() == ColumnDescription.REAL) {
135                                        Double firstReal = 0.0;
136                                        Double secondReal = 0.0;
137                                        try {
138                                                firstReal = Double.parseDouble(firstSymbol);
139                                        } catch (NumberFormatException e) {
140                                                throw new FeatureException("Could not cast the feature value '"+firstSymbol+"' to real value.", e);
141                                        }
142                                        String secondSymbol = ((SingleFeatureValue)secondValue).getSymbol();
143                                        try {
144                                                secondReal = Double.parseDouble(secondSymbol);
145                                        } catch (NumberFormatException e) {
146                                                throw new FeatureException("Could not cast the feature value '"+secondSymbol+"' to real value.", e);
147                                        }
148                                        Double result = firstReal*secondReal;
149                                        singleFeatureValue.setValue(result);
150                                        table.addSymbol(result.toString());
151                                        singleFeatureValue.setSymbol(result.toString());
152                                }
153                                singleFeatureValue.setNullValue(false);
154                                singleFeatureValue.setIndexCode(1);
155                        }
156                }
157        }
158        
159        public Class<?>[] getParameterTypes() {
160                return paramTypes; 
161        }
162
163        public FeatureValue getFeatureValue() {
164                return singleFeatureValue;
165        }
166
167        public String getSymbol(int code) throws MaltChainedException {
168                return table.getSymbolCodeToString(code);
169        }
170        
171        public int getCode(String symbol) throws MaltChainedException {
172                return table.getSymbolStringToCode(symbol);
173        }
174        
175        public FeatureFunction getFirstFeature() {
176                return firstFeature;
177        }
178
179        public void setFirstFeature(FeatureFunction firstFeature) {
180                this.firstFeature = firstFeature;
181        }
182
183        public FeatureFunction getSecondFeature() {
184                return secondFeature;
185        }
186
187        public void setSecondFeature(FeatureFunction secondFeature) {
188                this.secondFeature = secondFeature;
189        }
190
191        public SymbolTableHandler getTableHandler() {
192                return tableHandler;
193        }
194
195        public SymbolTable getSymbolTable() {
196                return table;
197        }
198
199        public void setSymbolTable(SymbolTable table) {
200                this.table = table;
201        }
202        
203        public int getType() {
204                return type;
205        }
206
207        public String getMapIdentifier() {
208                return getSymbolTable().getName();
209        }
210        
211        public boolean equals(Object obj) {
212                if (this == obj)
213                        return true;
214                if (obj == null)
215                        return false;
216                if (getClass() != obj.getClass())
217                        return false;
218                return obj.toString().equals(this.toString());
219        }
220        
221        public String toString() {
222                final StringBuilder sb = new StringBuilder();
223                sb.append("Merge(");
224                sb.append(firstFeature.toString());
225                sb.append(", ");
226                sb.append(secondFeature.toString());
227                sb.append(')');
228                return sb.toString();
229        }
230        
231}