/*
 *  
 *  $Id: wrectangulo.cpp $
 *  Ginkgo CADx Project
 *
 *  Copyright 2008-14 MetaEmotion S.L. All rights reserved.
 *  http://ginkgo-cadx.com
 *
 *  This file is licensed under LGPL v3 license.
 *  See License.txt for details
 *
 *
 */
//#define _GINKGO_TRACE
#include <api/globals.h>
#include "wrectangulo.h"
#include <api/ievento.h>
#include <api/icontexto.h>
#include <api/iwidgetsrenderer.h>
#include "main/managers/widgetsmanager.h"
#include <vtkgl.h>
#include <api/westilo.h>
#include <cmath>

//region "Implementacion de WRectanguloBuilder"

GNC::GCS::Widgets::WRectanguloBuilder::WRectanguloBuilder(TWidgetsManager* pManager, const GNC::GCS::TriggerButton& buttonMask, long gid) : GNC::GCS::Widgets::IWidgetBuilder(pManager, buttonMask, gid)
{
	m_MouseDown = false;
	m_Estado = WBS_Ninguno;
	m_Dentro = true;
}

GNC::GCS::Widgets::WRectanguloBuilder::~WRectanguloBuilder()
{
}

void GNC::GCS::Widgets::WRectanguloBuilder::OnMouseEvents(GNC::GCS::Events::EventoRaton& evento)
{
	if (!m_pManager) {
		return;
	}
	//------------------------------------------------------
	// Dragging
	if (m_MouseDown && evento.ButtonUp(m_ButtonMask)) {
		m_MouseDown = false;
		if (m_Estado != WBS_Creando) {
			m_Estado = WBS_Ninguno;
			return;
		}

		m_Estado = WBS_Ninguno;

		m_Stop= evento.iP;

		m_Vertices[0].Asignar(m_Start.x, m_Start.y);
		m_Vertices[1].Asignar(m_Stop.x, m_Start.y);
		m_Vertices[2].Asignar(m_Stop.x, m_Stop.y);
		m_Vertices[3].Asignar(m_Start.x, m_Stop.y);

		TVector diff = m_Stop - m_Start;
		if (std::abs(diff.x) > 0.001f && std::abs(diff.y) > evento.c->RelacionImagenPantalla().NormaInfinito()) {
			WRectangulo* w = new WRectangulo(m_Vertices, m_pManager, evento.c->GetRenderer()->GetVID(), "rectangulo", m_GID);
			m_pManager->InsertarWidget(w);
			m_pManager->LanzarEventoCreacion(w);
		}

		m_pManager->Modificado();
		m_Estado = WBS_Ninguno;
		ConsumirEvento();
	}
	else if (evento.ButtonDown(m_ButtonMask)) {
		if (m_Estado != WBS_Ninguno) {
			return;
		}
		GTRACE("WRectanguloBuilder::OnMouseEvents:: Left down)");
		m_MouseDown = true;

		m_Start= evento.iP;
		m_Stop = m_Start;

		m_Vertices[0].Asignar(m_Start.x, m_Start.y);
		m_Vertices[1].Asignar(m_Stop.x, m_Start.y);
		m_Vertices[2].Asignar(m_Stop.x, m_Stop.y);
		m_Vertices[3].Asignar(m_Start.x, m_Stop.y);

		m_pManager->Modificado();
		m_Estado = WBS_Creando;
		ConsumirEvento();
	}
	else if (evento.Dragging() && m_MouseDown) {
		if (m_Estado != WBS_Creando) {
			return;
		}
		GTRACE("WRectanguloBuilder::OnMouseEvents:: Creando...)");

		m_Stop= evento.iP;

		m_Vertices[0].Asignar(m_Start.x, m_Start.y);
		m_Vertices[1].Asignar(m_Stop.x, m_Start.y);
		m_Vertices[2].Asignar(m_Stop.x, m_Stop.y);
		m_Vertices[3].Asignar(m_Start.x, m_Stop.y);

		m_pManager->Modificado();
		ConsumirEvento();
	}
	else if( evento.Moving() ){
		m_NodoMoviendose= evento.iP;
		m_Estado = WBS_Ninguno;
	}
}

void GNC::GCS::Widgets::WRectanguloBuilder::OnKeyEvents(TEventoTeclado&)
{

}

