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 VlookupFormulaFunction implements CellFormulaFunction { @Override public Object evaluate(CellValueVisitor visitor, AstArgList args) { if (args.values.size() < 3 || args.values.size() > 4) throw new IllegalStateException(); Object lookupValue = args.values.get(0).accept(visitor); boolean lookupIsString = lookupValue instanceof String; FormulaError2 error = FormulaError2.forObject(lookupValue); if(error!=null) return error.getString(); if(lookupValue instanceof Variant){ Object varVal = ((Variant)lookupValue).getValue(); Double dVal = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(varVal); if(dVal==null) { lookupValue = varVal.toString(); lookupIsString = true; } else lookupValue = dVal; } SpreadsheetMatrix array = (SpreadsheetMatrix) args.values.get(1).accept(visitor); boolean approximateMatch = args.values.size() == 4 ? (Boolean) args.values.get(3).accept(visitor) : true; boolean valueExists = false; if(array.values.length != 0){ for(int i = 0; i < array.getHeight(); i++){ if(lookupIsString){ Object obj = array.get(i,0); if(obj instanceof Variant) obj = ((Variant)obj).getValue(); if(obj!=null && SpreadsheetGraphUtils.asValidNumber(obj)==null){ obj = obj.toString(); String valStr = ((String)obj).toLowerCase(); if((lookupValue.toString().toLowerCase()).compareTo(valStr)>=0 ){ valueExists = true; break; } } } else if(lookupValue instanceof Number){ Double d = ((Number)lookupValue).doubleValue(); Number d2 = SpreadsheetGraphUtils.asValidNumber(array.get(i,0)); if(d2!=null && d>=(d2.doubleValue())){ valueExists = true; break; } } } // if(lookupIsString){ // Object obj = array.values[0]; // if(obj instanceof Variant) // obj = ((Variant)obj).getValue(); // if(SpreadsheetGraphUtils.asValidNumber(obj)!=null) // return FormulaError2.NA.getString(); // obj = obj.toString(); // String valStr = ((String)obj).toLowerCase(); // if((lookupValue.toString().toLowerCase()).compareTo(valStr)<0 ) // return FormulaError2.NA.getString(); // } // else if(lookupValue instanceof Number){ // Double d = ((Number)lookupValue).doubleValue(); // Number d2 = SpreadsheetGraphUtils.asValidNumber(array.values[0]); // if(d2==null || d<(d2.doubleValue())) // return FormulaError2.NA.getString(); // } } if(!valueExists) return FormulaError2.NA.getString(); Number colIndexN = SpreadsheetGraphUtils.asValidNumber(args.values.get(2).accept(visitor)); if(colIndexN==null) return FormulaError2.REF.getString(); int colIndexNum = colIndexN.intValue(); if(colIndexNum>array.getWidth()) return FormulaError2.REF.getString(); if (approximateMatch) { Integer rowPosOfLargestValSmallerThanLookUp = null; if(lookupIsString){ String ref = lookupValue.toString().toLowerCase(); String previousValue = null; String largestValSmallerThanLookUp = null; for(int i = 0; i < array.getHeight(); i++){ Object val = array.get(i, 0); if(val instanceof Variant) val = ((Variant)val).getValue(); String currValue = val.toString().toLowerCase(); if(currValue.compareTo(ref)>0){ if(i==0) return array.get(i, colIndexNum-1); else if(previousValue.compareTo(ref) > currValue.compareTo(ref)) return array.get(i, colIndexNum-1); else return array.get(i - 1, colIndexNum - 1); } if(rowPosOfLargestValSmallerThanLookUp==null){ rowPosOfLargestValSmallerThanLookUp = i; largestValSmallerThanLookUp = currValue; } else if(largestValSmallerThanLookUp.compareTo(currValue)<0){ rowPosOfLargestValSmallerThanLookUp = i; largestValSmallerThanLookUp = currValue; } previousValue = currValue; } } else { double ref = SpreadsheetGraphUtils.asNumber(lookupValue); double lastDiff = Double.MIN_VALUE; Double largestValSmallerThanLookUp = null; for (int i = 0; i < array.getHeight(); i++) { Object value = array.get(i, 0); double n = SpreadsheetGraphUtils.asNumber(value); double diff = n - ref; if (diff > 0) { if (i == 0) return array.get(i, colIndexNum - 1); else if (diff < -lastDiff) return array.get(i, colIndexNum - 1); else return array.get(i - 1, colIndexNum - 1); } if(rowPosOfLargestValSmallerThanLookUp==null){ rowPosOfLargestValSmallerThanLookUp = i; largestValSmallerThanLookUp = n; } else if(largestValSmallerThanLookUp < n){ rowPosOfLargestValSmallerThanLookUp = i; largestValSmallerThanLookUp = n; } lastDiff = diff; } } if(rowPosOfLargestValSmallerThanLookUp!=null) return array.get(rowPosOfLargestValSmallerThanLookUp, colIndexNum - 1); } else { for (int i = 0; i < array.getHeight(); i++) { Object value = array.get(i, 0); if(value instanceof Variant){ if(lookupIsString) value = ((Variant)value).getValue().toString(); else value = SpreadsheetGraphUtils.asNumber(value); } if (SpreadsheetGraphUtils.excelEquals(lookupValue, value)) { return array.get(i, colIndexNum - 1); } } } return FormulaError2.NA.getString(); } }