/*
 *  
 *  $Id: wnota.cpp $
 *  Ginkgo CADx Project
 *
 *  Copyright 2008-12 MetaEmotion S.L. All rights reserved.
 *  http://ginkgo-cadx.com
 *
 *  This file is licensed under LGPL v3 license.
 *  See License.txt for details
 *
 *
 */
#if defined(__DEPRECATED)
#undef __DEPRECATED
#endif
#include <list>
#include <vtkgl.h>
#include <cmath>
#include <cairo/cairo.h>

#include <wx/xml/xml.h>
#include <wx/menu.h>

#include <api/globals.h>
#include <api/internationalization/internationalization.h>
#include <api/math/geometry3d.h>

#include "wnota.h"
#include <api/ievento.h>
#include <api/iwidgetsrenderer.h>
#include <api/icontexto.h>
#include <api/iwidgetsmanager.h>

#include <main/managers/widgetsmanager.h>

#include <widgets/gui/selecciontexto.h>


#include <resources/ginkgoresourcesmanager.h>
#include <api/westilo.h>


#include "openglhelper.h"

#include <vtkRenderer.h>
#include <vtkCamera.h>

//====================================================================================================
//= Builder de notas
//====================================================================================================
GNC::GCS::Widgets::WNotaBuilder::WNotaBuilder(GNC::GCS::IWidgetsManager* pManager, const GNC::GCS::TriggerButton& buttonMask) : IWidgetBuilder(pManager, buttonMask)
{
	m_MouseDown = false;
	m_Estado = WBS_Ninguno;
	m_pTempWidget = NULL;
}

GNC::GCS::Widgets::WNotaBuilder::~WNotaBuilder()
{
	if (m_pTempWidget != NULL) {
		delete m_pTempWidget;
	}
}

void GNC::GCS::Widgets::WNotaBuilder::OnMouseEvents(GNC::GCS::Events::EventoRaton& evento)
{
	if (!m_pManager) {
		return;
	}
	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_Posicion= evento.iP;
		m_pManager->InsertarWidget(m_pTempWidget);
		m_pManager->LanzarEventoCreacion(m_pTempWidget);
		m_pTempWidget = NULL;
		evento.Skip(false);
		m_pManager->Modificado();

	} else if (evento.ButtonDown(m_ButtonMask)) {
		if (m_Estado != WBS_Ninguno) {
			return;
		}
		m_MouseDown = true;
		m_Posicion= evento.iP;
		if (m_pTempWidget != NULL) {
			delete m_pTempWidget;
		}
		m_pTempWidget = new WCajaTexto(m_pManager, evento.c->GetRenderer()->GetVID(), m_Posicion, "Nota de Texto");
		m_pManager->LanzarEventoCreacion(m_pTempWidget);
		m_pManager->Modificado();
		m_Estado = WBS_Creando;
		evento.Skip(false);
	} else if (evento.Dragging() && m_MouseDown) {
		if (m_Estado != WBS_Creando) {
			return;
		}
		m_Posicion= evento.iP;
		if (m_pTempWidget != NULL) {
			m_pTempWidget->m_Posicion = m_Posicion;
		}
		m_pManager->Modificado();
		evento.Skip(false);
	}else if( evento.Moving() ){
		GTRACE("Moviendose");
	}
}

void GNC::GCS::Widgets::WNotaBuilder::OnKeyEvents(GNC::GCS::Events::EventoTeclado&)
{
}

void GNC::GCS::Widgets::WNotaBuilder::Render(GNC::GCS::Contexto3D* c)
{
	if (m_Estado != WBS_Creando) {
		return;
	}
	if (m_pTempWidget == NULL) {
		return;
	}
	m_pTempWidget->Render(c);
}

GNC::GCS::Widgets::TipoCursor GNC::GCS::Widgets::WNotaBuilder::GetCursor()
{
	return GNC::GCS::Widgets::CUR_CREAR_ANOTACION;
}

//====================================================================================================
//= Widget de notas
//====================================================================================================
GNC::GCS::Widgets::WCajaTexto::WCajaTexto(IWidgetsManager* pManager, long vid, GNC::GCS::Vector posicion, const char* nombre, std::string texto) : IWidget(pManager, vid, nombre), GNC::GCS::Widgets::IWidgetSerializable()
{
	m_AnchoMaximo = 150.0f;
	m_Texto = texto;
	m_Vacio = false;
	m_MouseDown = false;
	m_ReservaRecursos = true;
	m_Posicion = posicion;
	m_pWidgetSeleccion = NULL;
}

