package org.n3r.eql.param;
import com.google.common.base.Objects;
import lombok.SneakyThrows;
import lombok.val;
import org.n3r.eql.ex.EqlExecuteException;
import org.n3r.eql.map.EqlRun;
import org.n3r.eql.param.EqlParamPlaceholder.InOut;
import org.n3r.eql.util.Names;
import java.util.ArrayList;
import java.util.List;
public class EqlParamsBinder {
private EqlRun eqlRun;
private List<Object> boundParams;
private boolean hasIterateOption;
private enum ParamExtra {
Extra, Normal
}
public void prepareBindParams(boolean hasIterateOption, EqlRun eqlRun) {
this.hasIterateOption = hasIterateOption;
this.eqlRun = eqlRun;
eqlRun.setIterateOption(hasIterateOption);
boundParams = new ArrayList<Object>();
switch (eqlRun.getPlaceHolderType()) {
case AUTO_SEQ:
for (int i = 0; i < eqlRun.getPlaceholderNum(); ++i)
setParam(i, getParamByIndex(i), ParamExtra.Normal);
break;
case MANU_SEQ:
for (int i = 0; i < eqlRun.getPlaceholderNum(); ++i)
setParam(i, findParamBySeq(i + 1), ParamExtra.Normal);
break;
case VAR_NAME:
for (int i = 0; i < eqlRun.getPlaceholderNum(); ++i)
setParam(i, findParamByName(i), ParamExtra.Normal);
break;
default:
break;
}
bindExtraParams();
eqlRun.setBoundParams(boundParams);
}
private void bindExtraParams() {
Object[] extraBindParams = eqlRun.getExtraBindParams();
if (extraBindParams == null) return;
int i = eqlRun.getPlaceholderNum();
int ii = eqlRun.getPlaceholderNum() + extraBindParams.length;
for (; i < ii; ++i) {
val extraParam = extraBindParams[i - eqlRun.getPlaceholderNum()];
setParam(i, extraParam, ParamExtra.Extra);
}
}
private void setParam(int index, Object value, ParamExtra extra) {
val placeHolder = eqlRun.getPlaceHolder(index);
switch (extra) {
case Extra:
setParamValue(placeHolder, index, value);
break;
default:
setParamEx(placeHolder, index, value);
break;
}
}
@SneakyThrows
private void setParamValue(EqlParamPlaceholder placeHolder, int index, Object value) {
if (hasIterateOption) {
List<Object> values = (List<Object>) value;
Object[] boundParam = new Object[values.size()];
Object[] paramsValue = new Object[boundParam.length];
for (int i = 0, ii = boundParam.length; i < ii; ++i) {
val paramValueDealer = new ParamValueDealer(placeHolder);
paramValueDealer.dealSingleValue(values.get(i));
boundParam[i] = paramValueDealer.getBoundParam();
paramsValue[i] = paramValueDealer.getParamValue();
}
boundParams.add(boundParam);
eqlRun.addRealParam(index + 1, paramsValue);
} else {
val paramValDealer = new ParamValueDealer(placeHolder);
paramValDealer.dealSingleValue(value);
boundParams.add(paramValDealer.getBoundParam());
eqlRun.addRealParam(index + 1, paramValDealer.getParamValue());
}
}
private void setParamEx(EqlParamPlaceholder placeHolder, int index, Object value) {
if (registerOut(index)) return;
setParamValue(placeHolder, index, value);
}
private boolean registerOut(int index) {
EqlParamPlaceholder placeholder = eqlRun.getPlaceHolders()[index];
val inOut = placeholder.getInOut();
if (eqlRun.getSqlType().isProcedure() && inOut != InOut.IN) {
eqlRun.registerOutParameter(index + 1, placeholder.getOutType());
}
return inOut == InOut.OUT;
}
private Object findParamByName(int index) {
String varName = eqlRun.getPlaceHolders()[index].getPlaceholder();
val evaluator = eqlRun.getEqlConfig().getExpressionEvaluator();
Object property = evaluator.eval(varName, eqlRun);
if (!hasIterateOption && property != null
|| hasIterateOption && !isAllNullInBatchOption(property))
return property;
String propertyName = Names.underscoreNameToPropertyName(varName);
return Objects.equal(propertyName, varName) ? property : evaluator.eval(propertyName, eqlRun);
}
private boolean isAllNullInBatchOption(Object property) {
val listProperties = (List<Object>) property;
for (Object object : listProperties) {
if (object != null) return false;
}
return true;
}
private Object getParamByIndex(int index) {
val placeHolders = eqlRun.getPlaceHolders();
if (index < placeHolders.length && eqlRun.getSqlType().isProcedure()
&& placeHolders[index].getInOut() == InOut.OUT)
return null;
if (hasIterateOption)
throw new EqlExecuteException("bad parameters when batch option is set");
Object[] params = eqlRun.getParams();
if (params != null && index < params.length)
return params[index];
throw new EqlExecuteException("[" + eqlRun.getSqlId() + "] lack parameters at runtime");
}
private Object findParamBySeq(int index) {
return getParamByIndex(eqlRun.getPlaceHolders()[index - 1].getSeq() - 1);
}
}