//===========================================================================//
// File:	gauge.cc                                                            //
// Project: MUNGA           Brick: Gauges                                    //
// Contents: Interface specification for Gauges                              //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  -----------------------------------------------------------//
// 02/10/95  CPB  Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. All rights reserved //
//                      PROPRIETARY and CONFIDENTIAL                         //
//===========================================================================//

#include <munga.hpp>
#pragma hdrstop

#if !defined(LAMP_HPP)
#	include <lamp.hpp>
#endif

//#########################################################################
//############################# LampManager ###############################
//#########################################################################
LampManager::LampManager():
	lampList(NULL),
	activeLampList(NULL),
	inactiveLampList(NULL)
{
	previousModeMask = (ModeMask) 0;
	Check_Fpu();
}

LampManager::~LampManager()
{
	Check(this);
	RemoveAllLamps();
	Check_Fpu();
}

Logical
	LampManager::TestInstance() const
{
	return True;
}

void
	LampManager::Update(ModeMask current_mode_mask)
{
	Check(this);
	//---------------------------------------------------------------
	// If the modeMask has changed, update the active/inactive lists.
	//---------------------------------------------------------------
	if (previousModeMask != current_mode_mask)
	{
		previousModeMask = current_mode_mask;

		ActivateLamps(current_mode_mask);
		DeactivateLamps(current_mode_mask);
	}
	//-----------------------------------------------------------------
	// Process all active lamps
	//-----------------------------------------------------------------
	ChainIteratorOf<Lamp*>
		i(activeLampList);
	Lamp
		*lamp_pointer;

	while ((lamp_pointer=i.ReadAndNext()) != NULL)
	{
		Check(lamp_pointer);
		lamp_pointer->Update();
	}
	Check_Fpu();
}

void
	LampManager::ActivateLamps(ModeMask current_mode_mask)
{
	Check(this);
	//-----------------------------------------------------------
	// Test the lamps in the 'inactive' list.  If any of them
	// have bits in their modeMask corresponding to the
	// new mode mask, move them to the 'active' list.
	//-----------------------------------------------------------
	ChainIteratorOf<Lamp*>
		i(inactiveLampList);
	Lamp
		*lamp_pointer;

	while ((lamp_pointer=i.GetCurrent()) != NULL)
	{
		Check(lamp_pointer);
		//-----------------------------------
		// Became active?
		//-----------------------------------
		if (lamp_pointer->modeMask & current_mode_mask)
		{
			//-----------------------------------
			// Yes, move to 'active' list
			//-----------------------------------
			i.Remove();
			activeLampList.Add(lamp_pointer);
			//-----------------------------------
			// Cause lamp to update itself
			//-----------------------------------
			lamp_pointer->Update(True);	// force notification of state change
		}
		else
		{
			//-----------------------------------
			// No, try the next one
			//-----------------------------------
			i.Next();
		}
	}
	Check_Fpu();
}
		
void
	LampManager::DeactivateLamps(ModeMask current_mode_mask)
{
	Check(this);
	//---------------------------------------------------------------
	// Test the lamps in the 'active' list.  If any of them do NOT
	// have bits in their modeMask corresponding to the new mode
	// mask, move them to the 'inactive' list.
	//---------------------------------------------------------------
	ChainIteratorOf<Lamp*>
		i(activeLampList);
	Lamp
		*lamp_pointer;

	while ((lamp_pointer=i.GetCurrent()) != NULL)
	{
		Check(lamp_pointer);
		//-----------------------------------
		// Became inactive?
		//-----------------------------------
		if (!(lamp_pointer->modeMask & current_mode_mask))
		{
			//-----------------------------------
			// Yes, move to 'inactive' list
			//-----------------------------------
			i.Remove();
			inactiveLampList.Add(lamp_pointer);
		}
		else
		{
			//-----------------------------------
			// No, try the next one
			//-----------------------------------
			i.Next();
		}
	}
	Check_Fpu();
}

Lamp*
	LampManager::FindLamp(LampID lamp_id, ModeMask mode_mask)
{
	Check(this);

	//---------------------------------------------------------------
	// Search for lamp with both proper ID and modeMask
	//---------------------------------------------------------------
	ChainIteratorOf<Lamp*>
		i(lampList);
	Lamp
		*lamp_pointer;

	while ((lamp_pointer=i.ReadAndNext()) != NULL)
	{
		Check(lamp_pointer);

		if (lamp_pointer->lampID == lamp_id)
		{
			if (lamp_pointer->modeMask == mode_mask)
			{
				Check_Fpu();
				return lamp_pointer;
			}
		}
	}
	Check_Fpu();
	return NULL;
}
			
