class BatteryCharger extends ItemBase
{
	// Model selections
	static protected const string SEL_CLIPS_CAR			= "clips_car_battery";
	static protected const string SEL_CLIPS_TRUCK		= "clips_truck_battery";
	static protected const string SEL_CLIPS_DETACHED	= "clips_detached";
	static protected const string SEL_CLIPS_FOLDED		= "clips_folded";
	static protected const string SEL_SWITCH_ON			= "switch_on";
	static protected const string SEL_SWITCH_OFF		= "switch_off";
	static protected const string SEL_CORD_PLUGGED		= "cord_plugged";
	static protected const string SEL_CORD_FOLDED		= "cord_folded";
	static protected const string SEL_LIGHT_STATE_1		= "light_stand_by";
	static protected const string SEL_LIGHT_STATE_2		= "light_charging";
	static protected const string SEL_LIGHT_STATE_3		= "light_charged";
	
	// glow materials
	static protected const string RED_LIGHT_GLOW		= "dz\\gear\\camping\\data\\battery_charger_light_r.rvmat";
	static protected const string GREEN_LIGHT_GLOW		= "dz\\gear\\camping\\data\\battery_charger_light_g.rvmat";
	static protected const string YELLOW_LIGHT_GLOW		= "dz\\gear\\camping\\data\\battery_charger_light_y.rvmat";
	static protected const string SWITCH_LIGHT_GLOW		= "dz\\gear\\camping\\data\\battery_charger_light_switch_on.rvmat";
	static protected const string DEFAULT_MATERIAL 		= "dz\\gear\\camping\\data\\battery_charger.rvmat";
	
	protected const string 	ATTACHED_CLIPS_STATES[] 		= {SEL_CLIPS_CAR, SEL_CLIPS_TRUCK}; // TO DO: If it's required by design, add helicopter battery here and register its selection names.
	protected const int 	ATTACHED_CLIPS_STATES_COUNT		= 2; // Reffers to this ^ array
	
	
	
	int 						m_BatteryEnergy0To100;
	protected float 			m_ChargeEnergyPerSecond;
	
	static protected 	float 	m_BlinkingStatusLightInterval = 0.4; // How often the lights blink
	ref 				Timer 	m_UpdateStatusLightsTimer;
	protected 			bool 	m_BlinkingStatusLightIsOn = false;	// Status of one blinking light
	
	void BatteryCharger()
	{
		m_ChargeEnergyPerSecond = GetGame().ConfigGetFloat ("CfgVehicles " + GetType() + " ChargeEnergyPerSecond");
		m_UpdateStatusLightsTimer = new Timer( CALL_CATEGORY_SYSTEM );
		SwitchLightOff();
		RegisterNetSyncVariableInt("m_BatteryEnergy0To100");
	}
	
	override bool IsElectricAppliance()
	{
		return true;
	}

	override void OnWork( float consumed_energy )
	{
		// Charging functionality
		ItemBase battery = ItemBase.Cast( GetCompEM().GetPluggedDevice() );
		
		if ( battery )
		{
			if ( GetGame().IsServer() )
			{
				float battery_capacity = battery.GetCompEM().GetEnergyMax();
				
				if ( battery.GetCompEM().GetEnergy() < battery_capacity )
				{
					float charger_health = GetHealth("", "");
					float energy_add = m_ChargeEnergyPerSecond * ( consumed_energy / GetCompEM().GetEnergyUsage() );
					
					#ifdef DIAG_DEVELOPER
					if (FeatureTimeAccel.GetFeatureTimeAccelEnabled(ETimeAccelCategories.ENERGY_RECHARGE))
					{
						float timeAccel = FeatureTimeAccel.GetFeatureTimeAccelValue();
						energy_add *= timeAccel;
					}
					#endif
					
					if ( GetCompEM().ConsumeEnergy(energy_add) ) // consumes energy from the power source
					{
						// There is enough of energy to use
						energy_add = energy_add * ( 0.5 + charger_health*0.005 ); // Damaged charger works less efficiently - 50% damage causes 75% efficiency
					}
					else
					{
						// There is NOT enough of energy to use
						energy_add = 0;
					}
					
					battery.GetCompEM().AddEnergy( energy_add );
				}
				else
				{
					battery.GetCompEM().SetEnergy( battery_capacity );
				}
				m_BatteryEnergy0To100 = battery.GetCompEM().GetEnergy0To100();
				SetSynchDirty();
			}
		}
	}

	override void OnWorkStart()
	{
		if ( GetGame().IsClient()  ||  !GetGame().IsMultiplayer() )
		{
			UpdateStatusLights();
			m_UpdateStatusLightsTimer.Run( m_BlinkingStatusLightInterval/2 , this, "UpdateStatusLights", NULL, true);
		}
	}
		
