package org.simantics.spreadsheet.graph.formula; import org.simantics.databoard.binding.mutable.Variant; import org.simantics.spreadsheet.graph.CellFormulaFunction; import org.simantics.spreadsheet.graph.CellValueVisitor; import org.simantics.spreadsheet.graph.SpreadsheetGraphUtils; import org.simantics.spreadsheet.graph.SpreadsheetMatrix; import org.simantics.spreadsheet.graph.parser.ast.AstArgList; public class MatchFormulaFunction implements CellFormulaFunction{ @Override public Object evaluate(CellValueVisitor visitor, AstArgList args) { if (args.values.size() < 2 || args.values.size() > 3) throw new IllegalStateException(); SpreadsheetMatrix lookup_array = (SpreadsheetMatrix) args.values.get(1).accept(visitor); if(lookup_array.getWidth()!=1 && lookup_array.getHeight()!=1) return FormulaError2.NA.getString(); Object lookup_value = args.values.get(0).accept(visitor); int match_type = 1; try{ if(args.values.size()==3){ int matchArg = ((Number)args.values.get(2).accept(visitor)).intValue(); if(matchArg<0) match_type = -1; else if(matchArg>0) match_type = 1; else match_type = 0; } } catch(Exception e) { return FormulaError2.NA.getString(); } boolean useHeight = false; if(lookup_array.getWidth()==1) useHeight = true; int max = 0; if(useHeight) max = lookup_array.getHeight(); else max = lookup_array.getWidth(); Integer pos = null; if(lookup_value instanceof Variant){ Object obj = ((Variant)lookup_value).getValue(); Number nVal = SpreadsheetGraphUtils.asValidNumber(obj); if(nVal!=null) obj = nVal; else obj = obj.toString(); } if(lookup_value instanceof Number){ Double previousValue = null; Double closestMatch = null; Double lookup = ((Number)lookup_value).doubleValue(); int indexWhereCorrectOrderStartsAt = 0; if(match_type!=0) { for(int i = 0; i < max;i++){ Double currValue = null; Number currNum; if(useHeight){ currNum = SpreadsheetGraphUtils.asValidNumber(lookup_array.get(i,0)); } else { currNum = SpreadsheetGraphUtils.asValidNumber(lookup_array.get(0,i)); } if(currNum!=null){ currValue = currNum.doubleValue(); if(currValue != null){ if(previousValue!=null){ if((match_type==-1 && currValue>previousValue) || (match_type==1 && currValuepreviousValue) || (match_type==1 && currValue 0 && match_type==1) || (comp<0 && match_type==-1)){ if(closestMatch==null && pos==null){ closestMatch = currValue; pos = i; } else if((currValue.compareTo(closestMatch)>=0 && match_type==1) || (currValue.compareTo(closestMatch)<=0 && match_type==-1)){ closestMatch = currValue; pos = i; } } previousValue = currValue; } } } } else if(lookup_value instanceof String){ String previousValue = null; String closestMatch = null; String lookup = (String)lookup_value; int indexWhereCorrectOrderStartsAt = 0; if(match_type!=0) { for(int i = 0; i < max;i++){ String currValue = null; Object obj; if(useHeight){ obj = lookup_array.get(i,0); } else { obj = lookup_array.get(0,i); } if(obj instanceof Variant){ obj = ((Variant)obj).getValue(); } if(obj!=null && !(obj instanceof Number)){ currValue = obj.toString(); currValue = currValue.toLowerCase(); } if(currValue != null && !currValue.equals("")){ if(previousValue!=null){ if((match_type==-1 && currValue.compareTo(previousValue)>0) || (match_type==1 && currValue.compareTo(previousValue)<0)) indexWhereCorrectOrderStartsAt = i; else break; } previousValue = currValue; } } } int begin = indexWhereCorrectOrderStartsAt; for(int i = begin; i < max;i++){ String currValue = null; Object obj; if(useHeight){ obj = lookup_array.get(i,0); } else { obj = lookup_array.get(0,i); } if(obj instanceof Variant){ obj = ((Variant)obj).getValue(); } if(obj!=null && !(obj instanceof Number)){ currValue = obj.toString(); currValue = currValue.toLowerCase(); } if(currValue != null && !currValue.equals("")){ if(previousValue==null) previousValue = currValue; if((match_type==-1 && currValue.compareTo(previousValue)>0) || (match_type==1 && currValue.compareTo(previousValue)<0)){ if(pos!=null) return pos+1; previousValue = currValue; } int comp = lookup.compareTo(currValue); if(comp == 0){ closestMatch = currValue; pos = i; } else if((comp > 0 && match_type==1) || (comp<0 && match_type==-1)){ if(closestMatch==null && pos==null){ closestMatch = currValue; pos = i; } else if((currValue.compareTo(closestMatch)>=0 && match_type==1) || (currValue.compareTo(closestMatch)<=0 && match_type==-1)){ closestMatch = currValue; pos = i; } } previousValue = currValue; } } } if(pos==null)return FormulaError2.NA.getString(); return pos+1; } }