/*
 * ====================================================================
 * This software is subject to the terms of the Common Publilc License
 * Agreement, available at the following URL:
 *   http://www.opensource.org/licenses/cpl.html .
 * You must accept the terms of that agreement to use this software.
 * ====================================================================
 */
package org.pivot4j.transform.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

import org.apache.commons.lang.NullArgumentException;
import org.olap4j.Cell;
import org.olap4j.CellSet;
import org.olap4j.CellSetAxis;
import org.olap4j.OlapConnection;
import org.olap4j.OlapException;
import org.olap4j.Position;
import org.olap4j.metadata.Member;
import org.olap4j.metadata.MetadataElement;
import org.pivot4j.PivotException;
import org.pivot4j.PivotModel;
import org.pivot4j.mdx.Exp;
import org.pivot4j.query.QueryAdapter;
import org.pivot4j.transform.AbstractTransform;
import org.pivot4j.transform.DrillThrough;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DrillThroughImpl extends AbstractTransform implements DrillThrough {

	private Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * @param queryAdapter
	 * @param connection
	 */
	public DrillThroughImpl(QueryAdapter queryAdapter, OlapConnection connection) {
		super(queryAdapter, connection);
	}

	/**
	 * @return the logger
	 */
	protected Logger getLogger() {
		return logger;
	}

	/**
	 * @see org.pivot4j.transform.DrillThrough#drillThrough(org.olap4j.Cell)
	 */
	@Override
	public ResultSet drillThrough(Cell cell) {
		return drillThrough(cell, null, 0);
	}

	/**
	 * @see org.pivot4j.transform.DrillThrough#drillThrough(org.olap4j.Cell,
	 *      java.util.List, int)
	 */
	@Override
	public ResultSet drillThrough(Cell cell, List<MetadataElement> selection,
			int maximumRows) {
		if (cell == null) {
			throw new NullArgumentException("cell");
		}

		ResultSet result;

		if (selection != null && !selection.isEmpty() || maximumRows > 0) {
			result = performDrillThroughMdx(cell, selection, maximumRows);
		} else {
			result = performDrillThrough(cell);
		}

		return result;
	}

	/**
	 * @param cell
	 * @return
	 */
	protected ResultSet performDrillThrough(Cell cell) {
		try {
			return cell.drillThrough();
		} catch (OlapException e) {
			throw new PivotException(e);
		}
	}

	/**
	 * @param cell
	 * @param selection
	 * @param maximumRows
	 * @return
	 */
	protected ResultSet performDrillThroughMdx(Cell cell,
			List<MetadataElement> selection, int maximumRows) {
		PivotModel model = getModel();
		QueryAdapter query = getQueryAdapter();

		StringBuilder builder = new StringBuilder();

		builder.append("DRILLTHROUGH");

		if (maximumRows > 0) {
			builder.append(" MAXROWS ");
			builder.append(maximumRows);
		}

		builder.append(" SELECT (");

		boolean isFirst = true;

		List<Integer> coords = cell.getCoordinateList();

		CellSet cellSet = cell.getCellSet();
		List<CellSetAxis> axes = cellSet.getAxes();

		int axisOrdinal = 0;
		for (int ordinal : coords) {
			Position position = axes.get(axisOrdinal++).getPositions()
					.get(ordinal);

			for (Member member : position.getMembers()) {
				if (isFirst) {
					isFirst = false;
				} else {
					builder.append(", ");
				}

				builder.append(member.getUniqueName());
			}
		}

		builder.append(") ON COLUMNS FROM ");
		builder.append(model.getCube().getUniqueName());

		Exp slicer = query.getParsedQuery().getSlicer();

		if (slicer != null) {
			builder.append(" WHERE ");
			builder.append(slicer.toMdx());
		}

		if (selection != null && !selection.isEmpty()) {
			builder.append(" RETURN ");

			isFirst = true;

			for (MetadataElement elem : selection) {
				if (isFirst) {
					isFirst = false;
				} else {
					builder.append(", ");
				}

				builder.append(elem.getUniqueName());
			}
		}

		String mdx = builder.toString();

		if (logger.isDebugEnabled()) {
			logger.debug("Drill through MDX : {}", mdx);
		}

		ResultSet result;

		try {
			Statement stmt = getConnection().createStatement();
			result = stmt.executeQuery(mdx);
		} catch (SQLException e) {
			throw new PivotException(e);
		}

		return result;
	}
}

@@ -753,24 +753,57 @@
 j.Position;%0A
+import org.olap4j.metadata.Cube;%0A
 import org.o
@@ -1093,16 +1093,51 @@
 hrough;%0A
+import org.pivot4j.util.OlapUtils;%0A
 import o
@@ -2727,16 +2727,48 @@
 odel();%0A
+%09%09Cube cube = model.getCube();%0A%0A
 %09%09QueryA
@@ -3469,22 +3469,68 @@
 .append(
-member
+OlapUtils.wrapRaggedIfNecessary(member, cube)%0A%09%09%09%09%09%09
 .getUniq
@@ -3607,31 +3607,20 @@
 .append(
-model.getC
+c
 ube
-()
 .getUniq
@@ -4004,32 +4004,139 @@
 d(%22, %22);%0A%09%09%09%09%7D%0A%0A
+%09%09%09%09if (elem instanceof Member) %7B%0A%09%09%09%09%09elem = OlapUtils.wrapRaggedIfNecessary((Member) elem, cube);%0A%09%09%09%09%7D%0A%0A
 %09%09%09%09builder.appe

Fix #127: Drillthrough not working for ragged cubes