/*
* ball_ops.cc
* DIN Is Noise is copyright (c) 2006-2024 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/

#include "ball_ops.h"
#include "ball.h"
#include "vector2d.h"
#include "mondrian.h"
#include "console.h"
#include "utils.h"
#include "chrono.h"
#include "ui_list.h"

extern char BUFFER[];
extern ui_clock ui_clk;
extern const float PI_BY_180;

int ball_op::eval (ball* b) {
	int ret = 0;
	if (alarm.active) {
		ret = alarm (ui_clk());
	}
	return ret;
}

turn::turn ()  {
	alarm.triggert = TRIGGERT;
	rd.set (-CLOCKWISE, ANTI_CLOCKWISE);
	vx = vy = 0;
	angle = 0;
}

void turn::gen_angle (ball* b) {
	vx = b->vx;
	vy = b->vy;
	angle = PI_BY_180 * rd ();
}

void turn::start (ball* b) {
	alarm.start ();
	gen_angle (b);
}

int turn::eval (ball* b) {
	if (alarm.active) {
		if (alarm (ui_clk())) {
			gen_angle (b);
		} else {
			b->vx = vx;
			b->vy = vy;
			rotate_vector (b->vx, b->vy, alarm () * angle);
			b->calc_velocity_slope ();
		}
	}
	return 1;
}

speed::speed () { 
	max = 0.0f;
	alarm.triggert = TRIGGERT;
	rd.set (-BRAKE, ACCELERATE);
	start = delta = 0;
}

void speed::gen_delta (ball* b) {
	start = b->V;
	delta = rd ();
}

int speed::eval (ball* b) {
	if (alarm.active) {
		if (alarm (ui_clk())) {
			gen_delta (b);
		} else {
			float a = alarm ();
			float s = start + a * delta;
			clamp (0.0f, s, max);
			b->V = s;
		}
	}
	return 1;
}

teleport::teleport () : radius (MAX_RADIUS) {
	extern const float TWO_PI;
	rd.set (0, TWO_PI);
}

int teleport::eval (ball* b) {
	int boe = ball_op::eval ();
	if (boe) {
		float theta = rd ();
		b->x += (radius * cos (theta));
		b->y += (radius * sin (theta));
		mondrian0.locate_ball (b);
	}
	return boe;
}

Clone::Clone () {
	max = 1;
	n = max;
	clone_can_clone = 0;
	offset = 0;
	alarm.active = 0;
	alarm.triggert = 1.0f;
}

extern ui_list uis;
int Clone::eval (ball* b) {
	int boe = ball_op::eval ();
	if (boe) {
		if (b->op_clone.n) {
			if (mondrian0.num_balls > max_balls) {
				sprintf (BUFFER, "Cant clone no more :( Reached Max of %d balls", max_balls);
				cons << RED << BUFFER << eol;
			} else {
				mondrian0.clone_ball (b);
				b->op_clone.n--;
			}
		} else {
			n = max;
			alarm.stop ();
			MENU.cb_clone.set_state (0, 0);
			cons << GREEN << "Finished cloning ball" << eol;
		}
	}
	return boe;
}

Transform::Transform () {
	alarm.triggert = 5;
}

int Transform::eval (ball* b) {
	int boe = ball_op::eval ();
	if (boe) {
		int t = rules [b->type];
		if (t == ball::INVALID) {
			rnd<float> rd (ball::BOUNCER, ball::HEALER);
			t = int (rd () + 0.5f);
		}
		b->set_type (t);
	}
	return boe;
}
