/*
 * Copyright (C) 2004, 2007-2008 by the Widelands Development Team
 *
 * This program 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 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */

#include "logic/maphollowregion.h"

namespace Widelands {

template <>
MapHollowRegion<Area<>>::MapHollowRegion(const Map& map, HollowArea<Area<>> const hollow_area)
   : hollow_area_(hollow_area),
     phase_(Top),
     delta_radius_(hollow_area.radius - hollow_area.hole_radius),
     row_(0),
     rowwidth_(hollow_area.radius + 1),
     rowpos_(0),
     left_(hollow_area) {
	assert(hollow_area.hole_radius < hollow_area.radius);
	for (uint16_t r = hollow_area.radius; r; --r)
		map.get_tln(hollow_area_, &hollow_area_);
	left_ = hollow_area_;
}

template <> bool MapHollowRegion<Area<>>::advance(const Map& map) {
	if (phase_ == None)
		return false;
	++rowpos_;
	if (rowpos_ < rowwidth_) {
		map.get_rn(hollow_area_, &hollow_area_);
		if ((phase_ & (Upper | Lower)) && rowpos_ == delta_radius_) {
			//  Jump over the hole.
			const uint32_t holewidth = rowwidth_ - 2 * delta_radius_;
			for (uint32_t i = 0; i < holewidth; ++i)
				map.get_rn(hollow_area_, &hollow_area_);
			rowpos_ += holewidth;
		}
	} else {
		++row_;
		if (phase_ == Top && row_ == delta_radius_)
			phase_ = Upper;

		// If we completed the widest, center line, switch into lower mode
		// There are radius_+1 lines in the upper "half", because the upper
		// half includes the center line.
		else if (phase_ == Upper && row_ > hollow_area_.radius) {
			row_ = 1;
			phase_ = Lower;
		}

		if (phase_ & (Top | Upper)) {
			map.get_bln(left_, &hollow_area_);
			++rowwidth_;
		} else {

			if (row_ > hollow_area_.radius) {
				phase_ = None;
				return true;  // early out
			} else if (phase_ == Lower && row_ > hollow_area_.hole_radius)
				phase_ = Bottom;

			map.get_brn(left_, &hollow_area_);
			--rowwidth_;
		}

		left_ = hollow_area_;
		rowpos_ = 0;
	}

	return true;
}
}
