//===========================================================================//
// File:	searchlight.hpp                                                     //
// Project: BattleTech                                                       //
// Contents: Searchlight (illumination) subsystem                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. All Rights reserved //
//                      PROPRIETARY AND CONFIDENTIAL                         //
//===========================================================================//
//
// RECONSTRUCTED from the shipped binary (Ghidra pseudo-C, recovered shard
// part_013.c).  NO SEARCHLIGHT.HPP survived; the class body is inferred from
// usage and the embedded string pool.  Each method cites its @ADDR.
//
// IDENTIFICATION:
//   * mech3.cpp factory map: Searchlight::CreateStreamedSubsystem @004b85a8,
//     DefaultData &DAT_00511198.
//   * vtable @005114d4 (slot0 dtor @004b8568), ctor @004b84dc.
//   * CreateStreamedSubsystem @004b85a8 stamps classID 0x0BD8 and streamed
//     model size 0xF4; it parses NO searchlight-specific model fields (empty
//     resource extension).
//   * String pool @00511440 ("ToggleLamp", "Searchlight", "LightOn",
//     "LightState").  ClassDerivations name "Searchlight" @005111a8.
//   * A message-handler record @00511210 binds "ToggleLamp" -> FUN_004b860c.
//
// BASE CLASS:
//   Searchlight IS-A PowerWatcher (powersub.hpp): ctor @004b84dc chains to the
//   PowerWatcher ctor FUN_004b18a4 with &DAT_00511198, and
//   CreateStreamedSubsystem chains to PowerWatcher::CreateStreamedSubsystem
//   FUN_004b198c.  The shared base occupies bytes 0..0x1D8; Searchlight's own
//   members begin at 0x1D8.  It exposes one queryable attribute "LightState".
//
#if !defined(SEARCHLIGHT_HPP)
#	define SEARCHLIGHT_HPP

#if !defined(POWERSUB_HPP)
	#include "powersub.hpp"
#endif

//##########################################################################
//#####################    Local multi-level alarm shim    #################
//##########################################################################
//
// CROSS-FAMILY: heat.hpp does `typedef GaugeAlarm AlarmIndicator;` but the
// engine GaugeAlarm (GAUGALRM.h) has a PROTECTED ctor/dtor and no
// Initialize/Finalize/SetLevel; the mech.hpp/mechrecon.hpp alias resolves
// AlarmIndicator to ReconAlarm, which also lacks Initialize/Finalize.  Until
// the heat family provides a real multi-level AlarmIndicator, this module owns
// a tiny faithful stand-in for ITS OWN alarm member (it does NOT redefine the
// AlarmIndicator typedef).
//
#if !defined(BT_LOCAL_ALARM_SHIM)
#	define BT_LOCAL_ALARM_SHIM
	struct BtAlarm
	{
		int		level;
		BtAlarm()					: level(0) {}
		void	Initialize(int /*levels*/)	{ level = 0; }	// FUN_0041b9ec
		void	Finalize()					{}				// FUN_0041baa4
		void	SetLevel(int n)				{ level = n; }	// FUN_0041bbd8
		int		GetLevel() const			{ return level; }
	};
#endif

//##########################################################################
//#####################    Searchlight::SubsystemResource    ###############
//##########################################################################
//
// Empty extension of the PowerWatcher resource (CreateStreamedSubsystem
// @004b85a8 reads no light-specific fields; it only stamps classID/model
// size).  The ctor seeds commandedOn from the inherited segment field (+0x28).
//
	struct Searchlight__SubsystemResource:
		public PowerWatcher::SubsystemResource
	{
		// RESOURCE_AUDIT.md: Searchlight adds NO resource field.  The ctor seeds
		// commandedOn from the INHERITED segmentIndex (resource +0x28); the old
		// `int segmentDefault;` was appended after the base (compiled at ~0xF4, OOB)
		// and read garbage.  Empty extension = correct 0xF4 model size.
	};

