/*
 *  
 *  $Id: ianotador.h $
 *  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 "iannotator.h"
#include <api/westilo.h>
#include <api/icontexto.h>
#include <api/iwidgetsrenderer.h>
#include <api/iwidgetsmanager.h>
#include <api/ivista.h>
#include <api/istudycontext.h>
#include <main/entorno.h>
#include <vtkginkgoimageviewer.h>
#include <api/dicom/dcmdictionary.h>
#include <api/internationalization/internationalization.h>
#include <vtkRenderWindow.h>
#include <vtkImageData.h>

GNC::GCS::IAnnotator::IAnnotator(GNC::GCS::IVista *pView): m_pView(pView)
{
}

GNC::GCS::IAnnotator::~IAnnotator()
{
}

std::string GNC::GCS::IAnnotator::GetAnnotationValue(GNC::GCS::Contexto3D* c, const std::string& key)
{
	if (key == "${NEWLINE}") {
		return "\n";
	} else if (key =="${GINKGO.VERSION.FULLTEXT}") {
		return GNC::Entorno::Instance()->GetGinkgoVersionString();
	} else if (key =="${GINKGO.ARCH}") {
		if (sizeof(void*) == 4) {
			return "32 bits";
		}
		else {
			return "64 bits";
		}
	} else if (key == "${VOLUME.IDX}") {
		if (m_pView != NULL && m_pView != NULL && m_pView->GetEstudio().IsValid()) {
			std::ostringstream ostr;
			ostr << m_pView->GetEstudio()->ActiveFileIndex + 1;
			return ostr.str();
		}
	} else if (key == "${SLICE.WIDTH}") {
		if (c->GetRenderer() != NULL && c->GetRenderer()->m_pImageViewer != NULL) {
			int dims[3];
			c->GetRenderer()->m_pImageViewer->GetDimensions(dims);
			std::ostringstream ostr;
			ostr << dims[0];
			return ostr.str();
		}
	} else if (key == "${SLICE.HEIGHT}") {
		if (c->GetRenderer() != NULL && c->GetRenderer()->m_pImageViewer != NULL) {
			int dims[3];
			c->GetRenderer()->m_pImageViewer->GetDimensions(dims);
			std::ostringstream ostr;
			ostr << dims[1];
			return ostr.str();
		}
	} else if (key == "${SLICE.WL.FULLTEXT}") {
		if (c->GetRenderer() != NULL && c->GetRenderer()->m_pImageViewer != NULL) {
			std::ostringstream ostr;
			ostr << "WL: ";
			ostr << std::setiosflags(ios::fixed) << std::setprecision(ANNOTATION_FP_PRECISION);
			ostr << c->GetRenderer()->m_pImageViewer->GetWindow() << "/" << c->GetRenderer()->m_pImageViewer->GetLevel();
			return ostr.str();
		}
	} else if (key == "${SLICE.IDX}") {
		if (c->GetRenderer() != NULL && c->GetRenderer()->m_pImageViewer != NULL) {
			std::ostringstream ostr;
			ostr << c->GetRenderer()->m_pImageViewer->GetTindex() + 1;
			return ostr.str();
		}
	} else if (key == "${SLICE.COUNT}") {
		if (c->GetRenderer() != NULL && c->GetRenderer()->m_pImageViewer != NULL) {
			int dims[3];
			c->GetRenderer()->m_pImageViewer->GetDimensions(dims);
			std::ostringstream ostr;
			ostr << dims[2];
			return ostr.str();
		}
	} else if (key == "${SLICE.IDX.FULLTEXT}") {
		if (c->GetRenderer() != NULL && c->GetRenderer()->m_pImageViewer != NULL && m_pView != NULL && m_pView->GetEstudio().IsValid()) {
			int dims[3];
			c->GetRenderer()->m_pImageViewer->GetDimensions(dims);
			std::ostringstream ostr;
			ostr << _Std("Slice") << ": " <<  c->GetRenderer()->m_pImageViewer->GetTindex() + 1 << " " << _Std("of") << " " << dims[2] << std::endl << _Std("Volume") << ": " << m_pView->GetEstudio()->ActiveFileIndex + 1;
			return ostr.str();
		}
	} else if (key == "${SLICE.VOXEL.SIZE}") {
		if (c->GetRenderer() != NULL && c->GetRenderer()->m_pImageViewer != NULL && m_pView != NULL && m_pView->GetEstudio().IsValid()) {
			double spacing[3];
			bool hasSpacing = m_pView->GetEstudio()->GetSpacingActive(spacing[0], spacing[1], spacing[2]);
			std::ostringstream ostr;
			if (hasSpacing) {
				ostr << std::setiosflags(ios::fixed) << std::setprecision(ANNOTATION_FP_PRECISION);
				ostr << _Std("Voxel:") << spacing[0] << "x" << spacing[1] << " mm.";
			}
			else {
				ostr << _Std("Image without metric information");
			}
			return ostr.str();
		}
	} else if (key == "${SLICE.THICKNESS}") {
		return GetFloatingPointTagWithPrecision(GKDCM_SliceThickness, "N/A", ANNOTATION_FP_PRECISION);		
	}  else if (key == "${SLICE.THICKNESS.FULLTEXT}") {
		if(ContainsTag(GKDCM_SliceThickness)) {
			std::ostringstream ostr;
			ostr << _Std("Slice thickness") << ": " << GetFloatingPointTagWithPrecision(GKDCM_SliceThickness, "N/A", ANNOTATION_FP_PRECISION) << " mm.";
			return ostr.str();
		}
	} else if (key == "${SLICE.LOCATION}") {
		return GetFloatingPointTagWithPrecision(GKDCM_SliceLocation, "N/A", ANNOTATION_FP_PRECISION);
	}  else if (key == "${SLICE.LOCATION.FULLTEXT}") {
		if(ContainsTag(GKDCM_SliceLocation)) {
			std::ostringstream ostr;
			ostr << _Std("Slice location") << ": " << GetFloatingPointTagWithPrecision(GKDCM_SliceLocation, "N/A", ANNOTATION_FP_PRECISION);
			return ostr.str();
		}
	} else if (key == "${VIEW.SCALE}") {
		if (c->GetRenderer() != NULL && c->GetRenderer()->m_pImageViewer != NULL) {
			double ppmm =  (c->GetRenderer()->m_pImageViewer->GetRenderWindow()->GetDPI() / 25.4); // pixels per mm
			double mmpp =  1.0 / ppmm; // mm per pixel
			double spacing[3];
			c->GetRenderer()->m_pImageViewer->GetSpacing(spacing);
			double onePixelHeight = c->GetRenderer()->m_pImageViewer->GetZoomFactor();
			std::ostringstream ostr;
			ostr << std::setiosflags(ios::fixed) << std::setprecision(ANNOTATION_FP_PRECISION);
			ostr << _Std("Scale") << " 1:" << ( (spacing[1] * mmpp) / onePixelHeight);
			return ostr.str();
		}
	} else if (key == "${SLICE.LATERALITY}") {
		std::string lat = GetTagValue(c, GKDCM_ImageLaterality);
		if(lat != "") {
			std::ostringstream ostr;
			if(lat=="R"){
				ostr << _Std("Right") << ";" ;
			}else if(lat=="L"){
				ostr << _Std("Left") << ";";
			}
			return ostr.str();
		}
	}
	
	return "";
}

std::string GNC::GCS::IAnnotator::GetFloatingPointTagWithPrecision(const std::string& key, const std::string& defValue, int precision)
{
	if (m_pView != NULL && m_pView->GetEstudio().IsValid()) {
		std::string value;
		if (m_pView->GetEstudio()->GetTagActiveImage(key, value) && !value.empty()) {

			double fpVal = 0.0f;

			std::istringstream is(value);
			is >> fpVal;

			std::ostringstream ostr;
			ostr << std::setiosflags(ios::fixed) << std::setprecision(precision);
			ostr << fpVal;
			return ostr.str();
		} 
	} 
	return defValue;
}

bool GNC::GCS::IAnnotator::ContainsTag(const std::string& key)
{
	if (m_pView != NULL && m_pView->GetEstudio().IsValid()) {
		std::string value;
		if (m_pView->GetEstudio()->GetTagActiveImage(key, value) && !value.empty()) {
			return true;
		} 
	} 
	return false;
}

std::string GNC::GCS::IAnnotator::GetTagValue(GNC::GCS::Contexto3D* /*c*/, const std::string& key, const std::string& defValue)
{
	if (m_pView != NULL && m_pView->GetEstudio().IsValid()) {
		std::string value;
		if (m_pView->GetEstudio()->GetTagActiveImage(key, value) && !value.empty()) {
			return value;
		} 
	} 
	return defValue;
}