void GNC::GCS::Widgets::WRectanguloBuilder::Render(GNC::GCS::Contexto3D* /*c*/)
{

	if (m_Estado == WBS_Creando) {
		glLineWidth(2.0f);
		glEnable(GL_LINE_STIPPLE);
		glLineStipple(3, 0xAAAA);
		glColor4f(0.0f, 0.5f, 0.0f, 0.75f);
		glBegin(GL_LINE_LOOP);
		glVertex2d(m_Vertices[0].x, m_Vertices[0].y);
		glVertex2d(m_Vertices[1].x, m_Vertices[1].y);
		glVertex2d(m_Vertices[2].x, m_Vertices[2].y);
		glVertex2d(m_Vertices[3].x, m_Vertices[3].y);
		glEnd();

		glDisable(GL_LINE_STIPPLE);
	}
	else {

	}
}

GNC::GCS::Widgets::TipoCursor GNC::GCS::Widgets::WRectanguloBuilder::GetCursor()
{
	return GNC::GCS::Widgets::CUR_CREAR_RECTANGULO;
}

//endregion



//region "Constructor y destructor"

GNC::GCS::Widgets::WRectangulo::WRectangulo(TVector bb[4], IWidgetsManager* pManager, long vid, const char* nombre, long gid) : GNC::GCS::Widgets::IWidget(pManager, vid, nombre, gid)
{
	m_Vertices[0] = bb[0];
	m_Vertices[1] = bb[1];
	m_Vertices[2] = bb[2];
	m_Vertices[3] = bb[3];
	m_MouseDown = false;
	m_UID = (long)this;
}

GNC::GCS::Widgets::WRectangulo::~WRectangulo()
{
	LanzarEventoDestruccion();
}

//endregion

void GNC::GCS::Widgets::WRectangulo::OnMouseEvents(GNC::GCS::Events::EventoRaton& evento)
{
	if(m_Oculto){
		return;
	}
	//------------------------------------------------------
	// Leaving
	if (evento.Leaving() ) {
		Iluminar(false);
	}
	//------------------------------------------------------
	// Entering
	else if (evento.Entering() ) {
		if (m_MouseDown) {
			Iluminar(true);
		}
	}
	//------------------------------------------------------
	// Dragging
	else if (evento.Dragging() && m_MouseDown) {
		Vector delta = evento.iP - m_PosCursor;
		m_PosCursor = evento.iP;

		if (EstaSeleccionado())  {
			m_Vertices[0] += delta;
			m_Vertices[1] += delta;
			m_Vertices[2] += delta;
			m_Vertices[3] += delta;
		}
		else if (m_Vertices[0].m_Seleccionado) {
			m_Vertices[3].x += delta.x;
			m_Vertices[0] += delta;
			m_Vertices[1].y += delta.y;
		}
		else if (m_Vertices[1].m_Seleccionado) {
			m_Vertices[2].x += delta.x;
			m_Vertices[1] += delta;
			m_Vertices[0].y += delta.y;
		}
		else if (m_Vertices[2].m_Seleccionado) {
			m_Vertices[1].x += delta.x;
			m_Vertices[2] += delta;
			m_Vertices[3].y += delta.y;
		}
		else if (m_Vertices[3].m_Seleccionado) {
			m_Vertices[0].x += delta.x;
			m_Vertices[3] += delta;
			m_Vertices[2].y += delta.y;
		}
		LanzarEventoModificacion();
		Modificar(true);
		ConsumirEvento();
		return;
	}
	//------------------------------------------------------
	// LeftDown
	else if (evento.LeftDown()) {

		if (EventoConsumido() && !evento.m_controlDown) {
			SeleccionarNodo(m_Vertices[0], false);
			SeleccionarNodo(m_Vertices[1], false);
			SeleccionarNodo(m_Vertices[2], false);
			SeleccionarNodo(m_Vertices[3], false);
			Seleccionar(false);
			return;
		}

		bool dentro = false;

		m_PosCursor= evento.iP;

		const GNC::GCS::Vector& factor = evento.c->RelacionImagenPantalla();

		for (int i = 0; i < 4 && !dentro; ++i)
		{
			if (m_Vertices[i].Hits(evento.iP, factor)) {
				SeleccionarNodo(m_Vertices[i], true);
				IluminarNodo(m_Vertices[i], true);
				for (int j = 0; j < 4; ++j)
				{
					if (i != j) {
						SeleccionarNodo(m_Vertices[i], false);
					}
				}
				Seleccionar(false);
				dentro = true;
			}
			else {
				SeleccionarNodo(m_Vertices[i], false);
				IluminarNodo(m_Vertices[i], false);
			}
		}

		if (!dentro) {
			if (evento.iP.DentroDePoligono2(m_Vertices, 4)) {
				if (evento.m_controlDown) { // Inversion de seleccion
					InvertirSeleccion();
				}
				else{
					Seleccionar(true);
				}
				dentro = true;
			}
			else { // Click fuera del nodo
				if (!evento.m_controlDown) {
					Seleccionar(false);
				}
				else {
					ConsumirEvento();
					if (EstaSeleccionado()) {
						m_MouseDown = true;
						m_PosCursor= evento.iP;
					}
				}
			}
		}

		if (dentro) {
			m_MouseDown = true;
			m_PosCursor= evento.iP;
			ConsumirEvento();
		}

		return;
	}
	//------------------------------------------------------
	// LeftUP
	else if (evento.LeftUp()) {
		if (m_MouseDown) {
			m_MouseDown = false;
			ConsumirEvento();
		}
	}
	//------------------------------------------------------
	// Moving
	else if (evento.Moving()) {
		if (EventoConsumido()) {
			IluminarNodo(m_Vertices[0], false);
			IluminarNodo(m_Vertices[1], false);
			IluminarNodo(m_Vertices[2], false);
			IluminarNodo(m_Vertices[3], false);
			Iluminar(false);
			return;
		}

		bool dentro = false;

		m_PosCursor= evento.iP;

		const GNC::GCS::Vector& factor = evento.c->RelacionImagenPantalla();

		for (int i = 0; i < 4 && !dentro; ++i)
		{
			if (m_Vertices[i].Hits(evento.iP, factor)) {
				IluminarNodo(m_Vertices[i], true);
				for (int j = 0; j < 4; ++j)
				{
					if (j != i) {
						IluminarNodo(m_Vertices[j], false);
					}
				}
				Iluminar(false);
				dentro = true;
			}
			else {
				IluminarNodo(m_Vertices[i], false);
			}
		}

		if (!dentro) {

			if (evento.iP.DentroDePoligono2(m_Vertices, 4)) {
				Iluminar(true);
				dentro = true;
			}
			else {
				Iluminar(false);
			}
		}

		if (dentro) {
			ConsumirEvento();
		}

		return;
	}
}

