/*****************************************************************************/
// Copyright 2006-2019 Adobe Systems Incorporated
// All Rights Reserved.
//
// NOTICE:	Adobe permits you to use, modify, and distribute this file in
// accordance with the terms of the Adobe license agreement accompanying it.
/*****************************************************************************/

#include "dng_tile_iterator.h"

#include "dng_exceptions.h"
#include "dng_image.h"
#include "dng_pixel_buffer.h"
#include "dng_tag_types.h"
#include "dng_utils.h"
		
/*****************************************************************************/

dng_tile_iterator::dng_tile_iterator (const dng_image &image,
									  const dng_rect &area)
									  
	:	fArea			()
	,	fTileWidth		(0)
	,	fTileHeight		(0)
	,	fTileTop		(0)
	,	fTileLeft		(0)
	,	fRowLeft		(0)
	,	fLeftPage		(0)
	,	fRightPage		(0)
	,	fTopPage		(0)
	,	fBottomPage		(0)
	,	fHorizontalPage (0)
	,	fVerticalPage	(0)
	
	{
	
	Initialize (image.RepeatingTile (),
				area & image.Bounds ());
				
	}
						   
/*****************************************************************************/

dng_tile_iterator::dng_tile_iterator (const dng_point &tileSize,
									  const dng_rect &area)
									  
	:	fArea			()
	,	fTileWidth		(0)
	,	fTileHeight		(0)
	,	fTileTop		(0)
	,	fTileLeft		(0)
	,	fRowLeft		(0)
	,	fLeftPage		(0)
	,	fRightPage		(0)
	,	fTopPage		(0)
	,	fBottomPage		(0)
	,	fHorizontalPage (0)
	,	fVerticalPage	(0)
	
	{
	
	dng_rect tile (area);
	
	tile.b = Min_int32 (tile.b, tile.t + tileSize.v);
	tile.r = Min_int32 (tile.r, tile.l + tileSize.h);
	
	Initialize (tile,
				area);
	
	}
						   
/*****************************************************************************/

dng_tile_iterator::dng_tile_iterator (const dng_rect &tile,
									  const dng_rect &area)
									  
	:	fArea			()
	,	fTileWidth		(0)
	,	fTileHeight		(0)
	,	fTileTop		(0)
	,	fTileLeft		(0)
	,	fRowLeft		(0)
	,	fLeftPage		(0)
	,	fRightPage		(0)
	,	fTopPage		(0)
	,	fBottomPage		(0)
	,	fHorizontalPage (0)
	,	fVerticalPage	(0)
	
	{
	
	Initialize (tile,
				area);
	
	}
						   
/*****************************************************************************/

void dng_tile_iterator::Initialize (const dng_rect &tile,
									const dng_rect &area)
	{
	
	fArea = area;
	
	if (area.IsEmpty ())
		{
		
		fVerticalPage =	 0;
		fBottomPage	  = -1;
		
		return;
		
		}
	
	int32 vOffset = tile.t;
	int32 hOffset = tile.l;
	
	int32 tileHeight = tile.b - vOffset;
	int32 tileWidth	 = tile.r - hOffset;
	
	fTileHeight = tileHeight;
	fTileWidth	= tileWidth;
	
	fLeftPage  = (fArea.l - hOffset	   ) / tileWidth;
	fRightPage = (fArea.r - hOffset - 1) / tileWidth;
	
	fHorizontalPage = fLeftPage;
	
	fTopPage	= (fArea.t - vOffset	) / tileHeight;
	fBottomPage = (fArea.b - vOffset - 1) / tileHeight;
	
	fVerticalPage = fTopPage;
	
	fTileLeft = fHorizontalPage * tileWidth	 + hOffset;
	fTileTop  = fVerticalPage	* tileHeight + vOffset;

	fRowLeft = fTileLeft;
			
	}
									  
/*****************************************************************************/

bool dng_tile_iterator::GetOneTile (dng_rect &tile)
	{
	
	if (fVerticalPage > fBottomPage)
		{
		return false;
		}

	if (fVerticalPage > fTopPage)
		tile.t = fTileTop;
	else
		tile.t = fArea.t;

	if (fVerticalPage < fBottomPage)
		tile.b = fTileTop + fTileHeight;
	else
		tile.b = fArea.b;

	if (fHorizontalPage > fLeftPage)
		tile.l = fTileLeft;
	else
		tile.l = fArea.l;

	if (fHorizontalPage < fRightPage)
		tile.r = fTileLeft + fTileWidth;
	else
		tile.r = fArea.r;

	if (fHorizontalPage < fRightPage)
		{
		fHorizontalPage++;
		fTileLeft += fTileWidth;
		}

	else
		{

		fVerticalPage++;
		fTileTop += fTileHeight;

		fHorizontalPage = fLeftPage;
		fTileLeft = fRowLeft;

		}
		
	return true;
	
	}

/*****************************************************************************/

dng_tile_reverse_iterator::dng_tile_reverse_iterator (const dng_image &image,
													  const dng_rect &area)

	:	fTiles ()

	,	fIndex (0)

	{
	
	dng_tile_forward_iterator iterator (image, area);

	Initialize (iterator);

	}

/*****************************************************************************/

dng_tile_reverse_iterator::dng_tile_reverse_iterator (const dng_point &tileSize,
													  const dng_rect &area)

	:	fTiles ()

	,	fIndex (0)

	{
	
	dng_tile_forward_iterator iterator (tileSize, area);

	Initialize (iterator);
	
	}
						   
/*****************************************************************************/

dng_tile_reverse_iterator::dng_tile_reverse_iterator (const dng_rect &tile,
													  const dng_rect &area)

	:	fTiles ()

	,	fIndex (0)

	{
	
	dng_tile_forward_iterator iterator (tile, area);

	Initialize (iterator);
	
	}
	
/*****************************************************************************/

bool dng_tile_reverse_iterator::GetOneTile (dng_rect &tile)
	{
	
	if (fIndex == 0)
		{
		
		return false;
		
		}

	fIndex--;
	
	tile = fTiles [fIndex];

	return true;

	}

/*****************************************************************************/

void dng_tile_reverse_iterator::Initialize (dng_tile_forward_iterator &iterator)
	{
	
	dng_rect tile;

	while (iterator.GetOneTile (tile))
		{
		
		fTiles.push_back (tile);
		
		}

	fIndex = fTiles.size ();
	
	}

/*****************************************************************************/
