// This source code is property of the Computer Graphics and Visualization
// chair of the TU Dresden. Do not distribute!
// Copyright (C) CGV TU Dresden - All Rights Reserved
//
#include "AtomicTransform.h"

#include <cgv/math/transformations.h>
#include <libs/cgv_gl/gl/gl.h>

#include "math_helper.h"

void AtomicTransform::set_limits(double lower, double upper)
{
	this->lower_limit = lower;
	this->upper_limit = upper;
	this->value = 0;
}

void AtomicTransform::set_value(const double &value, void *)
{
	this->value = value;
	changed_signal(value);
}

std::string AtomicTransform::get_name() const { return title; }
const double AtomicTransform::get_value(void *) const { return value; }
const double AtomicTransform::get_lower_limit() const { return lower_limit; }
const double AtomicTransform::get_upper_limit() const { return upper_limit; }

AtomicRotationTransform::AtomicRotationTransform(Vec3 axis)
	: axis(axis)
{
	lower_limit = -180;
	upper_limit = 180;
	value = 0;
}

Mat4 AtomicRotationTransform::calculate_matrix()
{
	return rotate(axis, (float)value);
}

void AtomicRotationTransform::drawIndicator(float size)
{
	if (lower_limit == upper_limit)
		return;
	//Calculate rotation matrix from x-axis to current axis
	Vec3 rot_axis = cgv::math::cross(Vec3(1, 0, 0), axis);
	float angle = acosf(axis.x() / axis.length());
	Mat4 t;
	if (angle == 0)
		t.identity();
	else
		t = rotate(rot_axis, angle * 180.0f / 3.1415926f);
	glBegin(GL_TRIANGLE_FAN);
	glVertex3f(0, 0, 0);
	for (float v = (float)lower_limit; v <= upper_limit; v += 5)
	{
		auto p = t * size * Vec4(0, -cosf(v * PI / 180.0f), -sinf(v * PI / 180.0f), 0);
		glVertex3f(p.x(), p.y(), p.z());
	}
	auto end = t * size * Vec4(0, -cosf((float)upper_limit * PI / 180.0f), -sinf((float)upper_limit * PI / 180.0f), 0);
	glVertex3f(end.x(), end.y(), end.z());
	glEnd();
}
void AtomicRotationTransform::drawActualIndicator(float size)
{
	//Calculate rotation matrix from x-axis to current axis
	Vec3 rot_axis = cgv::math::cross(Vec3(1, 0, 0), axis);
	float angle = acosf(axis.x() / axis.length());
	Mat4 t;
	if (angle == 0)
		t.identity();
	else
		t = rotate(rot_axis, angle * 180.0f / 3.1415926f);
	glBegin(GL_LINES);
	glVertex3f(0, 0, 0);
	auto p = t * size * Vec4(0, -cosf((float)value * PI / 180.0f), -sinf((float)value * PI / 180.0f), 0);
	glVertex3f(p.x(), p.y(), p.z());
	glEnd();
}

void AtomicRotationTransform::optimize_value(const Vec3 &local_vector, const Vec3 &target, bool inverse)
{
	/*Task: Implement parameter optimization*/

	// target into local_target
	// get dofs
	// project target into plane decided by which dofs exist
	// scal mult local_target and local_vector

	// use only degrees defined by dofs
	// if inverse == true use -angle with set_value()

	double result = 0.0;

	if (inverse)
		result = -result;

	set_value(result);
}

AtomicTranslationTransform::AtomicTranslationTransform(int dim)
	: dim(dim)
{
	lower_limit = -10;
	upper_limit = 10;
}

Mat4 AtomicTranslationTransform::calculate_matrix()
{
	Mat4 result;
	result.identity();
	result(dim, 3) = (float)value;
	return result;
}

void AtomicTranslationTransform::optimize_value(const Vec3 &local_vector, const Vec3 &target, bool inverse)
{
}