package net.sf.jasperreports.engine.fill;

import java.sql.Connection;
import java.util.Map;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRDatasetParameter;
import net.sf.jasperreports.engine.JRDatasetRun;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExpression;
import net.sf.jasperreports.engine.JRQuery;
import net.sf.jasperreports.engine.JRScriptletException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class JRFillDatasetRun implements JRDatasetRun {
  private static final Log log = LogFactory.getLog(JRFillDatasetRun.class);
  
  private final JRBaseFiller filler;
  
  private final JRFillDataset dataset;
  
  private JRExpression parametersMapExpression;
  
  private JRDatasetParameter[] parameters;
  
  private JRExpression connectionExpression;
  
  private JRExpression dataSourceExpression;
  
  public JRFillDatasetRun(JRBaseFiller filler, JRDatasetRun datasetRun, JRFillObjectFactory factory) {
    factory.put(datasetRun, this);
    this.filler = filler;
    this.dataset = (JRFillDataset)filler.datasetMap.get(datasetRun.getDatasetName());
    this.parametersMapExpression = datasetRun.getParametersMapExpression();
    this.parameters = datasetRun.getParameters();
    this.connectionExpression = datasetRun.getConnectionExpression();
    this.dataSourceExpression = datasetRun.getDataSourceExpression();
  }
  
  public void evaluate(JRFillElementDataset elementDataset, byte evaluation) throws JRException {
    Map parameterValues = JRFillSubreport.getParameterValues(this.filler, this.parametersMapExpression, this.parameters, evaluation, false, (this.dataset.getResourceBundle() != null), false);
    try {
      if (this.dataSourceExpression != null) {
        JRDataSource dataSource = (JRDataSource)this.filler.evaluateExpression(this.dataSourceExpression, evaluation);
        this.dataset.setDatasourceParameterValue(parameterValues, dataSource);
      } else if (this.connectionExpression != null) {
        Connection connection = (Connection)this.filler.evaluateExpression(this.connectionExpression, evaluation);
        this.dataset.setConnectionParameterValue(parameterValues, connection);
      } 
      copyConnectionParameter(parameterValues);
      this.dataset.setParameterValues(parameterValues);
      this.dataset.initDatasource();
      this.dataset.filterElementDatasets(elementDataset);
      this.dataset.initCalculator();
      iterate();
    } finally {
      this.dataset.closeDatasource();
      this.dataset.restoreElementDatasets();
    } 
  }
  
  protected void copyConnectionParameter(Map parameterValues) {
    JRQuery query = this.dataset.getQuery();
    if (query != null) {
      String language = query.getLanguage();
      if (this.connectionExpression == null && (language.equals("sql") || language.equals("SQL")) && !parameterValues.containsKey("REPORT_CONNECTION")) {
        JRFillParameter connParam = (JRFillParameter)this.filler.getParametersMap().get("REPORT_CONNECTION");
        Connection connection = (Connection)connParam.getValue();
        parameterValues.put("REPORT_CONNECTION", connection);
      } 
    } 
  }
  
  protected void iterate() throws JRException {
    this.dataset.start();
    init();
    if (this.dataset.next()) {
      detail();
      while (this.dataset.next()) {
        checkInterrupted();
        group();
        detail();
      } 
    } 
  }
  
  protected void checkInterrupted() {
    if (Thread.currentThread().isInterrupted() || this.filler.isInterrupted()) {
      if (log.isDebugEnabled())
        log.debug("Fill " + this.filler.fillerId + ": interrupting"); 
      this.filler.setInterrupted(true);
      throw new JRFillInterruptedException();
    } 
  }
  
  protected void group() throws JRException, JRScriptletException {
    this.dataset.calculator.estimateGroupRuptures();
    this.dataset.scriptlet.callBeforeGroupInit();
    this.dataset.calculator.initializeVariables((byte)4);
    this.dataset.scriptlet.callAfterGroupInit();
  }
  
  protected void init() throws JRScriptletException, JRException {
    this.dataset.scriptlet.callBeforeReportInit();
    this.dataset.calculator.initializeVariables((byte)1);
    this.dataset.scriptlet.callAfterReportInit();
  }
  
  protected void detail() throws JRScriptletException, JRException {
    this.dataset.scriptlet.callBeforeDetailEval();
    this.dataset.calculator.calculateVariables();
    this.dataset.scriptlet.callAfterDetailEval();
  }
  
  public String getDatasetName() {
    return this.dataset.getName();
  }
  
  public JRExpression getParametersMapExpression() {
    return this.parametersMapExpression;
  }
  
  public JRDatasetParameter[] getParameters() {
    return this.parameters;
  }
  
  public JRExpression getConnectionExpression() {
    return this.connectionExpression;
  }
  
  public JRExpression getDataSourceExpression() {
    return this.dataSourceExpression;
  }
  
  protected JRFillDataset getDataset() {
    return this.dataset;
  }
  
  public Object clone() {
    return null;
  }
}
