// Oleg Petruny staff

#include "AAudioLiner.h"

AAAudioLiner::AAAudioLiner() {
	this->bCanBeDamaged = false;
	this->SetActorTickEnabled(true);
	this->SetTickableWhenPaused(true);
}

/*void AAudioLiner::createAudioLiner(float bpm, TArray<FAudioLine> linesIn, AAudioLiner *&Liner, bool bPrintWorkCountNew, bool bPrintWorkDetailsNew, bool bPrintLinesDetailsNew) {
	Liner = NewObject<AAudioLiner>();
	Liner->bps = 60/bpm;
	Liner->lines = linesIn;
	Liner->bPrintWorkCount = bPrintWorkCountNew;
	Liner->bPrintWorkDetails = bPrintWorkDetailsNew;
	Liner->bPrintLinesDetails = bPrintLinesDetailsNew;
}
*/
void AAAudioLiner::changeAAudioLine(TArray<FAAudioLineToChange> changes) {
	this->work.Append(changes);
}

void AAAudioLiner::Tick(float DeltaTime) {
	this->time += DeltaTime;
	//GEngine->AddOnScreenDebugMessage(-1, 0.01f, FColor::Yellow, FString::SanitizeFloat(this->time));
	//if (this->bps*0.25f > ((this->time - FMath::FloorToInt(this->time))) * this->bps || ((this->time - FMath::FloorToInt(this->time))) * this->bps > this->bps*0.75f) {
	//for (int i = 0; i < this->lines.Num(); i++) {
		//GEngine->AddOnScreenDebugMessage(-1, 0.01f, FColor::Yellow, this->lines[i].components[0]->IsActive() ? "True" : "False");
	//}
	if (this->bPrintWorkCount) {
		GEngine->AddOnScreenDebugMessage(-1, 0.01f, FColor::Yellow, "work count: " + FString::FromInt(this->work.Num()));
	}
	if (this->bPrintLinesDetails) {
		for (int a = 0; a < this->lines.Num(); a++) {
			GEngine->AddOnScreenDebugMessage(a + 1, 1.0f, FColor::Yellow, ("line: " + FString::FromInt(a) + " volume: " + FString::SanitizeFloat(this->lines[a].volume) + " id: " + FString::FromInt(this->lines[a].id)));
		}
	}
	for (int i = 0; i < this->work.Num(); i++) {
		if (this->bPrintWorkDetails) {
			GEngine->AddOnScreenDebugMessage(0, (this->work[i].delay != 0) ? 0.01f : 2.0f, FColor::Yellow, "work line: " + FString::FromInt(this->work[i].line) + " id: " + FString::FromInt(this->lines[this->work[i].line].id) + " delay: " + FString::SanitizeFloat(this->work[i].delay));
		}

		//GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, FString::SanitizeFloat((this->time <= work[i].line.group.components[work[i].line.group.id]->Sound->Duration) ? this->time :
			//this->time - (FMath::FloorToInt(this->time / work[i].line.group.components[work[i].line.group.id]->Sound->Duration) - 1) * work[i].line.group.components[work[i].line.group.id]->Sound->Duration));
		if (this->work[i].delay <= 0) {
			switch (this->work[i].change) {
				case EAAudioLineChange::Play:
				{
					this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->VolumeMultiplier = this->work[i].volume = this->lines[this->work[i].line].volume;
					if (this->work[i].fullSync) {
						this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Play(this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Sound->Duration * ((this->time / this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Sound->Duration) - (FMath::FloorToInt(this->time / this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Sound->Duration))));
					} else {
						this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Play(((this->time - FMath::FloorToInt(this->time))) * this->bps);
					}
					if (this->lines[this->work[i].line].id > 0) {
						//if (this->lines[this->work[i].line].components[this->lines[this->work[i].line].id - 1]->GetPlayState 0_0) {}
						if (this->lines[this->work[i].line].components[this->lines[this->work[i].line].id - 1]->IsPlaying()) {
							this->lines[this->work[i].line].components[this->lines[this->work[i].line].id - 1]->FadeOut(2, 0);
						}
					}
					if (this->lines[this->work[i].line].id < this->lines[this->work[i].line].components.Num() - 1) {
						this->lines[this->work[i].line].id++;
						this->work.Add(FAAudioLineToChange(this->work[i].line, EAAudioLineChange::FadeIn, true, this->work[i].volume, 1, this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Sound->Duration - this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Sound->Duration * ((this->time / this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Sound->Duration) - (FMath::FloorToInt(this->time / this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Sound->Duration))) - this->bps));
					}
					this->work.RemoveAt(i, 1, true);
					i--;
					break;
				}
				case EAAudioLineChange::Stop:
				{
					if (this->lines[this->work[i].line].id > 0) {
						for (int ii = 0; ii < this->work.Num(); ii++) {
							if (this->work[ii].line == this->work[i].line && ii != i) {
								this->work.RemoveAt(ii, 1, true);
								//break;
							}
						}
					}
					this->lines[this->work[i].line].volume = 0;
					if (this->work[i].fullSync) {
						if (bps * 0.25f > ((this->time - FMath::FloorToInt(this->time))) * bps || ((this->time - FMath::FloorToInt(this->time))) * bps > bps * 0.75f) {
							this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Stop();
							this->lines[this->work[i].line].id = 0;
							this->work.RemoveAt(i, 1, true);
							i--;
						}
					} else {
						this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Stop();
						this->lines[this->work[i].line].id = 0;
						this->work.RemoveAt(i, 1, true);
						i--;
					}
					break;
				}
				case EAAudioLineChange::FadeIn:
				{
					this->lines[this->work[i].line].volume = this->work[i].volume;
					if (this->work[i].fullSync) {
						this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->FadeIn(this->work[i].duration, this->work[i].volume, this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Sound->Duration * ((this->time / this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Sound->Duration) - (FMath::FloorToInt(this->time / this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Sound->Duration))));
					} else {
						this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->FadeIn(this->work[i].duration, this->work[i].volume, ((this->time - FMath::FloorToInt(this->time))) * bps);
					}
					if (this->lines[this->work[i].line].id > 0) {
						//if (this->lines[this->work[i].line].components[this->lines[this->work[i].line].id - 1]->GetPlayState 0_0) {}
						if (this->lines[this->work[i].line].components[this->lines[this->work[i].line].id - 1]->IsPlaying()) {
							this->lines[this->work[i].line].components[this->lines[this->work[i].line].id - 1]->FadeOut(2, 0);
						}
					}
					if (this->lines[this->work[i].line].id < this->lines[this->work[i].line].components.Num() - 1) {
						this->lines[this->work[i].line].id++;
						this->work.Add(FAAudioLineToChange(this->work[i].line, EAAudioLineChange::FadeIn, true, this->work[i].volume, 1, this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Sound->Duration - this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Sound->Duration * ((this->time / this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Sound->Duration) - (FMath::FloorToInt(this->time / this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->Sound->Duration))) - this->bps));
					}
					this->work.RemoveAt(i, 1, true);
					i--;
					break;
				}
				case EAAudioLineChange::FadeOut:
				{
					if (this->lines[this->work[i].line].components.Num() > 1) {
						for (int ii = 0; ii < this->work.Num(); ii++) {
							if (this->work[ii].line == this->work[i].line && ii != i) {
								this->work.RemoveAt(ii, 1, true);
								//break;
							}
						}
					}
					this->lines[this->work[i].line].volume = 0;
					if (this->work[i].fullSync) {
						if (this->bps * 0.25f > ((this->time - FMath::FloorToInt(this->time))) * this->bps || ((this->time - FMath::FloorToInt(this->time))) * this->bps > this->bps * 0.75f) {
							this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->FadeOut(this->work[i].duration, this->work[i].volume);
							this->lines[this->work[i].line].id = 0;
							this->work.RemoveAt(i, 1, true);
							i--;
						}
					} else {
						this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->FadeOut(this->work[i].duration, this->work[i].volume);
						this->lines[this->work[i].line].id = 0;
						this->work.RemoveAt(i, 1, true);
						i--;
					}
					break;
				}
				case EAAudioLineChange::Adjust:
				{
					if (this->lines[this->work[i].line].id > 0) {
						for (int ii = 0; ii < this->work.Num(); ii++) {
							if (this->work[ii].line == this->work[i].line && ii != i) {
								this->work[ii].volume = this->work[i].volume;
								//break;
							}
						}
					}
					this->lines[this->work[i].line].volume = this->work[i].volume;
					if (this->work[i].fullSync) {
						if (this->bps * 0.25f > ((this->time - FMath::FloorToInt(this->time))) * this->bps || ((this->time - FMath::FloorToInt(this->time))) * this->bps > this->bps * 0.75f) {
							this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->AdjustVolume(this->work[i].duration, this->work[i].volume);
							this->work.RemoveAt(i, 1, true);
							i--;
						}
					} else {
						this->lines[this->work[i].line].components[this->lines[this->work[i].line].id]->AdjustVolume(this->work[i].duration, this->work[i].volume);
						this->work.RemoveAt(i, 1, true);
						i--;
					}
					break;
				}
				default:
				{
					this->work.RemoveAt(i, 1, true);
					i--;
					break;
				}
			}
		} else {
			this->work[i].delay -= DeltaTime;
		}
	}
	//}

}