//##########################################################################
//##########################    Searchlight    #############################
//##########################################################################

	class Searchlight:
		public PowerWatcher
	{
		friend struct SearchlightLayoutCheck;	// compile-time offset locks (searchlight.cpp)
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Shared Data Support
	//
	// DefaultData @00511198, ClassDerivations @005111a8 ("Searchlight").
	//
	public:
		static Derivation ClassDerivations;		// @005111a8
		static SharedData DefaultData;			// @00511198
		static Receiver::MessageHandlerSet MessageHandlers;	// @00511210 ("ToggleLamp")

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Attribute Support
	//
	// AttributePointers IndexEntry table @005111e0:
	//      id 5  "LightState"  -> @0x1D8   (offset encoded 0x1D9 == 0x1D8|1)
	//
	public:
		enum {
			LightStateAttributeID = PowerWatcher::NextAttributeID,	// 5
			NextAttributeID
		};

	private:
		static const IndexEntry AttributePointers[];	// @005111e0
	protected:
		static AttributeIndexSet AttributeIndex;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Local data.
	//
	protected:
		int		lightState;		// @0x1D8  reported on/off (gated by power + heat each frame); "LightState"
		int		commandedOn;	// @0x1DC  resource +0x28; toggled by the "ToggleLamp" message (@004b860c)
		int		requestedOn;	// @0x1E0  init 0; on/off input consumed by SearchlightSimulation
		BtAlarm	stateAlarm;		// @0x1E4  2-level light indicator (size 0x54)

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// BT segment / base-state compatibility shims (CROSS-FAMILY).
	//
	// These accessors / mutators logically belong on the shared bases
	// (Subsystem::GetSegmentFlags / SetInstanceFlag / SetGraphicsDirty,
	// PowerWatcher::HostShutDown / WatchedVoltageLevel, HeatSink::HeatStateLevel,
	// Mech controls-mapper lightsEnabled).  Until those families expose them they
	// are backed by local members so this module compiles; see report.
	//
	public:
		// De-shimmed (WAVE 4 un-stub): the 7 CROSS-FAMILY backing fields
		// (segmentFlags/hostShutDown/watchedVoltageLevel/heatStateLevel/
		// controlsAllowLights/graphicsDirty/instanceFlags) are DELETED.  They
		// duplicated engine-base state AND -- via the old shadow `segmentFlags`
		// (seeded 0) -- made the ctor gate ((0&0xC)==0 && (0&0x100)!=0) FALSE, so
		// SearchlightSimulation was NEVER installed.  Accessors now read the REAL
		// inherited base members (mirrors torso.hpp/torso.cpp):
		//   HostShutDown        <- MechSubsystem::simulationState == Destroyed (this+0x40)
		//   WatchedVoltageLevel <- PowerWatcher::watchdogAlarm level           (this+0x198)
		//   HeatStateLevel      <- HeatWatcher::heatAlarm level                (this+0x140)
		//   SetGraphicsDirty    -> engine Simulation::ForceUpdate()            (this+0x18)
		//   SetInstanceFlag     -> engine Simulation::simulationFlags |= bits  (this+0x28)
		// GetSegmentFlags() removed (the ctor gate now reads owner->simulationFlags).
		// ControlsAllowLights(): no ported base member (the real read is the
		// owner controls-mapper lightsEnabled via an unsafe raw owner-offset
		// chain) -> return True for bring-up; the only consumer (ToggleLamp) is
		// dormant.  Faithful follow-up = a real Mech::ControlsAllowLights().
		Logical	HostShutDown() const		{ return simulationState == 1; /* Destroyed */ }
		int		WatchedVoltageLevel() const	{ return watchdogAlarm.GetLevel(); }	// @0x198
		int		HeatStateLevel() const		{ return heatAlarm.GetLevel(); }		// @0x140
		Logical	ControlsAllowLights() const	{ return True; }	// bring-up (see above)
		void	SetGraphicsDirty()			{ ForceUpdate(); }	// this[0x18] |= 1
		void	SetInstanceFlag(int bits)	{ simulationFlags |= bits; }	// this[10] |= bits
		// The "ToggleLamp" command arg is carried at message+0xC (decomp).
		static int	MessageArg(Message &m)	{ return *(const int *)((const char *)&m + 0xC); }

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Simulation Support
	//
	public:
		typedef void
			(Searchlight::*Performance)(Scalar time_slice);

		void
			SetPerformance(Performance performance)
			{
				Check(this);
				activePerformance = (Simulation::Performance)performance;
			}

		void
			SearchlightSimulation(Scalar time_slice);	// @004b841c (Performance, PTR @00511200)

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Message handling
	//
	public:
		Logical
			ToggleLamp(Message &message);		// @004b860c (bound to "ToggleLamp" @00511210)

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Subsystem virtual overrides (vtable @005114d4)
	//
	// Only slots 6 and 7 (network state replication) are HUD-specific; slot 9
	// (HandleMessage) and slot 10 (ResetToInitialState) inherit PowerWatcher's
	// @004b179c / @004b1804.
	//
	// The decomp named these ReadUpdate/WriteUpdate over a fictional
	// NetworkPacket.value / NetworkRecord{kind,value}.  The real engine
	// network-state-replication virtuals (SIMULATE.h) are
	// ReadUpdateRecord(UpdateRecord*) / WriteUpdateRecord(UpdateRecord*,int);
	// the replicated on/off and the 0x14 record tag map to the real
	// UpdateRecord::simulationState / ::recordID fields.
	//
	public:
		void
			ReadUpdateRecord(UpdateRecord *message);				// slot 6, @004b83b8
		void
			WriteUpdateRecord(UpdateRecord *message, int update_model);	// slot 7, @004b83f0 (record tag 0x14)

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Class Support
	//
	public:
		static	Logical	TestClass(Mech&);
		Logical			TestInstance() const;	// @004b85f0

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction and Destruction
	//
	public:
		typedef Searchlight__SubsystemResource SubsystemResource;

		Searchlight(
			Mech				*owner,
			int					subsystem_ID,
			SubsystemResource	*subsystem_resource,
			SharedData			&shared_data = DefaultData
		);											// @004b84dc
		~Searchlight();								// @004b8568

		static int
			CreateStreamedSubsystem(				// @004b85a8
				NotationFile				*model_file,
				const char					*model_name,
				const char					*subsystem_name,
				SubsystemResource			*subsystem_resource,
				NotationFile				*subsystem_file,
				const ResourceDirectories	*directories,
				int							passes = 1
			);
	};

#endif