GNC::GCS::Widgets::WCajaTexto::~WCajaTexto()
{
	LanzarEventoDestruccion();
	if (m_pWidgetSeleccion != NULL) {
		m_pWidgetSeleccion->Destroy();
		m_pWidgetSeleccion = NULL;
	}
}

//----------------------------------------------------------------------------------------------------
//region "Serializado y desserializado"
GNC::GCS::Widgets::WCajaTexto::WCajaTexto(IWidgetsManager* pManager, long vid, wxXmlNode* nodo):GNC::GCS::Widgets::IWidget(pManager, vid, "Nota de Texto"), GNC::GCS::Widgets::IWidgetSerializable(nodo)
{
	m_AnchoMaximo = 150.0f;

	wxString strTmp = nodo->GetPropVal(wxT("x"),wxT("0.0"));
	double doubleTmp;
	strTmp.ToDouble(&doubleTmp);
	m_Posicion.x = (float) doubleTmp;

	strTmp = nodo->GetPropVal(wxT("y"),wxT("0.0"));
	strTmp.ToDouble(&doubleTmp);
	m_Posicion.y = (float) doubleTmp;

	strTmp = nodo->GetPropVal(wxT("r"),wxT("1.0"));
	strTmp.ToDouble(&doubleTmp);
	m_Color.SetRF((float) doubleTmp);

	strTmp = nodo->GetPropVal(wxT("g"),wxT("1.0"));
	strTmp.ToDouble(&doubleTmp);
	m_Color.SetGF((float) doubleTmp);

	strTmp = nodo->GetPropVal(wxT("b"),wxT("1.0"));
	strTmp.ToDouble(&doubleTmp);
	m_Color.SetBF((float) doubleTmp);

	strTmp = nodo->GetPropVal(wxT("a"),wxT("1.0"));
	strTmp.ToDouble(&doubleTmp);
	m_Color.SetAF((float) doubleTmp);

	m_Texto = std::string(nodo->GetPropVal(wxT("text"),wxT("")).ToUTF8());

	m_Vacio = false;
	m_MouseDown = false;
	m_ReservaRecursos = true;
	m_pWidgetSeleccion = NULL;
}

wxXmlNode* GNC::GCS::Widgets::WCajaTexto::Serializar(const std::string& nombreMedico)
{
	wxXmlNode* resultado = new wxXmlNode(NULL,wxXML_ELEMENT_NODE,wxT("text_widget"));
	//almacenamos los dos nodos
	resultado->AddProperty(new wxXmlProperty(wxT("x"),wxString::Format(wxT("%f"),m_Posicion.x)));
	resultado->AddProperty(new wxXmlProperty(wxT("y"),wxString::Format(wxT("%f"),m_Posicion.y)));
	resultado->AddProperty(new wxXmlProperty(wxT("r"),wxString::Format(wxT("%f"),m_Color.RF())));
	resultado->AddProperty(new wxXmlProperty(wxT("g"),wxString::Format(wxT("%f"),m_Color.GF())));
	resultado->AddProperty(new wxXmlProperty(wxT("b"),wxString::Format(wxT("%f"),m_Color.BF())));
	resultado->AddProperty(new wxXmlProperty(wxT("a"),wxString::Format(wxT("%f"),m_Color.AF())));
	resultado->AddProperty(new wxXmlProperty(wxT("text"),wxString::FromUTF8(m_Texto.c_str())));
	//metadatos
	SerializarMetadatos(resultado,nombreMedico);
	return resultado;
}
//endregion

GNC::GCS::Widgets::WCajaTexto::TexturaNota* GNC::GCS::Widgets::WCajaTexto::GetTextura(void* renderer)
{
	if(m_mapaRecursos.find(renderer) == m_mapaRecursos.end()) {
		TexturaNota* pTextura = new TexturaNota();
		m_mapaRecursos[renderer] = pTextura;
		Recalcular(renderer);
	}
	return m_mapaRecursos[renderer];
}

void GNC::GCS::Widgets::WCajaTexto::Invalidar()
{
	for (TMapaRecursos::iterator it = m_mapaRecursos.begin(); it != m_mapaRecursos.end(); ++it) {
		TexturaNota* tn = (*it).second;
		tn->correcta = false;
	}
}