void GNC::GCS::Widgets::WRectangulo::OnKeyEvents(GNC::GCS::Events::EventoTeclado& evento)
{
	if (evento.GetKeyCode() == WXK_ESCAPE) {
		Seleccionar(false);
	}
}

bool GNC::GCS::Widgets::WRectangulo::HitTest(float /*x*/, float /*y*/, const GNC::GCS::Vector&)
{
	return false;
}

bool GNC::GCS::Widgets::WRectangulo::HitTest(GNC::GCS::Vector* vertices, int numVertices)
{
	return
		m_Vertices[0].DentroDePoligono2(vertices, numVertices) &&
		m_Vertices[1].DentroDePoligono2(vertices, numVertices) &&
		m_Vertices[2].DentroDePoligono2(vertices, numVertices) &&
		m_Vertices[3].DentroDePoligono2(vertices, numVertices);
}

void GNC::GCS::Widgets::WRectangulo::Render(GNC::GCS::Contexto3D* /*c*/)
{
	if(m_Oculto){
		return;
	}

	wColorSombra.Aplicar();
	glBegin(GL_QUADS);
	glVertex2d(m_Vertices[0].x, m_Vertices[0].y);
	glVertex2d(m_Vertices[1].x, m_Vertices[1].y);
	glVertex2d(m_Vertices[2].x, m_Vertices[2].y);
	glVertex2d(m_Vertices[3].x, m_Vertices[3].y);
	glEnd();

	if (m_Seleccionado) {
		glLineWidth(2.0f);
		glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
		glBegin(GL_LINE_LOOP);
		glVertex2d(m_Vertices[0].x, m_Vertices[0].y);
		glVertex2d(m_Vertices[1].x, m_Vertices[1].y);
		glVertex2d(m_Vertices[2].x, m_Vertices[2].y);
		glVertex2d(m_Vertices[3].x, m_Vertices[3].y);
		glEnd();
	}

	if (m_Vertices[0].m_Seleccionado || m_Vertices[0].m_Iluminado) {
		glPointSize(5.0f);
		if (m_Vertices[0].m_Seleccionado) {
			glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
		}
		else {
			glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
		}

		glBegin(GL_LINE_STRIP);
		glVertex2d(m_Vertices[3].x, m_Vertices[3].y);
		glVertex2d(m_Vertices[0].x, m_Vertices[0].y);
		glVertex2d(m_Vertices[1].x, m_Vertices[1].y);
		glEnd();

		glBegin(GL_POINTS);
		glVertex2d(m_Vertices[0].x, m_Vertices[0].y);
		glEnd();
	}
	else if (m_Vertices[1].m_Seleccionado || m_Vertices[1].m_Iluminado) {
		if (m_Vertices[1].m_Seleccionado) {
			glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
		}
		else {
			glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
		}

		glBegin(GL_LINE_STRIP);
		glVertex2d(m_Vertices[0].x, m_Vertices[0].y);
		glVertex2d(m_Vertices[1].x, m_Vertices[1].y);
		glVertex2d(m_Vertices[2].x, m_Vertices[2].y);
		glEnd();

		glPointSize(5.0f);
		glBegin(GL_POINTS);
		glVertex2d(m_Vertices[1].x, m_Vertices[1].y);
		glEnd();

	}
	else if (m_Vertices[2].m_Seleccionado || m_Vertices[2].m_Iluminado) {
		if (m_Vertices[2].m_Seleccionado) {
			glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
		}
		else {
			glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
		}

		glBegin(GL_LINE_STRIP);
		glVertex2d(m_Vertices[1].x, m_Vertices[1].y);
		glVertex2d(m_Vertices[2].x, m_Vertices[2].y);
		glVertex2d(m_Vertices[3].x, m_Vertices[3].y);
		glEnd();

		glPointSize(5.0f);
		glBegin(GL_POINTS);
		glVertex2d(m_Vertices[2].x, m_Vertices[2].y);
		glEnd();
	}
	else if (m_Vertices[3].m_Seleccionado || m_Vertices[3].m_Iluminado) {
		if (m_Vertices[3].m_Seleccionado) {
			glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
		}
		else {
			glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
		}

		glBegin(GL_LINE_STRIP);
		glVertex2d(m_Vertices[2].x, m_Vertices[2].y);
		glVertex2d(m_Vertices[3].x, m_Vertices[3].y);
		glVertex2d(m_Vertices[0].x, m_Vertices[0].y);
		glEnd();

		glPointSize(5.0f);
		glBegin(GL_POINTS);
		glVertex2d(m_Vertices[3].x, m_Vertices[3].y);
		glEnd();
	}
}

