/*
 * This file is part of Nuts Framework.
 * Copyright(C) 2009-2012 Nuts Develop Team.
 *
 * Nuts Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License any later version.
 * 
 * Nuts Framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Nuts Framework. If not, see <http://www.gnu.org/licenses/>.
 */
package nuts.tools.esort;

import java.io.IOException;
import java.util.Comparator;
import java.util.TreeSet;

/**
 * K-Merge
 * @param <T> object type
 */
public abstract class KMerge<T> {

	protected class Segment {
		int segmentNo;
		T record;
	};
	
	protected class Compare implements Comparator<Segment> {
		protected Comparator<? super T> comparator;
		
		/**
		 * @return comparator
		 */
		public Comparator<? super T> getComparator() {
			return comparator;
		}

		/**
		 * @param comparator set comparator
		 */
		public void setComparator(Comparator<? super T> comparator) {
			this.comparator = comparator;
		}

		/**
		 * @param s1 segment 1
		 * @param s2 segment 2
		 * @return compare result
		 * @see java.util.Comparator#compare
		 */
		@SuppressWarnings("unchecked")
		public int compare(Segment s1, Segment s2) {
			if (comparator != null) {
				return comparator.compare(s1.record, s2.record);
			}
			
			if (s1.record instanceof Comparable) {
				Comparable c = (Comparable)(s1.record);
				return c.compareTo(s2.record);
			}
			return 0;
		}
	};
	
	private int size;

	private TreeSet<Segment> loserTree;
	
	private Compare compare;
	
	private KMergeIO mergeIO;
	
	/**
	 * constructor
	 * @param k size of k
	 */
	public KMerge(int k) {
		size = k;
		loserTree = new TreeSet<Segment>();
		compare = new Compare();
	}

	/**
	 * @param comparator set comparator
	 */
	public void setComparator(Comparator<? super T> comparator) {
		compare.setComparator(comparator);
	}
	
	/**
	 * @return mergeIO
	 */
	public KMergeIO getMergeIO() {
		return mergeIO;
	}

	/**
	 * @param mergeIO set mergeIO
	 */
	public void setMergeIO(KMergeIO mergeIO) {
		this.mergeIO = mergeIO;
	}

	/**
	 * construct tree
	 * @throws IOException
	 */
	protected void constructTree() throws IOException {
		for (int i = 0; i < size; i++) {
			Segment s = new Segment();
			s.segmentNo = i;
			s.record = read(i);
			if (s.record != null) {
				loserTree.add(s);
			}
		}
	}
	
	/**
	 * merge
	 * @throws IOException if an I/O error occurs
	 */
	public void merge() throws IOException {
		constructTree();

/*		while (loserTree.size() > 0) {
			Segment s = loserTree.pollFirst();
			write(s.record);
			
			s.record = read(s.segmentNo);
			if (s.record != null) {
				loserTree.add(s);
			}
		}*/
	}

	protected abstract T read(int segmentNo) throws IOException;
	
	protected abstract void write(T obj) throws IOException;
}