std::string GNC::GCS::IAnnotator::GetPositionAnnotation(GNC::GCS::Contexto3D* c, const GNC::GCS::Vector3D& wP)
{
	if (c->pRenderer == NULL || c->pRenderer->m_pImageViewer == NULL) {
		return "";
	}
	std::ostringstream os;
	os.setf(ios::floatfield, ios::fixed );
	os.precision(2);
	os.fill('0');

	//double zpos = SeriesViewer->GetPipeline()->GetCurrentSliceIndex();

	double ip[3] = {0,0,0};
	c->pRenderer->m_pImageViewer->Proyect2D(wP.v, ip);
	int pp[3] = {0, 0, 0};
	int dims[3];

	c->GetRenderer()->m_pImageViewer->GetDimensions(dims);
				
	os << _Std("Position:") << " W:(" << wP.x << ", " << wP.y << "," << wP.z << "); I:(" << ip[0] << ", " << ip[1] << ", " << ip[2] << ")";

	//corregir de convencion DICOM a convenciotk

	c->GetRenderer()->m_pImageViewer->CoordenadasImagenACoordenadasPixel(ip, pp);
	if (pp[0]>=0 && pp[0] < dims[0] && pp[1]>=0 && pp[1] < dims[1] && pp[2] >=0 && pp[2] < dims[2]) {
		const vtkSmartPointer<vtkImageData>& pImg = c->GetRenderer()->m_pImageViewer->GetDataObject();
		if (pImg == NULL || pImg->GetNumberOfPoints() == 0)
		{
			return "";
		}
		void *scalar = pImg->GetScalarPointer( (int)pp[0], (int)pp[1], (int)pp[2] );		

		if( scalar ) {
			
			bool primero = true;
			double value = 0.0f;

			for(int i = 0; i< c->GetRenderer()->m_pImageViewer->GetNumberOfComponents(); i++) {				
				switch (c->GetRenderer()->m_pImageViewer->GetInput()->GetScalarType()) {
					case VTK_DOUBLE:
						value = (((double*)scalar)[i]);
						break;
					case VTK_FLOAT:
						value = (double) (((float*)scalar)[i]);
						break;
					case VTK_UNSIGNED_LONG:
						value = (double) (((unsigned long*)scalar)[i]);
						break;
					case VTK_LONG:
						value = (double) (((long*)scalar)[i]);
						break;
					case VTK_UNSIGNED_INT:
						value = (double) (((unsigned int*)scalar)[i]);
						break;
					case VTK_INT:
						value = (double) (((int*)scalar)[i]);
						break;
					case VTK_UNSIGNED_SHORT:
						value = (double) (((unsigned short*)scalar)[i]);
						break;
					case VTK_SHORT:
						value = (double) (((short*)scalar)[i]);
						break;
					case VTK_UNSIGNED_CHAR:
						value = (double) (((unsigned char*)scalar)[i]);
						break;
					case VTK_CHAR:
						value = (double) (((char*)scalar)[i]);
						break;
				}

				if(primero) {
					os << " " << _Std("Value:") << value;
				} else {
					os << "," << value;
				}
				primero = false;
			}
		}
	}

	return os.str();
}