
#include "tool3d.h"
#include "paint_canvas.h"
#include "../geometry/point_set.h"
#include "../geometry/vertex_group.h"

#include <QMouseEvent>


namespace Tl {

	Tool3D::Tool3D(PaintCanvas* canvas) 
		: canvas_(canvas)
		, left_button_down_(false)
		, right_button_down_(false)
	{
	}

	PaintCanvas* Tool3D::canvas() const {
		return canvas_ ;
	}

	void Tool3D::set_canvas(PaintCanvas* canvas) {
		canvas_ = canvas ;
	}

	void Tool3D::status(const std::string& value) {
		std::cout << value << "TODO: prompt user in status bar" << std::endl;
		// status_message() ;
	}

	Line3f Tool3D::get_mouse_line_in_3d_space(const QPoint& mouse) const {
		QPoint pos = mouse;
		Point3f p_near = canvas()->unProjectionOf(pos.x(), pos.y(), 0.0f);
		Point3f p_far  = canvas()->unProjectionOf(pos.x(), pos.y(), 1.0f);

		return Line3f(p_near, p_far);
	}

	Vector3f Tool3D::get_view_direction_in_3d_space(const QPoint& mouse) const {
		Line3f line = get_mouse_line_in_3d_space(mouse);
		Vector3f dir = -line.to_vector();
		Global::normalize(dir);
		return dir;
	}

	Point3f Tool3D::get_intersect_point(const Plane3f& plane, const QPoint& mouse, bool& success) const {
		Line3f line = get_mouse_line_in_3d_space(mouse);

		CGAL::Object obj = CGAL::intersection(line, plane);
		if (const Point3f * point = CGAL::object_cast<Point3f>(&obj)) {
			success = true;
			return *point;
		} else {
			success = false;
			return Point3f(0.0f, 0.0f, 0.0f);
		}
	}

	Vertex* Tool3D::get_intersect_vertex(const VertexGroup* g, const QPoint& mouse, float bbox_ratio/* = 0.01f*/) const {
		Line3f line = get_mouse_line_in_3d_space(mouse);
		Point3f p_near = canvas()->unProjectionOf(mouse.x(), mouse.y(), 0.0f);

		double squred_distance = FLT_MAX;
		Vertex* iv = nil;

		Bbox3f box = g->bbox();
		float x = box.xmax() - box.xmin();
		float y = box.ymax() - box.ymin();
		float z = box.zmax() - box.zmin();
		float dist_thresh = (x+y+z) / 3.0f * bbox_ratio;
		float sqr_dist_thresh = dist_thresh * dist_thresh;

		for (unsigned int i=0; i<g->size(); ++i) {
			Vertex* v = g->at(i);

			float sqr_dist_to_line = CGAL::squared_distance(line, v->point());
			if (sqr_dist_to_line < sqr_dist_thresh) {
				float sd = CGAL::squared_distance(v->point(), p_near);
				if (sd < squred_distance) {
					squred_distance = sd;
					iv = v;
				}
			}
		}

		return iv;
	}

	//////////////////////////////////////////////////////////////////////////	


	EmptyTool3D::EmptyTool3D(PaintCanvas* canvas) 
		: Tool3D(canvas)
	{
	}

}