/*
	Lan Wars.
	Copyright (c) 2009, Darragh Coy.
	All rights reserved.
	Original work(s), source code & author(s) details available at: http://www.darraghcoy.com

	Redistribution and use in source and binary forms, with or without modification, are permitted 
	provided that the following conditions are met:

		* 	Redistributions of source code must retain the above copyright notice, this list of 
			conditions and the following disclaimer.
		* 	Redistributions in binary form must reproduce the above copyright notice, this list of 
			conditions and the following disclaimer in the documentation.
		* 	Neither the name of the author nor the names of contributors may be used to endorse or 
			promote products derived from this software without specific prior written permission.
		* 	The use of any third party libraries, modules or data files provided with the source 
			form of the program must follow and respect the individual licensing terms of these 
			components. You do not have permission to modify or circumvent the licensing terms for 
			provided third party components unless the third party licenses specifically allow this. 
			If you do not agree to the terms of provided third party components then you do not have 
			permission to use them in your derived work(s).
		* 	The terms of this license do not apply to separate (but related) distributions if supplied 
			by the author(s), only to the contents of this source distribution, derived works, and the 
			binaries produced by either modified or unmodified versions of the source code. The terms 
			of this license do not also apply to any third party libraries or components provided with 
			the source distribution. Such third party elements are licensed under their own separate 
			agreements.

	THIS SOFTWARE IS PROVIDED BY DARRAGH COY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
	ARE DISCLAIMED. IN NO EVENT SHALL DARRAGH COY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//=====================================================================================================================
/// @brief		Represents a subsector in the doom level. This structure is used as a helper class to help build
///				the path network; it holds inter-connectivity information with other subsectors in the level.
//=====================================================================================================================

#include "Precompiled.h"
#include "AI/BuildPathSubsector.h"
#include "AI/BuildPathNode.h"
#include "Doom/DoomLevel.h"
#include "Doom/DoomGLSubsectorV2.h"
#include "Doom/DoomPPSeg.h"
#include "GameObjects/GamePlayer.h"

using namespace Game;

//=====================================================================================================================	
/// @brief		Creates the path subsector
/// @param		level - level the subsector belongs to
/// @param		subsector - subsector this is in the level
/// @pre		Given doom level cannot be null
/// @pre		Given subsector cannot be null
//=====================================================================================================================

BuildPathSubsector::BuildPathSubsector( const DoomLevel & level , const DoomGLSubsectorV2 & subsector )
{
	// Check:
	
	ENSURE( &level			!= 0 , "Given doom level cannot be null"	)
	ENSURE( &subsector		!= 0 , "Given subsector cannot be null"		)
	
	// Save:
	
	m_level = &level; m_subsector = &subsector;
	
	// No closest node to us initially:
	
	m_closest_node = 0;
	
	// Build a list of subsectors we are connected to:
	
	BuildConnectedSubsectorsList();
	
	// Find the center of the subsector
	
	FindSubsectorCenter();
}

//=====================================================================================================================
/// @brief		Builds a list of other subsectors that the path subsector is directly connected to.
///	@remarks	This function only builds a list of subsectors that can be reached from this subsectors. Walls that 
///				are too high to move over are ignored when calculating connections.
//=====================================================================================================================

void BuildPathSubsector::BuildConnectedSubsectorsList()
{
	// Run through all the segs in our subsector:
	
	for ( unsigned i = 0 ; i < m_subsector->m_count ; ++i )
	{
		// Get this seg:
		
		const DoomPPSeg & seg = m_level->GetSeg(m_subsector->m_first_seg+i);
		
		// See if there is a seg opposite to this:
		
		if ( seg.m_opposite_seg )
		{
			// Good: get the subsector the opposite seg belongs to:
			
			DoomGLSubsectorV2 * opposite_subsector = seg.m_opposite_seg->m_subsector;
			
			// See if we have this subsector already:
			
			if ( std::find(m_connected_subsectors.begin(),m_connected_subsectors.end(),opposite_subsector) == m_connected_subsectors.end() )
			{
				// Not marked as connected to this subsector: add as a connected subsector if we can pass to it
				
				if ( CanTraverseTo(*opposite_subsector) )
				{
					m_connected_subsectors.push_back(opposite_subsector);
				}
			}
		}
	}
}

//=====================================================================================================================
/// @brief		Tells if it is possible to traverse from this subsector to the given subsector
/// @param		other - other subsector to check with
/// @returns	True if the other subsector can be reached from this subsector
//=====================================================================================================================

bool BuildPathSubsector::CanTraverseTo( const DoomGLSubsectorV2 & other ) const
{
	// Get our sector and the other sector:
	
	const DoomSector & our_sec = m_level->GetSector(*m_subsector);
	const DoomSector & otr_sec = m_level->GetSector(other);
	
	// If we are in the same sector then it is possible to traverse:
	
	if ( &our_sec == &otr_sec ) return true;

	// Get the height difference between the floors:
	
	float height_diff = float(otr_sec.m_floor_y) - float(our_sec.m_floor_y);
	
	// See if it is possible to step up to the height of the other subsector: if not then we cannot reach the other subsector
	
	if ( height_diff >= GamePlayer::COLLISION_HEIGHT * 0.90f ) return false;
	
	// See if the floor/ceiling heights of the sector will not allow us to pass through because both are too close together
	
	height_diff = float(otr_sec.m_ceiling_y) - float(otr_sec.m_floor_y);
	
	// See if that is the case:
	
	if ( height_diff <= GamePlayer::COLLISION_HEIGHT * 2.20f ) return false;
	
	// See if the gap between our floor and the other ceiling would prevent us from passing through
	
	height_diff =  float(otr_sec.m_ceiling_y) - float(our_sec.m_floor_y);
	
	// See if that is the case:
	
	if ( height_diff <= GamePlayer::COLLISION_HEIGHT * 2.20f ) return false;
	
	// If we got to here then we can reach the other subsector from here: return true
	
	return true;
}

//=====================================================================================================================
/// @brief		Calculates the center of the subsector
//=====================================================================================================================

void BuildPathSubsector::FindSubsectorCenter()
{
	// Store the sum of all the sector points here:
	
	Vec2f sum = Vec2f::Zero();
	
	// Run through all the segs in our subsector:
	
	for ( unsigned i = 0 ; i < m_subsector->m_count ; ++i )
	{
		// Get this seg:
		
		const DoomPPSeg & seg = m_level->GetSeg(m_subsector->m_first_seg+i);
		
		// Add the end point to the sum:
		
		sum += seg.m_end;
	}
	
	// Compute the average of the sector points:
	
	if ( m_subsector->m_count > 0 ) sum /= float(m_subsector->m_count);
	
	// Save the center point
	
	m_center = sum;
}
