// Fill out your copyright notice in the Description page of Project Settings.


#include "EnvJitterActor.h"


// Sets default values
AEnvJitterActor::AEnvJitterActor()
{
 	// 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;
	
	// light
    Light_int_ub = 20.0f;
    Light_row_yaw = 45.0f;
	Light_row_pitch = 30.0f;
	Light_color_power = 0.5f;
	Light_dir_point_mul = 1000.0f;

	// fog
	max_fog_density = 0.08f;
	max_fog_opacity = 0.2f;
}

// Called when the game starts or when spawned
void AEnvJitterActor::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void AEnvJitterActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

void AEnvJitterActor::Handle_Command(FString command)
{
	// light
	if ((command == "light-int")||(command == "All"))
	{
		Light_Intensity();
		UE_LOG(LogTemp, Warning, TEXT("Light intensity Changed"));
	}
	if ((command == "light-dir")||(command == "All"))
	{
		Light_Direction();
		UE_LOG(LogTemp, Warning, TEXT("Light direction Changed"));
	}
	if ((command == "light-color")||(command == "All"))
	{
		Light_Color();
		UE_LOG(LogTemp, Warning, TEXT("Light color Changed"));
	}
	if ((command == "fog")||(command == "All"))
	{
		Fog_multiplier();
		UE_LOG(LogTemp, Warning, TEXT("Fog condition Changed"));
	}
}

// TODO: the pointlight and spotlight intensity has different scale from directionallight
void AEnvJitterActor::Light_Intensity()
{
	TArray<AActor*> FoundActors;
	// intensity
	float new_intensity = FMath::FRandRange(0.1f, Light_int_ub);
	
	UGameplayStatics::GetAllActorsOfClass(GetWorld(), ADirectionalLight::StaticClass(), FoundActors);
	for (int32 i=0; i<FoundActors.Num(); i++)
	{
		ADirectionalLight* LightInstance = Cast<ADirectionalLight>(FoundActors[i]);
		LightInstance->SetBrightness(new_intensity);
	}

	UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASpotLight::StaticClass(), FoundActors);
	for (int32 i=0; i<FoundActors.Num(); i++)
	{
		ASpotLight* LightInstance = Cast<ASpotLight>(FoundActors[i]);
		LightInstance->SetBrightness(new_intensity * Light_dir_point_mul);
	}

	UGameplayStatics::GetAllActorsOfClass(GetWorld(), APointLight::StaticClass(), FoundActors);
	for (int32 i=0; i<FoundActors.Num(); i++)
	{
		APointLight* LightInstance = Cast<APointLight>(FoundActors[i]);
		LightInstance->SetBrightness(new_intensity * Light_dir_point_mul);
	}
}

void AEnvJitterActor::Light_Direction()
{
	TArray<AActor*> FoundActors;
	float yaw_delta = FMath::FRandRange(-Light_row_yaw, Light_row_yaw);
	float pitch_delta = FMath::FRandRange(-Light_row_pitch, Light_row_pitch);
	UGameplayStatics::GetAllActorsOfClass(GetWorld(), ADirectionalLight::StaticClass(), FoundActors);
	for (int32 i=0; i<FoundActors.Num(); i++)
	{
		ADirectionalLight* LightInstance = Cast<ADirectionalLight>(FoundActors[i]);
		FRotator rotation = LightInstance->GetActorRotation();
		UE_LOG(LogTemp, Warning, 
					TEXT("Old rotation: %f %f %f"), 
					rotation.Pitch, rotation.Yaw, rotation.Roll);
		rotation.Yaw += yaw_delta;
		rotation.Pitch += pitch_delta;
		UE_LOG(LogTemp, Warning, 
					TEXT("New rotation: %f %f %f"), 
					rotation.Pitch, rotation.Yaw, rotation.Roll);
		LightInstance->SetActorRelativeRotation(rotation);
		if (rotation.Pitch < -175.0f)
		{
			rotation.Pitch += 100.0f;
		}
		if (rotation.Pitch > -5.0f)
		{
			rotation.Pitch -= 100.0f;
		}
		UE_LOG(LogTemp, Warning, 
					TEXT("Regularized rotation: %f %f %f"), 
					rotation.Pitch, rotation.Yaw, rotation.Roll);
		LightInstance->SetActorRelativeRotation(rotation);
	}

	UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASpotLight::StaticClass(), FoundActors);
	for (int32 i=0; i<FoundActors.Num(); i++)
	{
		ASpotLight* LightInstance = Cast<ASpotLight>(FoundActors[i]);
		FRotator rotation = LightInstance->GetActorRotation();
		rotation.Yaw += yaw_delta;
		rotation.Pitch += pitch_delta;
		if (rotation.Pitch < 190.0f)
		{
			rotation.Pitch += 100.0f;
		}
		if (rotation.Pitch > 350.0f)
		{
			rotation.Pitch -= 100.0f;
		}
		LightInstance->SetActorRelativeRotation(rotation);
	}

	UGameplayStatics::GetAllActorsOfClass(GetWorld(), APointLight::StaticClass(), FoundActors);
	for (int32 i=0; i<FoundActors.Num(); i++)
	{
		APointLight* LightInstance = Cast<APointLight>(FoundActors[i]);
		FRotator rotation = LightInstance->GetActorRotation();
		rotation.Yaw += yaw_delta;
		rotation.Pitch += pitch_delta;
		if (rotation.Pitch < 190.0f)
		{
			rotation.Pitch += 100.0f;
		}
		if (rotation.Pitch > 350.0f)
		{
			rotation.Pitch -= 100.0f;
		}
		LightInstance->SetActorRelativeRotation(rotation);
	}
}

