/*
 * $Id: spectraBox.cxx,v 4.0 2003/04/28 14:40:03 hut66au Exp $
 *
 * Imview, the portable image analysis application
 * http://www.cmis.csiro.au/Hugues.Talbot/imview
 * ----------------------------------------------------------
 *
 *  Imview is an attempt to provide an image display application
 *  suitable for professional image analysis. It was started in
 *  1997 and is mostly the result of the efforts of Hugues Talbot,
 *  Image Analysis Project, CSIRO Mathematical and Information
 *  Sciences, with help from others (see the CREDITS files for
 *  more information)
 *
 *  Imview is Copyrighted (C) 1997-2001 by Hugues Talbot and was
 *  supported in parts by the Australian Commonwealth Science and 
 *  Industry Research Organisation. Please see the COPYRIGHT file 
 *  for full details. Imview also includes the contributions of 
 *  many others. Please see the CREDITS file for full details.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 * */

/*------------------------------------------------------------------------
 *
 * The code for the spectrum display panel
 *
 * Hugues Talbot	 1 Aug 1998
 *      
 *-----------------------------------------------------------------------*/

#include <string.h>
#include "imview.hxx"
#include "spectraBox.hxx"
#include "saveSpect.hxx"
#include "printSpect.hxx"

extern savespect        *saveSpectPanel;
extern printspect       *printSpectPanel;

void mySpectraBox::setSpectrum(double *theSpectrum, int nbval)
{
    if (theSpectrum != 0) {
	if (spectrum) delete[] spectrum;
	spectrum = new double[nbval];
	memcpy(spectrum, theSpectrum, nbval*sizeof(double));
	nbSpectrumValues = nbval;
	recomputeLimits();
    } else {
	if (spectrum) delete[] spectrum;
	spectrum = 0;
	nbSpectrumValues = 0;
    }

    return;
}

void mySpectraBox::recomputeLimits(void)
{
    if (spectrum) {
	if (!absolute)
	    mins = maxs = spectrum[0];
	// else they have already been set to 0
	for (int i = 1 ; i < nbSpectrumValues ; i++) {
	    if (spectrum[i] > maxs) maxs = spectrum[i];
	    if (spectrum[i] < mins) mins = spectrum[i];
	}
	// special case of the char values.
	if (absolute && (mins >= 0.0) && (maxs <= 255.0)) {
	    mins = 0.0;
	    maxs = 255.0;
	}
	// what if they are both equal?
	if (maxs == mins)
	    maxs = 1.0;
	if (theSpectra) {
	    theSpectra->setAxisBoxesLimits(0, nbSpectrumValues,
					   mins, maxs);
	}
    }

    return;
}

int mySpectraBox::handle(int event)
{
    int retval = 0;
    int button;

    if (spectrum) {
	button = Fl::event_button();
	switch (event) {
	  case FL_PUSH:
	    handleButtonPushed();
	    retval = 1;
	    break;

	  case FL_DRAG:
	    handleButtonDragged();
	    retval = 1;
	    break;

	  case FL_RELEASE:
	    handleButtonReleased();
	    retval = 1;
	    break;

	  case FL_LEAVE:
	    // Return to normal cursor
	    fl_cursor(FL_CURSOR_DEFAULT);
	    retval = 1;
	    break;
	    
	  default:
	    retval = 0;
	    break;
	}
    }
    
    return retval;
}

void mySpectraBox::handleButtonPushed()
{

    fl_cursor((Fl_Cursor)MY_CURSOR_VLINE);
    handleButtonDragged();
    
    return;
}

void mySpectraBox::handleButtonDragged()
{
    int index;
    int xx = Fl::event_x();
    int realwidth = w() - WIDTHMARGIN;
    
    index = (int)(((double)xx-x()-WIDTHMARGIN/2)*(nbSpectrumValues-1)/realwidth);
    if ((index >= 0) && (index < nbSpectrumValues) && theSpectra) {
	theSpectra->setXValue(index);
	theSpectra->setYValue(spectrum[index]);
    } 
    return;
}

void mySpectraBox::handleButtonReleased()
{
    fl_cursor(FL_CURSOR_DEFAULT);

    return;
}

