/* IntervalNode.java

	Purpose:
		
	Description:
		
	History:
		Oct 23, 2014 10:25:57 AM, Created by henrichen

	Copyright (C) 2014 Potix Corporation. All Rights Reserved.
*/

package org.zkoss.zssex.util;

import java.util.Collection;

import org.zkoss.zssex.util.ParallelIntervals.IntervalResult;

/**
 * @author henri
 *
 */
/// Node for [IntervalTree] which hold multiple [Interval]s with the same
/// low end point but with differnt high end points; the
/// type [T] is the type of the [Interval]'s payload.
///
/// Note that the maximum high end point of all [Interval]'s of all nodes rooted
/// by this node is called "topHigh" and are kept in node's [value]. And the
/// same low end point of all [Intervals]s in this node is kept in [key].
///
/// This implementation expose methods that will change intervals associated so
/// you can override them to maintain your interval consistency:
///
/// * [insertDuplicateInterval] - when trying to insert an interval with same
/// low end point and high end point to this node.
/// * [canDeleteInterval] - Checks whether you really want to delete the found
/// interval.
class IntervalNode<T> extends RBNode<Integer, Integer> {
	private static final long serialVersionUID = 2234929561334842768L;
	ParallelIntervals<T> intervals;
	
	IntervalNode(Interval<T> interval) {
		super(interval.getLow(), interval.getHigh());
		intervals = new ParallelIntervals<T>();
		intervals.insertInterval(interval);
	}
	
	/// Insert the specified interval into this node; returns the original
	/// [Interval] if duplicated in this node; otherwise, returns the new
	/// inserted one.
	Interval<T> insertInterval(Interval<T> interval, Object context) {
		final IntervalResult<T> result = intervals.insertInterval(interval);
		if (result.index >= 0) { // exist interval
		    // Found; update the found interval with the new interval
		    insertDuplicateInterval(result.interval, interval, context);
		}
		return result.interval;
	}
	
	/// Trying to add a duplicate interval with same low end point and high end
	/// point; default operation of this implementation is to assign the payload
	/// of the [original] interval with the payload of the [newone] interval if
	/// the payload of the [oringinal] interval is null.
	@SuppressWarnings("unchecked")
	protected void insertDuplicateInterval(Interval<T> original, Interval<T> newone, Object context) {
		if (original.getPayload() == null) {
			original.setPayload(newone.getPayload());
		}
		((IntervalContext<T>) context).original = original;
	}
	
	/// Delete the specified interval from this node and returns it; returns null
	/// if not found or if [canDeleteInterval] disallow deletion.
	Interval<T> deleteInterval(Interval<T> interval, Object context) {
		final IntervalResult<T> result = intervals.searchInterval(interval);
		if (result != null) { // found the interval!
		  // Delete found interval only if canDeleteInterval returns true
		  if (canDeleteInterval(result.interval, interval, context)) {
		    return intervals.deleteInterval(result.index);
		  }
		}
		return null;
	}
	
	/// Whether can delete the specified interval from this node; default would
	/// nullify [original] interval's payload and returns
	/// true to allow deleting the [original] interval from this node.
	boolean canDeleteInterval(Interval<T> original, Interval<T> refernce, Object context) {
		original.setPayload(null);
		return true;
	}
	
	/// Search the specified interval from this node and returns the one found;
	/// returns null if not.
	Interval<T> searchInterval(Interval<T> interval) {
		IntervalResult<T> result = intervals.searchInterval(interval);
		return result == null ? null : result.interval;
	}
	
	/// Maximum high end point of all [Interval]s in this node.
	int getMaxHigh() {
		return intervals.getMax();
	}
	
	/// Collect [Intervals] in this node that contains the specified [interval].
	void contains(Interval<T> interval, Collection<Interval<T>> results) {
		intervals.contains(interval, results);
	}
	
	/// Collect [Interval]s in this node that overlapped with the specified
	/// [interval].
	void overlaps(Interval<T> interval, Collection<Interval<T>> results) {
		intervals.overlaps(interval, results);
	}
	
	/// Collect [Interval] in this node that are contained by the specified
	/// [interval].
	void contained(Interval<T> interval, Collection<Interval<T>> results) {
		intervals.contained(interval, results);
	}
	
	/// Update the top high value of this node (kept in [value] property of this
	/// node).
	///
	/// A top high value is the maximum high end point of all [Interval]s of all
	/// nodes rooted by this node.
	boolean updateTopHigh() {
		final RBNode<Integer, Integer> l = getLeft(), r = getRight();
		
		int t = getMaxHigh();
		if (l != null && l.getValue() > t) t = l.getValue();
		if (r != null && r.getValue() > t) t = r.getValue();
		
		if (getValue() == t) return true;
		
		setValue(t);
		return false;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public IntervalNode<T> getLeft() {
		return (IntervalNode<T>) super.getLeft();
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public IntervalNode<T> getRight() {
		return (IntervalNode<T>) super.getRight();
	}

}

