/*
 *  
 *  $Id: calibracion.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
 *
 *
 */
#include <wx/icon.h>
#include <wx/msgdlg.h>
#include <wx/ginkgostyle/ginkgostyle.h>
#include "calibracion.h"
#include <sstream>
#include <main/entorno.h>
#include <api/controllers/ieventscontroller.h>
#include <api/iwidgetsrenderer.h>
#include <vtk/vtkginkgoimageviewer.h>
#include <eventos/modificacionimagen.h>
#include <resources/ginkgoresourcesmanager.h>
#include <api/math/geometry3d.h>

#ifdef __DEPRECATED
#undef __DEPRECATED
#endif
#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <limits>

GNC::GCS::Widgets::Dialogos::Calibracion::Calibracion(wxWindow* parent, TWidget* pWidget, TManager* pManager) : CalibracionBase(parent)
{
	wxIcon icono;
	icono.CopyFromBitmap(GinkgoResourcesManager::MenuIcons::GetIcoCalibrarImagen());
	this->SetIcon(icono);

	m_pWidget = pWidget;
	m_pManager = pManager;

	float metricaDistancia = m_pWidget->m_Distancia;

	if (metricaDistancia > 1000.0f) {
		metricaDistancia = metricaDistancia / 1000.0f;
		m_unidades->SetSelection(3);
	}
	else if (metricaDistancia > 10.0f) {
		metricaDistancia = metricaDistancia / 10.0f;
		m_unidades->SetSelection(2);
	}
	else if (metricaDistancia < 1.0f) {
		metricaDistancia = metricaDistancia * 1000.0f;
		m_unidades->SetSelection(0);
	}
	else {
		m_unidades->SetSelection(1);
	}

	std::ostringstream os;

	os << metricaDistancia;

	m_ControlDistancia->SetValue(wxString::FromUTF8(os.str().c_str()));
}

GNC::GCS::Widgets::Dialogos::Calibracion::~Calibracion()
{
}

void GNC::GCS::Widgets::Dialogos::Calibracion::OnDialogoKeyDown( wxKeyEvent& event )
{
	if (event.GetKeyCode() == WXK_ESCAPE) {
		Close();
	}
	else if (event.GetKeyCode() == WXK_RETURN) {
		if (ValidarDouble(m_ControlDistancia->GetValue(),std::numeric_limits<GNC::GCS::Vector::TComp>::min(), 1000000)){
			Close();
			Calibrar();
		}
	}
	else {
		event.Skip();
	}
}

void GNC::GCS::Widgets::Dialogos::Calibracion::OnControlDistanciaKeyDown( wxKeyEvent& event )
{
	if (event.GetKeyCode() == WXK_ESCAPE) {
		Close();
	}
	if (event.GetKeyCode() == WXK_RETURN) {
		if (ValidarDouble(m_ControlDistancia->GetValue(),std::numeric_limits<GNC::GCS::Vector::TComp>::min(), 1000000)){
			Close();
			Calibrar();
		}
	}
	else {
		event.Skip();
	}
}

void GNC::GCS::Widgets::Dialogos::Calibracion::OnBotonCancelarClick( wxCommandEvent& /*event*/ )
{
	Close();
}

void GNC::GCS::Widgets::Dialogos::Calibracion::OnBotonAceptarClick( wxCommandEvent& /*event*/ )
{
	//validamos el campo
	if(ValidarDouble(m_ControlDistancia->GetValue(),std::numeric_limits<GNC::GCS::Vector::TComp>::min(), 1000000)){
		m_panelMedida->Hide();
		m_pPanelEspera->Show(true);
		Layout();
		if(Calibrar()){
			Close();
		} else {
			m_panelMedida->Show(true);
			m_pPanelEspera->Hide();
			Layout();
		}
	}
}

void GNC::GCS::Widgets::Dialogos::Calibracion::OnActivate(wxActivateEvent& /*event*/)
{
	m_panelMedida->SetFocus();
}

void GNC::GCS::Widgets::Dialogos::Calibracion::OnClickEnMenu(wxCommandEvent& /*event*/){
	Center();
	ShowModal();
}