void mySpectraBox::draw()
{
    // superclass draw:
    draw_box();
    draw_label();

    if (spectrum != 0) {
	int xa, ya, xb, yb;
	int realwidth = w() - WIDTHMARGIN;
	int realheight = h() - HEIGHTMARGIN;

	fl_clip(x(),y(),w(),h());
	fl_color(FL_BLACK);
	for (int i = 1 ; i < nbSpectrumValues ; i++) {
	    xa = ((i-1)*realwidth)/(nbSpectrumValues-1) + WIDTHMARGIN/2;
	    ya = (int)((1.0 - (spectrum[i-1]-mins)/(maxs-mins))*realheight) + HEIGHTMARGIN/2;
	    xb = (i*realwidth)/(nbSpectrumValues - 1) + WIDTHMARGIN/2;
	    yb = (int)((1.0 - (spectrum[i]-mins)/(maxs-mins))*realheight) + HEIGHTMARGIN/2;
	    dbgprintf("Drawing from: (%d, %d) to (%d, %d)\n",
		      xa, ya, xb, yb);
	    fl_line(xa+x(), ya+y(), xb+x(), yb+y());
	}
	fl_pop_clip();
    }
    
    return; 
}


/// The spectra stuff

spectra::spectra()
{
    dbgprintf("Spectra display dialog created\n");
    spectraWindow = 0; // fluid depends on that
    spectraBox = 0;
    
    return;
}

void spectra::setDefaults(void)
{
    // we display relative values by default
    relative->set(); // button appearance
    spectraBox->setRelative(); // set the variable correctly
    spectrumTitle->value("Position: undefined");
    xvalue->value("0");
    yvalue->value("0");
    // the spectraBox needs to know us
    spectraBox->setSpectra(this);
    
    
    return;
}

// pass on the data...
void spectra::setData(double *s, int nb, int x, int y)
{
    static char buff[100];
    
    spectraBox->setSpectrum(s,nb);

    sprintf(buff, "Position: x=%d, y=%d", x, y);
    xIm = x;
    yIm = y;
    spectrumTitle->value(buff);

    return;
}

int spectra::visible()
{
    return spectraWindow->visible();
}

void spectra::redraw()
{
    spectraBox->redraw();
    return;
}

void spectra::show()
{
    spectraWindow->show();
}

void spectra::hide()
{
    spectraWindow->hide();
}

void spectra::setAxisBoxesLimits(double xminlimit, double xmaxlimit,
				 double yminlimit, double ymaxlimit)
{
    abcissaBox->setRange(xminlimit, xmaxlimit);
    ordinateBox->setRange(yminlimit, ymaxlimit);
    abcissaBox->redraw();
    ordinateBox->redraw();
}


/// The Spectra callbacks.

void relativecheck_cb(Fl_Check_Button *, spectra *panel)
{
    panel->displayRelative();
    return;
}

void absolutecheck_cb(Fl_Check_Button *, spectra *panel)
{
    panel->displayAbsolute();
    return;
}		      
    

void printbutton_cb(Fl_Button *, spectra *)
{
    dbgprintf("Print button pressed\n");
    if (printSpectPanel == 0) {
	printSpectPanel = new printspect;
	printspect &printref = *printSpectPanel;
	// initializes the fluid-generated panel
	printspect_panel(printref);
	// do our own initialization
	printSpectPanel->setDefaults();
    }

    // show the panel
    printSpectPanel->setCallerType(SPECTRAPANEL);
    printSpectPanel->show();
    
    return;
}

void savebutton_cb(Fl_Button *, spectra *)
{
    dbgprintf("Save button pressed\n");
    if (saveSpectPanel == 0) {
	saveSpectPanel = new savespect;
	savespect &saveref = *saveSpectPanel;
	// initializes the fluid-generated panel
	savespect_panel(saveref);
	// do our own initialization
	saveSpectPanel->setDefaults();
    }
    // show the panel
    saveSpectPanel->setCallerType(SPECTRAPANEL);
    saveSpectPanel->show();

    return;
}

void okbutton_cb(Fl_Return_Button*, spectra *panel)
{
    // this is very simple...
    panel->hide();
}
