#include "mungal4.h"
#pragma hdrstop

#define PRELOAD_ART

#include "..\munga\vdata.h"
#include "l4lamp.h"
#include "l4wrhous.h"

// #define LOCAL_TEST

#if defined(LOCAL_TEST)
#	define Test_Tell(n) cout << n
#else
#	define Test_Tell(n)
#endif

//#########################################################################
//############################# L4LampManager #############################
//#########################################################################
L4LampManager::L4LampManager(LBE4ControlsManager *controls_manager):
	LampManager()
{
	Check(controls_manager);
	controlsManager = controls_manager;

	previousLampState = new int[LBE4ControlsManager::LampCount];
	Register_Pointer(previousLampState);
	lampActiveFlag = new Logical[LBE4ControlsManager::LampCount];
	Register_Pointer(lampActiveFlag);
	//-----------------------------------------
	// Clear L4 lamp state tables
	//-----------------------------------------
	int
		i;

	Check_Pointer(previousLampState);
	for(i=0; i< LBE4ControlsManager::LampCount; ++i)
	{
		previousLampState[i] = RIO::solid + RIO::state1Off + RIO::state2Off;
	}
	Check_Fpu();
}

L4LampManager::~L4LampManager()
{
	Check(this);

	Unregister_Pointer(previousLampState);
	delete[] previousLampState;
	previousLampState = NULL;

	Unregister_Pointer(lampActiveFlag);
	delete[] lampActiveFlag;
	lampActiveFlag = NULL;

	Check_Fpu();
}

Logical
	L4LampManager::TestInstance() const
{
	Check_Fpu();
	return LampManager::TestInstance();
}

void
	L4LampManager::Update(ModeMask current_mode_mask)
{
	Check(this);
	Logical
		flush_inactive_lamps = (current_mode_mask != previousModeMask);
	int
		i;

	if (flush_inactive_lamps)
	{
		//---------------------------------------
		// Mark all lamps as inactive
		//---------------------------------------
		Check_Pointer(lampActiveFlag);
		for(i=0; i< LBE4ControlsManager::LampCount; ++i)
		{
			lampActiveFlag[i] = False;
		}
	}
	//---------------------------------------
	// Update LampManager, set lamp outputs,
	// and mark active lamps
	//---------------------------------------
	LampManager::Update(current_mode_mask);

	if (flush_inactive_lamps)
	{
		//---------------------------------------
		// Turn off inactive lamps
		//---------------------------------------
		Check_Pointer(lampActiveFlag);
		for(i=0; i< LBE4ControlsManager::LampCount; ++i)
		{
			if (lampActiveFlag[i] == False)
			{
				AssertNewLampValue(i, RIO::solid+RIO::state1Off+RIO::state2Off); 
			}
		}
	}
	Check_Fpu();
}

void
	L4LampManager::AssertNewLampValue(int lamp_number, int lamp_value)
{
	Check(this);

	Verify(lamp_number >= 0);
	Verify(lamp_number < LBE4ControlsManager::LampCount);
	//--------------------------------------
	// Update external hardware
	//--------------------------------------
	Check_Pointer(previousLampState);
	if (previousLampState[lamp_number] != lamp_value)
	{
		previousLampState[lamp_number] = lamp_value;
		//--------------------------------------
		// Send RIO command to update L4 lamp
		//--------------------------------------
		Check(controlsManager);
		controlsManager->SetLamp(lamp_number, lamp_value);
	}

	Check_Fpu();
}

//#########################################################################
//################################ L4Lamp #################################
//#########################################################################
L4Lamp::L4Lamp(
	LampID lamp_number,
	ModeMask mode_mask,
	L4LampManager *lamp_manager
) :
	Lamp(lamp_number, mode_mask, (LampManager *) lamp_manager)
{
	automatic = True;
	automaticValue = (ControlsButton) 0;
	previousAutomaticValue = automaticValue;

	SetState(LampStateDim);

	Check_Fpu();
}

L4Lamp::~L4Lamp()
{
	Check(this);
	SetState(LampStateOff);
	Check_Fpu();
}

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

void
	L4Lamp::SetAutomaticOperation(Logical automatic_flag)
{
	Check(this);
	automatic = automatic_flag;
	Check_Fpu();
}