void
	LampManager::AddLamp(Lamp *new_lamp)
{
	Check(this);
	//
	// Don't call Check(new_lamp) here!
	// The Lamp creator calls AddLamp before the lamp is fully built!
	//
	Check_Pointer(new_lamp);

	lampList.Add(new_lamp);

	if (new_lamp->modeMask & previousModeMask)
	{
		activeLampList.Add(new_lamp);
	}
	else
	{
		inactiveLampList.Add(new_lamp);
	}

	Check_Fpu();
}

void
	LampManager::RemoveLamp(LampID lamp_id, ModeMask mode_mask)
{
	Check(this);
	Lamp
		*lamp_pointer = FindLamp(lamp_id, mode_mask);
	if (lamp_id != NULL)
	{
		Unregister_Object(lamp_pointer);
		delete lamp_pointer;
	}

	Check_Fpu();
}

void
	LampManager::RemoveAllLamps()
{
	Check(this);
	//-------------------------------------------
	// Delete all lamps
	//-------------------------------------------
	ChainIteratorOf<Lamp*>
		i(lampList);
	Lamp
		*lamp_pointer;

	while ((lamp_pointer=i.ReadAndNext()) != NULL)
	{
		Check(lamp_pointer);
		Unregister_Object(lamp_pointer);
		delete lamp_pointer;
	}
	Check_Fpu();
}

//#########################################################################
//################################# Lamp ##################################
//#########################################################################
Lamp::Lamp(
	LampID lamp_id,
	ModeMask mode_mask,
	LampManager *lamp_manager
):
	Node(Gauge::GaugeClassID)
{
	Check(lamp_manager);
	Verify(mode_mask != (ModeMask) 0);	// if zero, it would NEVER execute

	lampID = lamp_id;
	modeMask = mode_mask;
	previousState = LampStateUndefined;
	manager = lamp_manager;
	alertActive = 0;

	manager->AddLamp(this);
	Check_Fpu();
}

Lamp::~Lamp()
{
	Check(this);
	Check_Fpu();
}

Logical
	Lamp::TestInstance() const
{
	return True;
}

void
	Lamp::SetState(LampState new_state)
{
	Check(this);

	if (new_state != previousState)
	{
		previousState = new_state;
		//---------------------------------------------
		// Update if mode is currently allowed
		//---------------------------------------------
		Check(manager);
		if (modeMask & manager->previousModeMask)
		{
			NotifyOfStateChange();
		}
	}
	Check_Fpu();
}

void
	Lamp::SetAlertState(Logical alert_state)
{
	Check(this);

	if (alert_state)
	{
		++alertActive;
	}
	else
	{
		--alertActive;
		if (alertActive < 0)
		{
			alertActive = 0;
		}
	}

	//---------------------------------------------
	// Update if mode is currently allowed
	//---------------------------------------------
	Check(manager);
	if (modeMask & manager->GetPreviousModeMask())
	{
		NotifyOfStateChange();
	}
	Check_Fpu();
}

void
	Lamp::Update(Logical /*force_notification*/)
{
	Fail("Lamp::Update method not overridden!");
}

void
	Lamp::NotifyOfStateChange()
{
	Check(this);
	Check_Fpu();
}

//#########################################################################
//############################## GraphicLamp ##############################
//#########################################################################
GraphicLamp::GraphicLamp(
	LampID lamp_id,
	ModeMask mode_mask,
	LampManager *lamp_manager,
	GaugeRenderer *the_renderer,
	int graphics_port_number
):
	Lamp(lamp_id, mode_mask, lamp_manager),
	renderer(the_renderer),
	localView(
		the_renderer == NULL ?
			NULL :
			the_renderer->GetGraphicsPort(graphics_port_number)
	)
{
	Check_Fpu();
}

GraphicLamp::~GraphicLamp()
{
	Check(this);
	Check_Fpu();
}

Logical
	GraphicLamp::TestInstance() const
{
	Check(&localView);
	Check_Fpu();
	return Lamp::TestInstance();
}


