package eu.dnetlib.enabling.database.resultset;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.support.rowset.SqlRowSet;

import eu.dnetlib.enabling.database.rmi.DatabaseException;
import eu.dnetlib.enabling.database.utils.DatabaseUtils;
import eu.dnetlib.enabling.resultset.SizedIterable;

public class IterableRowSet implements SizedIterable<String> {
	private String db;
	private String sql;
	private String sqlForCount;
	private DatabaseUtils dbUtils;
	private Integer size = null;

	private static final Log log = LogFactory.getLog(IterableRowSet.class); // NOPMD by marko on 11/24/08 5:02 PM

	
	public IterableRowSet(String db, String sql, String sqlForCount, DatabaseUtils dbUtils) {
		super();
		this.db = db;
		this.sql = sql;
		this.sqlForCount = sqlForCount;
		this.dbUtils = dbUtils;
	}

	@Override
	public Iterator<String> iterator() {
		try {
			final SqlRowSet rowset = dbUtils.executeSql(db, sql, SqlRowSet.class);

			return new Iterator<String>() {

				@Override
				public void remove() {	}

				@Override
				public String next() {
					try {
						if (!rowset.next()) 
							throw new RuntimeException("Premature end of rowset for query: " + sql);

						Map<String, Object> res = new HashMap<String, Object>();
						for (String column : rowset.getMetaData().getColumnNames())
							res.put(column, rowset.getObject(column));

						return dbUtils.rowToDocument(res).asXML();
					} catch (DatabaseException e) {
						throw new RuntimeException("Error navigating rowset for query: " + sql, e);
					}
				}

				@Override
				public boolean hasNext() {
					return !rowset.isLast();
				}
			};
		} catch (DatabaseException e) {
			throw new RuntimeException("Error creating iterator for query: " + sql, e);
		}
	}

	@Override
	public int getNumberOfElements() {
		if (size != null) return size;

		String query = (sqlForCount == null || sqlForCount.isEmpty()) ? 
				"SELECT count(*) FROM ( " + sql + " ) AS TABLELISTENER" : sqlForCount;

		try {
			log.debug("Calculating size using query: " + query);
			this.size = dbUtils.executeSql(db, query, Integer.class);
			return size;
		} catch (DatabaseException e) {
			log.error("Error in getSize, query: " + query, e);
			throw new IllegalStateException("Error in getSize, query: " + query, e);
		}

	}

}
