// Project Lab - NHTV Igad

#include "UnrealProject.h"

#include "NetworkCharacter.h"
#include "Effect.h"
#include "DefaultGameInstance.h"
#include "Prefs.h"

AEffect::AEffect()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;
	//RootComponent = m_particleComponent = CreateDefaultSubobject<UParticleSystemComponent>("PSys");
	m_followActor = nullptr;
	m_duration = 0.0f;
	deactivateParticlesBefore = 0;
	bReplicates = true;

}
void AEffect::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
	
	DOREPLIFETIME_CONDITION(AEffect, m_followActor, COND_InitialOnly);
	DOREPLIFETIME_CONDITION(AEffect, m_duration, COND_InitialOnly);
}
void AEffect::BeginPlay()
{
	m_particleSystems = GetComponentsByClass(UParticleSystemComponent::StaticClass());
	m_rootParticleSystem = Cast<UParticleSystemComponent>(RootComponent);
	m_rootAudio = Cast<UAudioComponent>(RootComponent);

	// Bind root component finished actions
	if(m_rootParticleSystem)
	{
		if(m_duration == 0.0f)
			m_rootParticleSystem->bAutoDestroy = true;

		float WarmupTimeRemember = m_rootParticleSystem->Template->WarmupTime;
		m_rootParticleSystem->Template->WarmupTime = m_lifeTime;
		m_rootParticleSystem->ActivateSystem();
		m_rootParticleSystem->Template->WarmupTime = WarmupTimeRemember;
		m_rootParticleSystem->OnSystemFinished.AddDynamic(this, &AEffect::OnRootParticleSystemFinished);
	}
	else if(m_rootAudio)
	{
		m_rootAudio->OnAudioFinished.AddDynamic(this, &AEffect::OnRootAudioFinished);
	}
	else
	{
		GWWARNING(L"Effect root is not a particles system or an audio component [" + GetName() + L"]");
	}

	Super::BeginPlay();
	TArray<UActorComponent*> audioComponents = GetComponentsByClass(UAudioComponent::StaticClass());
	float volume = Cast<UDefaultGameInstance>(GetGameInstance())->GetPrefs()->sfxVolume;
	for (int32 i = 0; i < audioComponents.Num(); i++)
	{
		Cast<UAudioComponent>(audioComponents[i])->SetVolumeMultiplier(volume);
	}

	if (IsValid(m_followActor))
	{
		ANetworkCharacter* networkcharacter = Cast<ANetworkCharacter>(m_followActor);
		if(networkcharacter)
			networkcharacter->RegisterEffect(this);
	}
}
void AEffect::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	if (IsValid(m_followActor))
	{
		ANetworkCharacter* networkcharacter = Cast<ANetworkCharacter>(m_followActor);
		if (networkcharacter)
			networkcharacter->UnRegisterEffect(this);
	}
}
void AEffect::OnRootParticleSystemFinished(UParticleSystemComponent*)
{
	if(m_duration == 0.0f) // Only auto-destroy if duration was not set
		Destroy();
}
void AEffect::OnRootAudioFinished()
{
	if(m_duration == 0.0f) // Only auto-destroy if duration was not set
		Destroy();
}
AActor* AEffect::GetFollower() const
{
	return m_followActor;
}
void AEffect::DeactivateParticles()
{
	for(int32 i = 0; i < m_particleSystems.Num(); i++)
	{
		Cast<UParticleSystemComponent>(m_particleSystems[i])->DeactivateSystem();
	}
	deactivateParticlesBefore = 0.0f;
}
void AEffect::CalculatePosition_Implementation()
{
	if (m_followActor)
	{
		SetActorLocation(m_followActor->GetActorLocation());
		SetActorRotation(m_followActor->GetActorRotation());
	}
}
void AEffect::BeginEffect_Implementation()
{
}
void AEffect::Tick( float DeltaTime )
{
	Super::Tick( DeltaTime );

	CalculatePosition();

		m_lifeTime += DeltaTime;
	if(m_duration > 0.0f) // Only use timer if duration was set
	{
		if(deactivateParticlesBefore > 0.0f)
		{
			if((m_lifeTime + deactivateParticlesBefore) >= m_duration)
			{
				DeactivateParticles();
			}
		}

		if(m_lifeTime >= m_duration)
		{
			Destroy();
		}
	}
	if (m_follow && !IsValid(m_followActor))
		DeactivateParticles();
}
void AEffect::Init(float duration, AActor* followActor, bool clientSideOnly)
{
	if(clientSideOnly)
		bReplicates = false;
	m_duration = duration;
	m_followActor = followActor;
	BeginEffect();
	m_follow = IsValid(followActor);
}
void AEffect::End_Implementation()
{
	//check(Role == ROLE_Authority);
	if(deactivateParticlesBefore > 0.0f)
	{
		m_duration = deactivateParticlesBefore;
		m_lifeTime = 0.0f;
		DeactivateParticles();
		check(m_duration > 0.0f);
	}
	else
	{
		Destroy();
	}
}

void ATargetedEffect::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
	DOREPLIFETIME(ATargetedEffect, target);
}
