/*
* Copyright (c) 2009 Stanford University, School of Medicine All rights reserved. 
* 
* STANFORD ACADEMIC SOFTWARE LICENSE AGREEMENT 
* FOR AngioLocalize SOURCE CODE: 
* 
* 1.  This is a legal agreement between you, RECIPIENT, and STANFORD UNIVERSITY.  
*       By accepting, receiving, and using AngioLocalize.including any accompanying information, materials or 
*       manuals (Program), you are agreeing to be bound by the terms of this Agreement.  
*       If you do not agree to the terms of this Agreement, promptly return the Program to the STANFORD.

* 2.  STANFORD grants to RECIPIENT a royalty-free, nonexclusive, and nontransferable license to use the Program 
*       and accompanying source code furnished hereunder, upon the terms and conditions set out below. 
*       documentation and/or other materials provided with the distribution. 
* 3.  RECIPIENT acknowledges that the Program is a research tool still in the development stage and that 
*       it is being supplied as is, without any accompanying services, support or improvements from STANFORD.
* 4.  RECIPIENT agrees to use the Program solely for internal non-commercial purposes. 
* 5.  RECIPIENT may create derivatives and further transfer the Program under the following terms and conditions: 
*        A) Recipient agrees to not commercially exploit the Program and agrees all uses will be for non-commercial purposes; and,
*        B) Recipient may not mark any derivatives with the title of Program and may not to use iPad mark for any derivatives; and,
*        C) Recipient agrees to mark and acknowledge all derivatives as follows: "This is a derivative work based on AngioLocalize:
*           Frameless AVM localization with 2D Digital Subtraction Angiography (DSA) and 3D Rotational Angiography (DRA) Images developed
*           by Dimitre Hristov, Lina Liu.
*        D) Recipient agrees to make all improvements, enhancements and derivatives available under 
*           similar terms and conditions to the research community. 
* 6.   RECIPIENT warrants that RECIPIENT will not remove or export any part of the software or Program from the United 
*       States except in full compliance with all United States and other applicable laws and regulations.
* 7.  RECIPIENT will use the Program in compliance with all applicable laws, policies and regulations including, but not 
*       limited to, any approvals, informed consent and patient confidentiality principles.
* 8.   RECIPIENT will indemnify, hold harmless, and defend Stanford against any claim of any kind arising out of or
*       related to the exercise of any rights granted under this Agreement or the breach of this Agreement by RECIPIENT.
* 9.  Title and copyright to the Program and any associated documentation shall at all times remain with STANFORD, 
*       and RECIPIENT agrees to preserve same.
*/ 
//----------------------------------------------------------------------------------
//! The ML module class XMarkerTransform.
/*!
// \file    mlXMarkerTransform.cpp
// \author  linal
// \date    2009-12-09
//
// 
*/
//----------------------------------------------------------------------------------

// Local includes
#include "mlXMarkerTransform.h"

ML_START_NAMESPACE


//! Implements code for the runtime type system of the ML
ML_BASEOP_CLASS_SOURCE(XMarkerTransform, BaseOp);

//----------------------------------------------------------------------------------
//! Constructor
//----------------------------------------------------------------------------------
XMarkerTransform::XMarkerTransform ()
  : BaseOp(0, 0)
{
  ML_TRACE_IN("XMarkerTransform::XMarkerTransform ()");

  // Suppress calls of handleNotification on field changes to
  // avoid side effects during initialization phase.
  handleNotificationOff();

  //! Get reference to the container for parameters/fields.
  FieldContainer &fields = *getFieldContainer();

  ML_CHECK(&fields);
  
  _matrix1Fld = fields.addMatrix("matrix1");
  _matrix2Fld = fields.addMatrix("matrix2");
  _matrix3Fld = fields.addMatrix("matrix3");

  (_inMarkerListFld = fields.addBase("inMarkerList"))->setBaseValue(NULL);

  // Generate field for marker list object.
  _outMarkerListFld = fields.addBase("outMarkerList");

  _inMarkerList = NULL;
  _outMarkerList = NULL;
  // Link marker list field to internal marker list object.
  _outMarkerListFld->setBaseValue(NULL);

  _apply1Fld = fields.addBool("apply1");
  _apply1Fld->setBoolValue(true);

  _apply2Fld = fields.addBool("apply2");
  _apply2Fld->setBoolValue(true);

  _apply3Fld = fields.addBool("apply3");
  _apply3Fld->setBoolValue(true);

  _autoApplyFld = fields.addBool("autoApply");
  _autoApplyFld->setBoolValue(false);

  _applyFld = fields.addNotify("apply");

  // Connect input fields with output field to update connected
  // modules if input images change.
  for (int inIdx=0; inIdx < 0; ++inIdx){
    for (int outIdx=0; outIdx < 0; ++outIdx){
      getInField(inIdx)->attachField(getOutField(outIdx));
    }
  }

  handleNotificationOn();
}

