content: /*
   * @(#)GranularityRangeModel.java
   *
   * Copyright 2002 EGANTT LLP. All rights reserved.
   * PROPRIETARY/QPL. Use is subject to license terms.
   */
  
  package com.egantt.drawing.painter.range.model;
  
  import java.awt.Graphics;
  import java.awt.Rectangle;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Iterator;
  
  import com.egantt.awt.graphics.GraphicsContext;
  import com.egantt.awt.graphics.context.CompoundContext;
  import com.egantt.awt.graphics.context.compound.SubCompoundContext;
  import com.egantt.drawing.painter.range.RangeIterator;
  import com.egantt.drawing.painter.range.RangeModel;
  import com.egantt.drawing.painter.range.RangeTransform;
  import com.egantt.drawing.painter.range.iterator.BasicRangeIterator;
  import com.egantt.drawing.painter.range.transform.CompoundRangeTransform;
  import com.egantt.model.drawing.DrawingGranularity;
  import com.egantt.model.drawing.DrawingTransform;
  import com.egantt.model.drawing.StateResources;
  import com.egantt.model.drawing.painter.PainterResources;
  import com.egantt.model.drawing.painter.PainterState;
  
  /**
   * This is an OffScreen plotter, unlike other plotters it attempts to calculate
   * the required granularity for a plotter by painting in a virtual buffer and then
   * guessing the range
   */
  public abstract class GranularityRangeModel implements RangeModel
  {
  	protected final int axisKey;
  	protected final int offset;
  
  	public GranularityRangeModel(int axisKey, int offset)
  	{
  		this.axisKey = axisKey;
  		this.offset = Math.abs(offset);
  	}
  
  	// _________________________________________________________________________
  
  	public GraphicsContext getContext(Object gran, GraphicsContext context) {
  		return gran != null && context instanceof CompoundContext
  			? new SubCompoundContext(gran, (CompoundContext) context) : context;
  	}
  
  	// _________________________________________________________________________
  
  	public RangeIterator iterator(Object key, Graphics g, Rectangle bounds,
  			PainterState state, GraphicsContext context)
  	{
  		DrawingGranularity granularity = (DrawingGranularity)
  			context.get(key, PainterResources.GRANULARITY);
  
  		RangeTransform transform = new CompoundRangeTransform(axisKey,
  																 (DrawingTransform []) state.get(StateResources.TRANSFORMS));
  
  		Object gran = state.get(StateResources.GRANULARITY_KEY);
  		gran = gran != null ? gran :
  			calculateGranularity(granularity, g, state, transform, bounds);
  
  		return iterator(gran, granularity, transform, bounds);
  	}
  
  	// __________________________________________________________________________
  
  	protected Object calculateGranularity(DrawingGranularity granularity,
  			Graphics g, PainterState state, RangeTransform transform, Rectangle bounds)
  	{
  		ArrayList <Object> granularities = new ArrayList<Object>();
  		Rectangle rect = new Rectangle(); // try to cache the rect's they are to expensive
  
  		for (Iterator iter = granularity.keys(); iter.hasNext();)
  		{
  			Object gran = iter.next();
  	
  			granularities.add(gran);
  
  			rect.setBounds(0,0, (int)
  					granularity.width(gran, transform, bounds.width),bounds.height);
  
  			if (!interateGranularities(granularity.values(gran, transform, bounds.width), gran, g, rect))
  			{
  				Object lastGran = granularities.get(Math.max(granularities.size() - offset -1, 0));
  				state.put(StateResources.GRANULARITY_KEY, lastGran);
  				return lastGran;
  			}
  		}
  		return null;
  	}
  	
  	protected boolean  interateGranularities(Iterator iter, Object gran, Graphics g, Rectangle rect) {
  		while (iter.hasNext())
  		{
  			if (accepts(iter.next(), gran,  g, rect))
  				return true;
  		}
  		return false;
  	}
  
  	// __________________________________________________________________________
  
  	protected abstract boolean accepts(Object key, Object gran, Graphics g, Rectangle bounds);
  
  
  	// __________________________________________________________________________
  
  	protected RangeIterator iterator(Object value, DrawingGranularity granularity,
  			RangeTransform transform, Rectangle bounds)
  	{
  		Iterator inner = value != null
  			? granularity.values(value, transform, bounds.width)
  			: Collections.EMPTY_SET.iterator();
  		return new BasicRangeIterator(inner, transform, bounds.width, bounds.height);
  	}
  }
  