	override void OnWorkStop()
	{
		if ( GetGame().IsClient()  ||  !GetGame().IsMultiplayer() )
		{
			UpdateStatusLights();
			m_UpdateStatusLightsTimer.Stop();
		}
	}
	
	void UpdateStatusLights()
	{
		if ( GetGame().IsClient()  ||  !GetGame().IsMultiplayer() )
		{
			if (GetCompEM().IsWorking())
			{
				SwitchLightOn();
				ItemBase battery = ItemBase.Cast( GetCompEM().GetPluggedDevice() );
				
				if (battery)
				{
					RedLightOff();
					
					if (m_BatteryEnergy0To100 <= 33)
					{
						// Less than 1/3 charged, yellow status light must repeatedly blink
						
						if (m_BlinkingStatusLightIsOn)
							YellowLightOn();
						else
							YellowLightOff();
						
						m_BlinkingStatusLightIsOn = !m_BlinkingStatusLightIsOn;
					}
					else if (m_BatteryEnergy0To100 > 33  &&  m_BatteryEnergy0To100 <= 66)
					{
						// Less than 2/3 charged, yellow status light must glow
						
						YellowLightOn();
					}
					else if (m_BatteryEnergy0To100 > 66  &&  m_BatteryEnergy0To100 < 100)
					{
						// Less than 3/3 charged, yellow status light must glow, green light must blink
						
						YellowLightOn();
						
						if (m_BlinkingStatusLightIsOn)
							GreenLightOn();
						else
							GreenLightOff();
						
						m_BlinkingStatusLightIsOn = !m_BlinkingStatusLightIsOn;
					}
					else if (m_BatteryEnergy0To100 >= 100)
					{
						// Fully charged, green light must glow
						YellowLightOff();
						GreenLightOn();
					}
				}
				else
				{
					if (m_BlinkingStatusLightIsOn)
						RedLightOn();
					else
						RedLightOff();
					
					m_BlinkingStatusLightIsOn = !m_BlinkingStatusLightIsOn;
					
					GreenLightOff();
					YellowLightOff();
				}
			}
			else
			{
				SwitchLightOff();
				GreenLightOff();
				RedLightOff();
				YellowLightOff();
			}
		}
	}
	
	override bool CanPutInCargo( EntityAI parent )
	{
		if( !super.CanPutInCargo(parent) ) {return false;}
		// No "Take" action if the item is connected
		if ( !GetCompEM().IsPlugged()  &&  !GetCompEM().GetPluggedDevice() )
		{
			return true;
		}
		
		return false;
	}

	override bool CanPutIntoHands( EntityAI parent ) 
	{
		if( !super.CanPutIntoHands( parent ) )
		{
			return false;
		}
		// No "Take into hands" action if the item is connected
		if ( !GetCompEM().IsPlugged()  &&  !GetCompEM().GetPluggedDevice() )
		{
			return true;
		}
		
		return false;
	}

	override void OnOwnSocketTaken( EntityAI device )
	{
		string att_type = device.GetType();
		
		if ( att_type == "CarBattery" )
		{
			HideAttachedClipsStates();
			ShowSelection(SEL_CLIPS_CAR);
		}
		
		if ( att_type == "TruckBattery" )
		{
			HideAttachedClipsStates();
			ShowSelection(SEL_CLIPS_TRUCK);
		}
		
		HideSelection(SEL_CLIPS_DETACHED);
		HideSelection(SEL_CLIPS_FOLDED);
	}

	override void OnOwnSocketReleased( EntityAI device )
	{
		HideAttachedClipsStates();
		ShowSelection(SEL_CLIPS_DETACHED);
	}

	override bool CanReceiveAttachment( EntityAI attachment, int slotId ) 
	{
		if ( !super.CanReceiveAttachment(attachment, slotId) )
			return false;
		
		ItemBase ibase;
		Class.CastTo(ibase, attachment);
		
		// No attaching if the charger is in inventory!
		PlayerBase charger_owner = PlayerBase.Cast( GetHierarchyRootPlayer() );
		if ( charger_owner )
			return false;
		
		// Only one attachment allowed
		if ( GetCompEM().GetPluggedDevice() )
			return false;
		
		if ( ibase.HasEnergyManager()  &&  ibase.GetCompEM().GetPluggedDevicesCount() >= 1 ) // Make sure nothing is plugged into the battery
			return false;
		
		return true;
	}
	