void GNC::GCS::Widgets::WRectangulo::OffscreenRender(GNC::GCS::Contexto3D* c)
{
	const GNC::GCS::Vector& escala = c->RefRelacionMundoPantallaOffscreen();

	TVector Vertices[4] = {c->Reproyectar(m_Vertices[0]) * c->factorReescalado, c->Reproyectar(m_Vertices[1]) * c->factorReescalado, c->Reproyectar(m_Vertices[2]) * c->factorReescalado, c->Reproyectar(m_Vertices[3]) * c->factorReescalado};

	cairo_set_line_width(c->cr, WIDGET_GROSOR_LINEA);

	// Color del cuerpo
	wColorNormal.AplicarCairo(c->cr);

	// Dibujo  de los puntos
	cairo_arc(c->cr, Vertices[0].x, Vertices[0].y, (WIDGET_SIZE_PUNTO / 2.0f) * escala.x, 0, M_2PI);
	cairo_fill(c->cr);
	cairo_arc(c->cr, Vertices[1].x, Vertices[1].y, (WIDGET_SIZE_PUNTO / 2.0f) * escala.x, 0, M_2PI);
	cairo_fill(c->cr);
	cairo_arc(c->cr, Vertices[2].x, Vertices[2].y, (WIDGET_SIZE_PUNTO / 2.0f) * escala.x, 0, M_2PI);
	cairo_fill(c->cr);
	cairo_arc(c->cr, Vertices[3].x, Vertices[3].y, (WIDGET_SIZE_PUNTO / 2.0f) * escala.x, 0, M_2PI);
	cairo_fill(c->cr);

	// Dibujo rectangulo
	cairo_move_to(c->cr, Vertices[0].x, Vertices[0].y);
	cairo_line_to(c->cr, Vertices[1].x, Vertices[1].y);
	cairo_line_to(c->cr, Vertices[2].x, Vertices[2].y);
	cairo_line_to(c->cr, Vertices[3].x, Vertices[3].y);
	cairo_line_to(c->cr, Vertices[0].x, Vertices[0].y);
	cairo_stroke(c->cr);
}