//----------------------------------------------------------------------------------------------------
//region "Colores"
void GNC::GCS::Widgets::WCajaTexto::SetColor(Color color) {
	if (m_Color != color) {
		m_Color = color;
		Invalidar();
		Modificar(true);
		m_pManager->LanzarEventoModificacion(this);
	}
}

const std::string& GNC::GCS::Widgets::WCajaTexto::GetTexto() const {
	return m_Texto;
}

void GNC::GCS::Widgets::WCajaTexto::SetTexto(const std::string& texto) {
	if (m_Texto != texto) {
		m_Texto = texto;
		ActualizarTimestampModificacion();
		Modificar(true);
	}
}

void GNC::GCS::Widgets::WCajaTexto::PropagarModificacion() {
	m_pManager->LanzarEventoModificacion(this);
}

const GNC::GCS::Widgets::Color& GNC::GCS::Widgets::WCajaTexto::GetColor() const {
	return m_Color;
}



void GNC::GCS::Widgets::WCajaTexto::OnMouseEvents(GNC::GCS::Events::EventoRaton& evento)
{
	if(EstaOculto()){
		return;
	}
	//------------------------------------------------------
	// Leaving
	else if (evento.Leaving() ) {
		Iluminar(false);
	}
	//------------------------------------------------------
	// Entering
	else if (evento.Entering() ) {
		if (m_MouseDown) {
			Iluminar(true);
		}
	}
	//------------------------------------------------------
	// Dragging
	if (evento.Dragging() && m_MouseDown) {
		if (EstaSeleccionado()) {
			Vector delta = evento.iP - m_PosCursor;
			m_PosCursor = evento.iP;
			m_Posicion += delta;
			LanzarEventoModificacion();
			Modificar(true);
			ConsumirEvento();
		}
		return;
	}
	//------------------------------------------------------
	// LeftDown
	else if (evento.LeftDown()) {

		if (EventoConsumido() && !evento.m_controlDown) {
			Seleccionar(false);
			return;
		}

		bool dentro = false;

		m_PosCursor= evento.iP;

		if (m_PosCursor.DentroDePoligono2(m_Quad, 4)) {
			if (evento.m_controlDown) { // Inversion de seleccion
				InvertirSeleccion();
			}
			else{
				Seleccionar(true);
			}
			dentro = true;
		}
		else { // Click fuera del texto
			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) {
			ActualizarTimestampModificacion();
			m_MouseDown = false;
			ConsumirEvento();
		}
		return;
	}
	else if (evento.ButtonDClick(GNC::GCS::Events::EventoRaton::EB_IZQUIERDO)) {
		if (!EventoConsumido()) {
			if (evento.iP.DentroDePoligono2(m_Quad,4)) {
				if (m_pWidgetSeleccion != NULL) {
					m_pWidgetSeleccion->Destroy();
					m_pWidgetSeleccion = NULL;
				}
				m_pWidgetSeleccion = new GNC::GCS::Widgets::Dialogos::SeleccionTexto(evento.c->pWindow, this, m_pManager);
				m_pWidgetSeleccion->Center();
				m_pWidgetSeleccion->ShowModal();
				ConsumirEvento();
			}
		}
	}
	//------------------------------------------------------
	// Moving
	else if (evento.Moving()) {
		if (EventoConsumido()) {
			Iluminar(false);
			return;
		}

		bool dentro = false;

		m_PosCursor= evento.iP;

		if (m_PosCursor.DentroDePoligono2(m_Quad,4)) {
			Iluminar(true);
			dentro = true;
		}
		else {
			Iluminar(false);
		}

		if (dentro) {
			ConsumirEvento();
		}
	}
}

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