	override bool CanLoadAttachment( EntityAI attachment) 
	{
		if ( !super.CanLoadAttachment(attachment) )
			return false;
		
		ItemBase ibase;
		Class.CastTo(ibase, attachment);
		
		// Only one attachment allowed
		if ( GetCompEM().GetPluggedDevice() )
			return false;
		
		if ( ibase.HasEnergyManager()  &&  ibase.GetCompEM().GetPluggedDevicesCount() >= 1 ) // Make sure nothing is plugged into the battery
			return false;
		
		return true;
	}
	
	void HideAttachedClipsStates()
	{
		for ( int i = 0; i < ATTACHED_CLIPS_STATES_COUNT; i++ )
		{
			string selection = ATTACHED_CLIPS_STATES[i];
			HideSelection(selection);
		}
	}
	
	
	
	// Control of status lights
	// ON
	void RedLightOn()
	{
		SetObjectMaterial( 0, RED_LIGHT_GLOW );
	}
	void GreenLightOn()
	{
		SetObjectMaterial( 2, GREEN_LIGHT_GLOW );
	}
	void YellowLightOn()
	{
		SetObjectMaterial( 1, YELLOW_LIGHT_GLOW );
	}
	void SwitchLightOn()
	{
		SetObjectMaterial( 3, SWITCH_LIGHT_GLOW );
	}
	// OFF
	void RedLightOff()
	{
		SetObjectMaterial( 0, DEFAULT_MATERIAL );
	}
	void GreenLightOff()
	{
		SetObjectMaterial( 2, DEFAULT_MATERIAL );
	}
	void YellowLightOff()
	{
		SetObjectMaterial( 1, DEFAULT_MATERIAL );
	}
	void SwitchLightOff()
	{
		SetObjectMaterial( 3, DEFAULT_MATERIAL );
	}
	
	
	override void OnSwitchOn()
	{
		HideSelection(SEL_SWITCH_OFF);
		ShowSelection(SEL_SWITCH_ON);
	}
	
	override void OnSwitchOff()
	{
		HideSelection(SEL_SWITCH_ON);
		ShowSelection(SEL_SWITCH_OFF);
	}
	
	// Inventory manipulation
	override void OnInventoryExit(Man player)
	{
		super.OnInventoryExit(player);
		
		HideAttachedClipsStates();
		HideSelection(SEL_CLIPS_FOLDED);
		ShowSelection(SEL_CLIPS_DETACHED);
	}
	
	override void OnInventoryEnter(Man player)
	{
		super.OnInventoryEnter(player);
		
		HideAttachedClipsStates();
		HideSelection(SEL_CLIPS_DETACHED);
		ShowSelection(SEL_CLIPS_FOLDED);
	}
		
	override void RefreshPhysics()
	{
		super.RefreshPhysics();
		
		if ( GetAttachmentByType(CarBattery) )
		{
			RemoveProxyPhysics( "battery" );
			AddProxyPhysics( "battery" );
		}
		else
			RemoveProxyPhysics( "battery" );
	}
		
	//================================================================
	// ADVANCED PLACEMENT
	//================================================================
	
	override void OnPlacementStarted(Man player)
	{	
		super.OnPlacementStarted(player);
		
		SetAnimationPhase(SEL_CLIPS_DETACHED, 0);
		SetAnimationPhase(SEL_CLIPS_FOLDED, 1);
		SetAnimationPhase(SEL_SWITCH_ON, 1);
		SetAnimationPhase(SEL_SWITCH_OFF, 1);
		SetAnimationPhase(SEL_LIGHT_STATE_1, 1);
		SetAnimationPhase(SEL_LIGHT_STATE_2, 1);
		SetAnimationPhase(SEL_LIGHT_STATE_3, 1);
	
		array<string> selections = {
			SEL_CORD_PLUGGED,
			SEL_CORD_FOLDED,
			SEL_CLIPS_DETACHED,
			SEL_CLIPS_FOLDED
		};
		
		PlayerBase playerPB = PlayerBase.Cast(player);
		foreach (string selection : selections)
		{		
			if (GetGame().IsMultiplayer() && GetGame().IsServer())
				playerPB.GetHologramServer().SetSelectionToRefresh(selection);		
			else
				playerPB.GetHologramLocal().SetSelectionToRefresh(selection);
		}
	}
		
	override bool IsDeployable()
	{
		return true;
	}
	
	override string GetDeploySoundset()
	{
		return "placeBatteryCharger_SoundSet";
	}
	
	override void SetActions()
	{
		super.SetActions();
		
		AddAction(ActionPlugIn);
		AddAction(ActionTogglePlaceObject);
		AddAction(ActionUnplugThisByCord);
		AddAction(ActionTurnOnWhileOnGround);		
		AddAction(ActionTurnOffWhileOnGround);
		AddAction(ActionPlaceObject);
	}
}