//----------------------------------------------------------------------------------
//! Handle field changes of the field field.
//----------------------------------------------------------------------------------
void XMarkerTransform::handleNotification (Field *field)
{
  ML_TRACE_IN("XMarkerTransform::handleNotification ()");

  if (_autoApplyFld->getBoolValue() == true || field == _applyFld
	  || field == _inMarkerListFld) {

      if (ML_BASE_IS_A((static_cast<Base*>(_inMarkerListFld->getBaseValue())), XMarkerList)){

		  _inMarkerList = static_cast<XMarkerList*>(_inMarkerListFld->getBaseValue());

		  if (_inMarkerList != NULL){

			/*if (!_isInNotificationCB) { 
				_inputList->addNotificationObserver(_csoListNotificationCB, this); 
			}*/
		  }
		} else {
		  _inMarkerList = NULL;
		}

	  if (_apply1Fld->getBoolValue() == true) {
		 AffineTransform(_matrix1Fld->getMatrixValue(), 1);
	  }
	  if (_apply2Fld->getBoolValue() == true) {
		 PerspectiveTransform(_matrix2Fld->getMatrixValue());
	  }
	  if (_apply3Fld->getBoolValue() == true) {
		 AffineTransform(_matrix3Fld->getMatrixValue(), 3);
	  }
	  _outMarkerListFld->setBaseValue(_outMarkerList);
  }

  // Handle changes of module parameters and connectors here.
  // For example:
  // if (getInField(0) == field){ /* Handle changes of input 0. */ }
  // if (fieldPtr == field){      /* Handle changes of a field added in constructor .*/ }
  // See section "Implementing handleNotification()" in ML Programming Guide for details.
  BaseOp::handleNotification(field);
}

//----------------------------------------------------------------------------------
//! Update internal module state after load or clone and enable notification handling again.
//----------------------------------------------------------------------------------
void XMarkerTransform::activateAttachments ()
{
  ML_TRACE_IN("XMarkerTransform::activateAttachments ()");

  // Update members to new field state here.
  // Call super class functionality to enable notification handling again.
  BaseOp::activateAttachments ();
}

//----------------------------------------------------------------------------------
//! This method use perspective transformation matrix to do the tranformation on inputCSOList
//! The result is put to outListFld.
//----------------------------------------------------------------------------------
void XMarkerTransform::AffineTransform (const mat4& matrix, int step)
{
	if (_inMarkerList == NULL)
			return;
	if (step == 1) {
		_outMarkerList = new XMarkerList(*_inMarkerList);
	} 

	for (size_t i = 0; i < _outMarkerList->getSize(); i ++) {
		XMarker *marker = (XMarker*)_outMarkerList->getItemAt(i);
		Tvec3<double> markerPos(marker->x(), marker->y(), marker->z());
		markerPos = (Tvec3<double>(matrix * markerPos.affinePoint(), true));
		marker->x() = markerPos[0];
		marker->y() = markerPos[1];
		marker->z() = markerPos[2];
		_outMarkerList->modifyItemAt(i, marker);
	}
}


//----------------------------------------------------------------------------------
//! This method use perspective transformation matrix to do the tranformation on inputCSOList
//! The result is put to outListFld.
//----------------------------------------------------------------------------------
void XMarkerTransform::PerspectiveTransform (const mat4& matrix)
{
	if (_outMarkerList == NULL)
		return;
	
	for (size_t i = 0; i < _outMarkerList->getSize(); i ++) {
		XMarker *marker = (XMarker*)_outMarkerList->getItemAt(i);
		Tvec3<double> markerPos(marker->x(), marker->y(), marker->z());
		markerPos = (Tvec3<double>(matrix * markerPos.affinePoint(), true)).divideByLastComp();
		marker->x() = markerPos[0];
		marker->y() = markerPos[1];
		marker->z() = 0.0;
		_outMarkerList->modifyItemAt(i, marker);
	}
}

ML_END_NAMESPACE

