/*
 * Copyright 2009-2010 by The Regents of the University of California
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * you may obtain a copy of the License from
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package edu.uci.ics.hyracks.dataflow.std.group;

import java.util.ArrayList;
import java.util.List;

import edu.uci.ics.hyracks.api.dataflow.IOpenableDataReader;
import edu.uci.ics.hyracks.api.dataflow.IOpenableDataWriter;
import edu.uci.ics.hyracks.api.dataflow.value.IComparator;
import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
import edu.uci.ics.hyracks.dataflow.std.base.IOpenableDataWriterOperator;

public class DeserializedPreclusteredGroupOperator implements
		IOpenableDataWriterOperator {
	private final int[] groupFields;

	private final IComparator[] comparators;

	private final IGroupAggregator aggregator;

	private Object[] lastData;

	private IOpenableDataWriter<Object[]> writer;

	private List<Object[]> buffer;

	private IOpenableDataReader<Object[]> reader;

	public DeserializedPreclusteredGroupOperator(int[] groupFields,
			IComparator[] comparators, IGroupAggregator aggregator) {
		this.groupFields = groupFields;
		this.comparators = comparators;
		this.aggregator = aggregator;
		buffer = new ArrayList<Object[]>();
		reader = new IOpenableDataReader<Object[]>() {
			private int idx;

			@Override
			public void open() {
				idx = 0;
			}

			@Override
			public void close() {
			}

			@Override
			public Object[] readData() {
				return idx >= buffer.size() ? null : buffer.get(idx++);
			}
		};
	}

	@Override
	public void close() throws HyracksDataException {
		if (!buffer.isEmpty()) {
			aggregate();
		}
		writer.close();
		try {
			aggregator.close();
		} catch (Exception e) {
			throw new HyracksDataException(e);
		}
	}

	private void aggregate() throws HyracksDataException {
		reader.open();
		aggregator.aggregate(reader, writer);
		reader.close();
		buffer.clear();
	}

	@Override
	public void open() throws HyracksDataException {
		lastData = null;
		writer.open();
	}

	@Override
	public void setDataWriter(int index, IOpenableDataWriter<Object[]> writer) {
		if (index != 0) {
			throw new IllegalArgumentException();
		}
		this.writer = writer;
	}

	@Override
	public void writeData(Object[] data) throws HyracksDataException {
		if (lastData != null && compare(data, lastData) != 0) {
			aggregate();
		}
		lastData = data;
		buffer.add(data);
	}

	private int compare(Object[] d1, Object[] d2) {
		for (int i = 0; i < groupFields.length; ++i) {
			int fIdx = groupFields[i];
			int c = comparators[i].compare(d1[fIdx], d2[fIdx]);
			if (c != 0) {
				return c;
			}
		}
		return 0;
	}
}