void
	L4Lamp::Update(Logical force_notification)
{
	Check(this);

	//--------------------------------------
	// Tell manager we're still active
	//--------------------------------------
	if (lampID >= 0)
	{
		if (lampID < LBE4ControlsManager::LampCount)
		{
			Check_Pointer(((L4LampManager *)manager)->lampActiveFlag);
			((L4LampManager *)manager)->lampActiveFlag[lampID] = True;
		}
	}
	//--------------------------------------
	// Update state if automatic
	//--------------------------------------
	if (automatic)
	{
		if (previousAutomaticValue != automaticValue)
		{
			previousAutomaticValue = automaticValue;

			if (previousAutomaticValue > 0)
			{
				SetState(LampStateOn);
			}
			else
			{
				SetState(LampStateDim);
			}
		}
		else if (force_notification)
		{
			NotifyOfStateChange();
		}
	}
	else if (force_notification)
	{
		NotifyOfStateChange();
	}
	Check_Fpu();
}

void
	L4Lamp::NotifyOfStateChange()
{
	Check(this);
	Check((L4LampManager *) manager);

	int
		output_value;

	if (alertActive)
	{
		switch(previousState)
		{
		default:
			output_value = RIO::flashFast + RIO::state1Off + RIO::state2Dim; 
			break;

		case LampStateDim:
		case LampStateOn:
			output_value = RIO::flashFast + RIO::state1Dim + RIO::state2Bright; 
			break;
		}        
	}
	else
	{
		switch(previousState)
		{
		default:
			output_value = RIO::solid + RIO::state1Off    + RIO::state2Off; 
			break;

		case LampStateDim:
			output_value = RIO::solid + RIO::state1Dim    + RIO::state2Dim; 
			break;

		case LampStateOn:
			output_value = RIO::solid + RIO::state1Bright + RIO::state2Bright;
			break;
		}        
	}

	((L4LampManager *) manager)->AssertNewLampValue(lampID, output_value);
	Check_Fpu();
}

//#########################################################################
//############################# L4VirtualLamp #############################
//#########################################################################
L4GraphicLamp::L4GraphicLamp(
	LampID lamp_id,
	ModeMask mode_mask,
	GaugeRenderer *the_renderer,
	int graphics_port_number,
	int left, int bottom,
	const char *map_name,
	int bg_color, int fg_color,
	Logical opaque_flag
) :
	GraphicLamp(
		lamp_id,
		mode_mask,
		the_renderer->GetLampManager(),
		the_renderer,
		graphics_port_number
	)
{
	//--------------------------------------------
	// Build copy of map name
	//--------------------------------------------
	Check_Pointer(map_name);
	mapName = new char[strlen(map_name)+1];
	Register_Pointer(mapName);
	strcpy(mapName, map_name);
	//--------------------------------------------
	// Get the image
	//--------------------------------------------
#	if defined(PRELOAD_ART)
	Check(renderer);
	L4Warehouse
		*warehouse = (L4Warehouse *) renderer->warehousePointer;
	Check(warehouse);

	warehouse->bitMapBin.Get(mapName);
#	endif

	opaque = opaque_flag;
   bgColor = bg_color;
	fgColor = fg_color;
	localView.SetOrigin(left, bottom);
	Check_Fpu();
}

L4GraphicLamp::~L4GraphicLamp()
{
	Check(this);
	Check_Pointer(mapName);
	//--------------------------------------------
	// Release the preloaded image
	//--------------------------------------------
#	if defined(PRELOAD_ART)
	Check(renderer);
	L4Warehouse
		*warehouse = (L4Warehouse *) renderer->warehousePointer;
	Check(warehouse);

	warehouse->bitMapBin.Release(mapName);
#	endif
	//--------------------------------------------
	// Delete the copy of the name
	//--------------------------------------------
	Check_Pointer(mapName);
	delete[] mapName;
	mapName = NULL;
	Check_Fpu();
}

Logical
	L4GraphicLamp::TestInstance() const
{
	return GraphicLamp::TestInstance();
}

void
	L4GraphicLamp::NotifyOfStateChange()
{
	Check(this);
	//--------------------------------------------
	// Get the bitmap
	//--------------------------------------------
	Check(renderer);
	L4Warehouse
		*warehouse = (L4Warehouse *) renderer->warehousePointer;
	Check(warehouse);

	BitMap
		*bitmap = warehouse->bitMapBin.Get(mapName);

	if (bitmap != NULL)
	{
		Check(bitmap);
		//--------------------------------------------
		// Set the color
		//--------------------------------------------
		if (previousState <= LampStateOff)
		{
			localView.SetColor(bgColor);
		}
		else
		{
			localView.SetColor(fgColor);
		}
		//--------------------------------------------
		// Draw the bitmap
		//--------------------------------------------
		if (opaque)
		{
			localView.DrawBitMapOpaque(bgColor, 0, bitmap);
		}
		else
		{
			localView.DrawBitMap(0, bitmap);
		}
		//--------------------------------------------
		// Release the bitmap
		//--------------------------------------------
		Check(warehouse);
		warehouse->bitMapBin.Release(mapName);
	}
	Check_Fpu();
}