void AEnvJitterActor::Light_Color()
{
	TArray<AActor*> FoundActors;
	// intensity

	float New_Red = FMath::FRandRange(0.0, 1.0f);
	New_Red = FMath::Pow(New_Red, Light_color_power);
	float New_Green = FMath::FRandRange(0.0, 1.0f);
	New_Green = FMath::Pow(New_Green, Light_color_power);
	float New_Blue = FMath::FRandRange(0.0, 1.0f);
	New_Blue = FMath::Pow(New_Blue, Light_color_power);

	UGameplayStatics::GetAllActorsOfClass(GetWorld(), ADirectionalLight::StaticClass(), FoundActors);
	for (int32 i=0; i<FoundActors.Num(); i++)
	{
		ADirectionalLight* LightInstance = Cast<ADirectionalLight>(FoundActors[i]);
		FLinearColor color = LightInstance->GetLightColor();
		UE_LOG(LogTemp, Warning, TEXT("Old Color: %f %f %f"), color.R, color.G, color.B);
		color.R = New_Red;
		color.G = New_Green;
		color.B = New_Blue;
		UE_LOG(LogTemp, Warning, TEXT("Color Changed"));
		UE_LOG(LogTemp, Warning, TEXT("New Color: %f %f %f"), color.R, color.G, color.B);
		LightInstance->SetLightColor(color);
	}

	UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASpotLight::StaticClass(), FoundActors);
	for (int32 i=0; i<FoundActors.Num(); i++)
	{
		ASpotLight* LightInstance = Cast<ASpotLight>(FoundActors[i]);
		FLinearColor color = LightInstance->GetLightColor();
		UE_LOG(LogTemp, Warning, TEXT("Old Color: %f %f %f"), color.R, color.G, color.B);
		color.R = New_Red;
		color.G = New_Green;
		color.B = New_Blue;
		UE_LOG(LogTemp, Warning, TEXT("Color Changed"));
		UE_LOG(LogTemp, Warning, TEXT("New Color: %f %f %f"), color.R, color.G, color.B);
		LightInstance->SetLightColor(color);
	}

	UGameplayStatics::GetAllActorsOfClass(GetWorld(), APointLight::StaticClass(), FoundActors);
	for (int32 i=0; i<FoundActors.Num(); i++)
	{
		APointLight* LightInstance = Cast<APointLight>(FoundActors[i]);
		FLinearColor color = LightInstance->GetLightColor();
		UE_LOG(LogTemp, Warning, TEXT("Old Color: %f %f %f"), color.R, color.G, color.B);
		color.R = New_Red;
		color.G = New_Green;
		color.B = New_Blue;
		UE_LOG(LogTemp, Warning, TEXT("Color Changed"));
		UE_LOG(LogTemp, Warning, TEXT("New Color: %f %f %f"), color.R, color.G, color.B);
		LightInstance->SetLightColor(color);
	}
}

void AEnvJitterActor::Fog_multiplier()
{
	float fog_density;
	float fog_opacity;
	if (FMath::FRandRange(0.0f, 1.0f) < 0.2)
	{
		fog_density = FMath::FRandRange(0.0f, max_fog_density);
		fog_opacity = FMath::FRandRange(0.0f, max_fog_opacity);
	}
	else
	{
		fog_density = 0.0f;
		fog_opacity = 0.0f;
	}
	
    
	TArray<AActor*> FoundActors;
	UGameplayStatics::GetAllActorsOfClass(GetWorld(), AExponentialHeightFog::StaticClass(), FoundActors);
	if (FoundActors.Num() <= 0)
	{
		UE_LOG(LogTemp, Warning, TEXT("No fog actor found"));
	}
	else
	{
		UE_LOG(LogTemp, Warning, TEXT("Fog actor found... "));
		AExponentialHeightFog * FogActor = Cast<AExponentialHeightFog>(FoundActors[0]);
		UExponentialHeightFogComponent * FogComponent = FogActor->GetComponent();
		FogComponent->SetFogDensity(fog_density);
		FogComponent->SetFogMaxOpacity(fog_opacity);
	}
}