bool GNC::GCS::Widgets::Dialogos::Calibracion::Calibrar()
{

	if (m_pWidget == NULL) {
		return false;
	}

	double oldSpacing[3];                    // Espaciado antiguo
	double newSpacing[3];                    // Nuevo espaciado

	GNC::GCS::Vector3D worldPosition0,worldPosition1, wDiff;

	double oldDist = m_pWidget->m_Distancia;  // Distancia antigua
	double newDist;                           // Nueva distancia

	std::string dist(m_ControlDistancia->GetValue().ToUTF8());
	std::istringstream is (dist);
	is >> newDist;

	if(m_unidades->GetSelection() == 0){
		newDist = newDist / 1000.0f;
	} else if(m_unidades->GetSelection() == 2){
		newDist = newDist * 10.0f;
	} else if(m_unidades->GetSelection() == 3){
		newDist = newDist * 1000.0f;
	}

	if(!ValidarDouble(newDist,(double)0.0000001f, (double)100000000.0f)) {
		return false;
	}

	newDist = std::abs(newDist);

	//proporcion...
	double proporcion = newDist / oldDist;

	m_pManager->GetRendererActivo()->m_pImageViewer->GetSpacing(oldSpacing);

	//const double raizDe3 = std::sqrt(3.0f);
	for (int i = 0; i< 3; ++i)
	{
		newSpacing[i] = proporcion * oldSpacing[i];
	}

	if(!ValidarDouble(newSpacing[0],std::numeric_limits<GNC::GCS::Vector::TComp>::min(), (double)1000000.0f)
		|| !ValidarDouble(newSpacing[1],std::numeric_limits<GNC::GCS::Vector::TComp>::min(), (double)1000000.0f)
		|| !ValidarDouble(newSpacing[2],std::numeric_limits<GNC::GCS::Vector::TComp>::min(), (double)1000000.0f)){
		return false;
	} else {
		//std::cout << "Nuevo espaciado: " << newSpacing[0] << ", " << newSpacing[1] << std::endl;

		GNC::GCS::Events::EventoModificacionImagen* pEvt = new GNC::GCS::Events::EventoModificacionImagen(m_pManager->GetVista(),GNC::GCS::Events::EventoModificacionImagen::ImagenRecalibrada,m_pWidget->GetVID());
		pEvt->SetOldSpacing(oldSpacing);
		pEvt->SetNewSpacing(newSpacing);

		double oldOrigin[3];                    // Origen antiguo
		m_pManager->GetRendererActivo()->m_pImageViewer->GetOrigin(oldOrigin);
		pEvt->SetOldOrigin(oldOrigin);
		pEvt->SetNewOrigin(oldOrigin);

		GNC::Entorno::Instance()->GetControladorEventos()->ProcesarEvento(pEvt);
		return true;
	}
}

bool GNC::GCS::Widgets::Dialogos::Calibracion::ValidarDouble(wxString wxStr, double min, double max ){
	if(wxStr != wxEmptyString ){
		double valor;
		if(!wxStr.ToDouble(&valor)) {
			wxMessageBox(_("The calibration value must be a decimal number"), _("Error"), wxICON_ERROR);
			return false;
		} else {
			if(valor <= min ){
				wxMessageBox(_("Calibration value is too low"), _("Error"), wxICON_ERROR);
				return false;
			}
			if(valor >= max){
				wxMessageBox(wxT("Calibration value is too high"), wxT("Error"), wxICON_ERROR);
				return false;
			}
		}
		return true;
	}
	wxMessageBox(_("Enter the calibration value"), _("Error"), wxICON_ERROR);
	return false;
}

bool GNC::GCS::Widgets::Dialogos::Calibracion::ValidarDouble(double valor, double min, double max ){
	if(valor<=min ){
		wxMessageBox(_("The calibration value is too low"), _("Error"), wxICON_ERROR);
		return false;
	}
	if(valor >=max){
		wxMessageBox(_("The calibration value is too high"), _("Error"), wxICON_ERROR);
		return false;
	}
	return true;
}