bool GNC::GCS::Widgets::WCajaTexto::HitTest(float x, float y, const GNC::GCS::Vector& )
{
	return GNC::GCS::Vector(x,y).DentroDePoligono2(m_Quad, 4);
}

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

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

	TexturaNota* tn = GetTextura(c->GetRenderer());
	if(tn->texto != m_Texto || !tn->correcta) {
		Recalcular(c->GetRenderer());
	}
	GNC::GCS::TexturaCairo* tc = tn->m_textura;

	if (!tc->contextoCreado) {
		//std::cerr << "Error: Contexto no creado" << std::endl;
		return;
	}
	if (!tc->texturaCargada) {
		tc->Cargar();
	}
	if (tc->texturaModificada) {
		tc->Actualizar();
	}

	TVector texP0;

	// Compute display pos
	GNC::GCS::Vector3D planePos(m_Posicion.x, m_Posicion.y, (double)c->pRenderer->m_pImageViewer->GetTindex());
	GNC::GCS::Vector3D worldPos;
	GNC::GCS::Vector3D displayPos;

	c->pRenderer->m_pImageViewer->UnProyect2D(planePos.v, worldPos.v);
	c->pRenderer->WorldToDisplay(worldPos.v, displayPos.v);

	GNC::GCS::Vector alineacion = GNC::GCS::Vector(-m_TamTexto.x / 2.0f, (m_TamTexto.y / 2.0f));
	GNC::GCS::Vector pos = (GNC::GCS::Vector(displayPos.x, displayPos.y) + alineacion).Redondear();

	wDibujarTexturaTexto2D(c, *tc, pos);

	if (m_Seleccionado || m_Iluminado) {
		wAplicarColor(m_Iluminado, m_MouseDown, m_Seleccionado);
		wDibujarBordeTexto2D(c, *tc, pos);
	}

	const GNC::GCS::Vector& escala = c->RefRelacionImagenPantalla();

	// Center

	m_Quad[0] =  m_Posicion - (m_TamTexto * escala * GNC::GCS::Vector(0.5, -0.5));
	
	m_Quad[2].x = m_Quad[0].x + (double)tc->ancho * escala.x;
	m_Quad[2].y = m_Quad[0].y - (double)tc->alto * escala.y;

	m_Quad[1].x = m_Quad[2].x;
	m_Quad[1].y = m_Quad[0].y;

	m_Quad[3].x = m_Quad[0].x;
	m_Quad[3].y = m_Quad[2].y;

	// Apply camera transformation

	GNC::GCS::Vector pm = m_Quad[0].PuntoMedio(m_Quad[2]);

	for (int i = 0; i < 4; i++) {
		m_Quad[i].RotarSobreZ( pm, c->rotacion);
	}

	#if 0 // DEBUG
	wAplicarColor(true, false, false);
	glBegin(GL_LINE_LOOP);
	glVertex2d(m_Quad[0].x, m_Quad[0].y);
	glVertex2d(m_Quad[1].x, m_Quad[1].y);
	glVertex2d(m_Quad[2].x, m_Quad[2].y);
	glVertex2d(m_Quad[3].x, m_Quad[3].y);
	glEnd();
	#endif

}

bool GNC::GCS::Widgets::WCajaTexto::GetMenuContextual(wxMenu *menuContextual, wxWindow* pParent) {

	m_pWidgetSeleccion = new GNC::GCS::Widgets::Dialogos::SeleccionTexto(pParent, this, m_pManager);

	wxMenuItem* pMenuEditar = new wxMenuItem(menuContextual, 1, wxT("Editar texto"), wxT("Editar contenido de la nota"), wxITEM_NORMAL );
	menuContextual->Connect(1,wxEVT_COMMAND_MENU_SELECTED,wxCommandEventHandler( GNC::GCS::Widgets::Dialogos::SeleccionTexto::OnClickEnMenu),NULL,m_pWidgetSeleccion);

#ifdef __WXMSW__
	pMenuEditar->SetBitmaps(GinkgoResourcesManager::MenuIcons::GetIcoEditar());
#else
	pMenuEditar->SetBitmap(GinkgoResourcesManager::MenuIcons::GetIcoEditar());
#endif

	menuContextual->Append(pMenuEditar);
	return true;
}


