/* -----------------------------------------------------------------------
   See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
   ----------------------------------------------------------------------- */
#include "plmregister_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "demons.h"
#include "gpuit_demons.h"
#include "logfile.h"
#include "plm_image.h"
#include "plm_image_header.h"
#include "registration_data.h"
#include "stage_parms.h"
#include "volume.h"
#include "volume_resample.h"
#include "xform.h"

void
do_gpuit_demons_stage_internal (
    Registration_data* regd, 
    Xform *xf_out, 
    Xform *xf_in, 
    Stage_parms* stage)
{
    int d;
    Demons_parms parms;
    Plm_image_header pih;

    Volume* fixed = regd->fixed_image->get_vol_float ();
    Volume* moving = regd->moving_image->get_vol_float ();
    Volume::Pointer moving_ss;
    Volume::Pointer fixed_ss;
    Volume::Pointer moving_grad;
    Volume* vf_out = 0;
    Volume* vf_in = 0;

    volume_convert_to_float (moving);		    /* Maybe not necessary? */
    volume_convert_to_float (fixed);		    /* Maybe not necessary? */

    lprintf ("SUBSAMPLE: (%g %g %g), (%g %g %g)\n", 
	stage->fixed_subsample_rate[0], stage->fixed_subsample_rate[1], 
	stage->fixed_subsample_rate[2], stage->moving_subsample_rate[0], 
	stage->moving_subsample_rate[1], stage->moving_subsample_rate[2]
    );
    moving_ss = volume_subsample_vox_legacy (
        moving, stage->moving_subsample_rate);
    fixed_ss = volume_subsample_vox_legacy (
        fixed, stage->fixed_subsample_rate);

    moving_grad = Volume::New(volume_make_gradient (moving_ss.get()));

    demons_default_parms (&parms);
    parms.max_its = stage->max_its;
    parms.filter_std = stage->demons_std;
    parms.accel = stage->demons_acceleration;
    parms.homog = stage->demons_homogenization;
    parms.threading = stage->threading_type;
    for (d = 0; d < 3; d++) {
	parms.filter_width[d] = stage->demons_filter_width[d];
    }

    /* Transform input xform to gpuit vector field */
    if (xf_in->m_type == STAGE_TRANSFORM_NONE) {
	vf_in = 0;
    } else {
        pih.set_from_gpuit (fixed_ss->dim, 
            fixed_ss->offset, fixed_ss->spacing, 
            fixed_ss->direction_cosines);
	xform_to_gpuit_vf (xf_out, xf_in, &pih);
	vf_in = xf_out->get_gpuit_vf();
    }

    /* Run demons */
    vf_out = demons (fixed_ss.get(), moving_ss.get(), moving_grad.get(), 
        vf_in, &parms);

    /* Do something with output vector field */
    //xf_out->set_gpuit_vf (vf_out);
    xf_out->set_gpuit_vf (Volume::Pointer(vf_out));
}

void
do_gpuit_demons_stage (
    Registration_data* regd, 
    Xform *xf_out, 
    Xform *xf_in,
    Stage_parms* stage)
{
    do_gpuit_demons_stage_internal (regd, xf_out, xf_in, stage);
}