void GNC::GCS::Widgets::WCajaTexto::Recalcular(void* renderer)
{
	TexturaNota* tn = GetTextura(renderer);
	GNC::GCS::TexturaCairo* tc = tn->m_textura;
	tn->correcta = true;

	if (!tc->contextoCreado) {
		tc->Redimensionar(32, 32);
	}

	std::string texto = m_Texto;
	if (texto.empty()) {
		texto = _Std("Double click to edit");
	}

	m_Texto = texto;

	tn->texto = texto;

	if (!tc->contextoCreado) {
		tc->Redimensionar(2, 2);
	}

	cairo_font_options_t* options;

	cairo_select_font_face (tc->cr, "Arial", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
	cairo_set_font_size(tc->cr, WIDGET_SIZE_FUENTE);
	options = cairo_font_options_create ();
	cairo_get_font_options(tc->cr, options);
	cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_NONE);
	cairo_set_font_options(tc->cr, options);
	cairo_font_options_destroy(options);
	options = NULL;

	m_TamTexto = GNC::GCS::GLHelper::calcularBoundingBox((*tc), m_Texto, m_AnchoMaximo); // Tamaño de la region en pixels

	tc->Redimensionar(std::ceil(m_TamTexto.x), std::ceil(m_TamTexto.y));
	m_TamTexto.Asignar(tc->ancho, tc->alto);

	cairo_select_font_face (tc->cr, "Arial", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
	cairo_set_font_size(tc->cr, WIDGET_SIZE_FUENTE);
	options = cairo_font_options_create ();
	cairo_get_font_options(tc->cr, options);
	cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_NONE);
	cairo_set_font_options(tc->cr, options);
	cairo_font_options_destroy(options);
	options = NULL;

	cairo_set_operator(tc->cr, CAIRO_OPERATOR_SOURCE);
	cairo_set_source_rgba(tc->cr, 0.0f, 0.0f, 0.0f, 0.0f);
	cairo_paint(tc->cr);

	GNC::GCS::GLHelper::dibujarTexto((*tc), m_Texto, m_Color, m_AnchoMaximo);
}

void GNC::GCS::Widgets::WCajaTexto::LiberarRecursos(GNC::GCS::IWidgetsRenderer* renderer)
{
	TMapaRecursos::iterator it = m_mapaRecursos.find(renderer);
	if(it!=m_mapaRecursos.end()) {
		delete (*it).second;
		m_mapaRecursos.erase(it);
	}
}

void GNC::GCS::Widgets::WCajaTexto::Seleccionar(bool seleccionado)
{
	if (m_Seleccionado != seleccionado) {
		m_Seleccionado = seleccionado;
		m_Modificado = true;
	}
}

void GNC::GCS::Widgets::WCajaTexto::Iluminar(bool iluminado)
{
	if (m_Iluminado != iluminado) {
		m_Iluminado = iluminado;
		m_Modificado = true;
	}
}

void GNC::GCS::Widgets::WCajaTexto::Ocultar(bool oculto)
{
	if (m_Oculto != oculto) {
		m_Oculto = oculto;
		m_Modificado = true;
	}
}

void GNC::GCS::Widgets::WCajaTexto::InsertarPropiedades(TListaMapasPropiedades &listaMapaPropiedades)
{
	TMapaPropiedades& primerMapa = listaMapaPropiedades.front();
	{
		 primerMapa[_Std("Text")] = m_Texto;
	}
}

void GNC::GCS::Widgets::WCajaTexto::OffscreenRender(GNC::GCS::Contexto3D* c)
{
	const GNC::GCS::Vector& escala = c->RefRelacionMundoPantallaOffscreen();
	TVector Pos = c->Reproyectar(m_Posicion) * c->factorReescalado;
	cairo_font_options_t* options;
	options = cairo_font_options_create ();

	cairo_select_font_face (c->cr, "Arial", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
	cairo_set_font_size(c->cr, std::max(WIDGET_SIZE_FUENTE * escala.x, (double)8.0f));
	cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_NONE);
	cairo_set_font_options(c->cr, options);

	m_TamTexto = GNC::GCS::Widgets::HelperTexto::calcularBoundingBox(c, m_Texto, m_AnchoMaximo * escala.x); // Tamaño de la region en pixels

	GNC::GCS::Vector puntoTexto(Pos.x - (m_TamTexto.x / 2.0f), Pos.y);
	puntoTexto.Redondear();
	cairo_set_source_rgba (c->cr, 1.0f, 1.0f, 1.0f, 1.0f);
	cairo_save(c->cr);
	cairo_translate(c->cr, puntoTexto.x, puntoTexto.y);
	GNC::GCS::Widgets::HelperTexto::dibujarTexto(c, m_Texto, GNC::GCS::Widgets::Color(m_Color.B8(), m_Color.G8(), m_Color.R8(), m_Color.A8()), m_AnchoMaximo * escala.x);
	cairo_restore(c->cr);

	cairo_font_options_destroy(options);
}
