/*===========================================================================
  Copyright (C) 1995-2009 European Southern Observatory (ESO)
 
  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., 675 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* .IDENT       midasutil.c                                */
/* .AUTHORS     Pascal Ballester (ESO/Garching)            */
/*              Cristian Levin   (ESO/La Silla)            */
/* .KEYWORDS    XLong, Spectroscopy, Long-Slit             */
/* .PURPOSE                                                */
/* .VERSION     1.0  Package Creation  17-MAR-1993       

    090821	last modif				   */
/* ------------------------------------------------------- */

#include <gl_defs.h>
#include <xm_defs.h>
#include <midas_def.h>
#include <main_defs.h>
#include <spec_defs.h>
#include <spec_comm.h>

#include <UxLib.h>

#define MAXCDESC	20
#define DEFAULT_SKY	"sky"

#define TOGGLE_STATE(x, y, z)   XmToggleButtonSetState(UxGetWidget(UxFindSwidget(x)), y, z);
#define SET_SENSITIVE(x, y)  XtSetSensitive(UxGetWidget(UxFindSwidget(x)), y);

extern int  file_exists(), AppendDialogText(), read_catalog_table();

extern void XmToggleButtonSetState();



int  exist_descriptor();
void ReadDefaultsLong();
void DisplayParamsLong();
void WriteKeyword();
void GetCdesc();

/****************************************************************************
 GetCdesc(): returns the 'desc' character descriptor from the image 'image'.
*/
void GetCdesc( image, desc, str )
char *image, *desc, *str;
{
    char value[MAXCDESC];
    int retval; /* useless */
    int id ;

    if ( file_exists(image, ".bdf") && exist_descriptor(image, desc) ) {
        SCFOPN(image, D_R4_FORMAT, 0, F_IMA_TYPE, &id);
        SCDGETC(id, desc, 1, MAXCDESC, &retval, value);
        SCFCLO(id);
    }
    else
        strcpy(value, "");

    strcpy(str,value);
}

/****************************************************************************
 exist_descriptor_table(): checks if the descriptor 'desc' exists in 'table'.
*/
int exist_descriptor_table( table, desc )
char *table;    /* name of the table */
char *desc;     /* descriptor name */
{
    int nulval, id;
    char type;

    if ( file_exists( table, ".tbl" ) ) {
        TCTOPN( table, F_I_MODE, &id);
        SCDFND( id, desc, &type, &nulval, &nulval );
        if ( type != ' ' ) {
            TCTCLO(id);
            return(TRUE);
        }
        TCTCLO(id);
    }
    return(FALSE);
}
/****************************************************************************
 exist_descriptor(): checks if the descriptor 'desc' exists in 'image'.
*/
int exist_descriptor( image, desc )
char *image;    /* name of the image */
char *desc;     /* descriptor name */
{
    int nulval, id;
    char type;

    if ( file_exists( image, ".bdf" ) ) {
        SCFOPN( image, D_R4_FORMAT, 0, F_IMA_TYPE, &id );
        SCDFND( id, desc, &type, &nulval, &nulval );
        if ( type != ' ' ) {
            SCFCLO(id);
            return(TRUE);
        }
        SCFCLO(id);
    }
    return(FALSE);
}

void UpdateDescriptors( frame )
char frame[];
{
    char str[MAXLINE];

    GetCdesc(frame, "INSTRUME", str);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_instrume")), str);
    strcpy(Instrume, str);
    WriteKeyword(str, K_INSTRUME);

    GetCdesc(frame, "IDENT", str);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_wlc")), str);
    strcpy(Wlc, frame);
    WriteKeyword(frame, K_WLC);
}

/*
void UpdateWlcIdent( frame )
char frame[];
{

}
*/

void UpdateRebinParameters()
{
    int unit;		/* useless */
    int actval, nulval;	/* useless */
    char str[MAXLINE];
    int id;

    if ( !exist_descriptor_table(Coerbr, "REBSTRT") ) 
	return;

    TCTOPN(Coerbr, F_I_MODE, &id);
    SCDRDD(id, "REBSTRT", 1, 1, &actval, &Rebstrt, &unit, &nulval);
    SCDRDD(id, "REBSTP", 1, 1, &actval, &Rebstp, &unit, &nulval);
    SCDRDD(id, "REBEND", 1, 1, &actval, &Rebend, &unit, &nulval);
    TCTCLO(id);

    sprintf(str, "%.3f", Rebstrt);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_rebstrt")), str);
    sprintf(str, "%.3f", Rebend);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_rebend")), str);
    sprintf(str, "%.6g", Rebstp);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_rebstp")), str);
}

void InitLong()
{
    ReadDefaultsLong();
    DisplayParamsLong();
}

void ReadDefaultsLong()
{
    int unit;		/* useless */
    int actval, nulval;	/* useless */

    SCKGETC("COERBR", 1, 20, &actval, Coerbr);
    SCKGETC("COORFIL", 1, 20, &actval, Coorfil);

/* main form */
    SCKGETC("SESSION", 1, 20, &actval, Session);
    SCKGETC("INSTRUME", 1, 20, &actval, Instrume);
    SCKGETC("WLC", 1, 20, &actval, Wlc);
    SCKRDI("YSTART", 1, 1, &actval, &Ystart, &unit, &nulval);
    SCKGETC("LINCAT", 1, 20, &actval, Lincat);
    SCKRDI("WRANG", 1, 2, &actval, Wrang, &unit, &nulval);
    SCKRDR("IMIN", 1, 1, &actval, &Imin, &unit, &nulval);

/* search form */
    SCKGETC("SEAMTD", 1, 12, &actval, Seamtd);
    SCKRDI("YWIDTH", 1, 1, &actval, &Ywidth, &unit, &nulval);
    SCKRDI("YSTEP", 1, 1, &actval, &Ystep, &unit, &nulval);
    SCKRDR("THRES", 1, 1, &actval, &Thres, &unit, &nulval);
    SCKRDI("WIDTH", 1, 1, &actval, &Width, &unit, &nulval);

/* wavelength calibration form */
    SCKGETC("WLCMTD", 1, 10, &actval, Wlcmtd);
    SCKRDR("TOL", 1, 1, &actval, &Tol, &unit, &nulval);
    SCKRDI("DCX", 1, 2, &actval, Dcx, &unit, &nulval);
    SCKRDI("WLCNITER", 1, 2, &actval, Wlcniter, &unit, &nulval);
    SCKRDR("ALPHA", 1, 1, &actval, &Alpha, &unit, &nulval);
    SCKRDR("MAXDEV", 1, 1, &actval, &Maxdev, &unit, &nulval);
    SCKGETC("GUESS", 1, 60, &actval, Guess);
/* later
    SCKRDR("SHIFT", 1, 1, &actval, &Shift, &unit, &nulval);
*/
    SCKGETC("COROPT", 1, 2, &actval, Coropt);
    SCKGETC("TWODOPT", 1, 2, &actval, Twodopt);
/* not yet used
    SCKRDR("AVDISP", 1, 1, &actval, &Avdisp, &unit, &nulval);
    SCKRDR("WCENTER", 1, 1, &actval, &Wcenter, &unit, &nulval);
*/

/* rebin form */
    SCKGETC("REBMTD", 1, 12, &actval, Rebmtd);
    SCKRDD("REBSTRT", 1, 1, &actval, &Rebstrt, &unit, &nulval);
    SCKRDD("REBEND", 1, 1, &actval, &Rebend, &unit, &nulval);
    SCKRDD("REBSTP", 1, 1, &actval, &Rebstp, &unit, &nulval);

/* flux calibration form */
    SCKGETC("EXTAB", 1, 60, &actval, Extab);
    SCKGETC("FLUXTAB", 1, 60, &actval, Fluxtab);
    SCKGETC("RESPTAB", 1, 60, &actval, Resptab);
    SCKGETC("PLOTYP", 1, 60, &actval, Plotyp);
    SCKGETC("FITYP", 1, 60, &actval, Fityp);
    SCKGETC("RESPONSE", 1, 60, &actval, Response);
    SCKRDI("FITD", 1, 1, &actval, &Fitd, &unit, &nulval);
    SCKRDR("SMOOTH", 1, 1, &actval, &Smooth, &unit, &nulval);

/* extraction form */
    SCKGETC("EXTMTD", 1, 10, &actval, Extmtd);
    SCKRDI("LOWSKY", 1, 2, &actval, Lowsky, &unit, &nulval);
    SCKRDI("UPPSKY", 1, 2, &actval, Uppsky, &unit, &nulval);
    SCKRDI("OBJECT", 1, 2, &actval, Objlim, &unit, &nulval);
    SCKRDI("SKYORD", 1, 1, &actval, &Skyord, &unit, &nulval);
    SCKRDI("ORDER", 1, 1, &actval, &Order, &unit, &nulval);
    SCKRDI("NITER", 1, 1, &actval, &Niter, &unit, &nulval);
    SCKRDI("RADIUS", 1, 1, &actval, &Radius, &unit, &nulval);
    SCKRDI("SKYMOD", 1, 1, &actval, &Skymod, &unit, &nulval);
    SCKRDR("RON", 1, 1, &actval, &Ron, &unit, &nulval);
    SCKRDR("GAIN", 1, 1, &actval, &Gain, &unit, &nulval);
    SCKRDR("SIGMA", 1, 1, &actval, &Sigma, &unit, &nulval);

    if ( Tol >= 0.0 )
	TolPixels = TRUE;
    else {
	TolPixels = FALSE;
	Tol = -Tol;
    }
}

void ReadParamsLong( session )
char session[];
{
    int unit;		/* useless */
    int actval, nulval;	/* useless */
    int id;

    TCTOPN(session, F_I_MODE, &id);
    strcpy(Session, session);

    SCDGETC(id, "COERBR", 1, 20, &actval, Coerbr);
    SCDGETC(id, "COORFIL", 1, 20, &actval, Coorfil);

/* main form */
    SCDGETC(id, "INSTRUME", 1, 20, &actval, Instrume);
    SCDGETC(id, "WLC", 1, 20, &actval, Wlc);
    SCDRDI(id, "YSTART", 1, 1, &actval, &Ystart, &unit, &nulval);
    SCDGETC(id, "LINCAT", 1, 20, &actval, Lincat);
    SCDRDI(id, "WRANG", 1, 2, &actval, Wrang, &unit, &nulval);
    SCDRDR(id, "IMIN", 1, 1, &actval, &Imin, &unit, &nulval);

/* search form */
    SCDGETC(id, "SEAMTD", 1, 12, &actval, Seamtd);
    SCDRDI(id, "YWIDTH", 1, 1, &actval, &Ywidth, &unit, &nulval);
    SCDRDI(id, "YSTEP", 1, 1, &actval, &Ystep, &unit, &nulval);
    SCDRDR(id, "THRES", 1, 1, &actval, &Thres, &unit, &nulval);
    SCDRDI(id, "WIDTH", 1, 1, &actval, &Width, &unit, &nulval);

/* wavelength calibration form */
    SCDGETC(id, "WLCMTD", 1, 10, &actval, Wlcmtd);
    SCDRDR(id, "TOL", 1, 1, &actval, &Tol, &unit, &nulval);
    SCDRDI(id, "DCX", 1, 2, &actval, Dcx, &unit, &nulval);
    SCDRDI(id, "WLCNITER", 1, 2, &actval, Wlcniter, &unit, &nulval);
    SCDRDR(id, "ALPHA", 1, 1, &actval, &Alpha, &unit, &nulval);
    SCDRDR(id, "MAXDEV", 1, 1, &actval, &Maxdev, &unit, &nulval);
    SCDGETC(id, "GUESS", 1, 60, &actval, Guess);
/* later
    SCDRDR(id, "SHIFT", 1, 1, &actval, &Shift, &unit, &nulval);
*/
    SCDGETC(id, "COROPT", 1, 2, &actval, Coropt);
    SCDGETC(id, "TWODOPT", 1, 2, &actval, Twodopt);
/* not yet used
    SCDRDR(id, "AVDISP", 1, 1, &actval, &Avdisp, &unit, &nulval);
    SCDRDR(id, "WCENTER", 1, 1, &actval, &Wcenter, &unit, &nulval);
*/
/* rebin form */
    SCDGETC(id, "REBMTD", 1, 12, &actval, Rebmtd);
    SCDRDD(id, "REBSTRT", 1, 1, &actval, &Rebstrt, &unit, &nulval);
    SCDRDD(id, "REBEND", 1, 1, &actval, &Rebend, &unit, &nulval);
    SCDRDD(id, "REBSTP", 1, 1, &actval, &Rebstp, &unit, &nulval);

/* flux calibration form */
    SCDGETC(id, "EXTAB", 1, 60, &actval, Extab);
    SCDGETC(id, "FLUXTAB", 1, 60, &actval, Fluxtab);
    SCDGETC(id, "RESPTAB", 1, 60, &actval, Resptab);
    SCDGETC(id, "PLOTYP", 1, 60, &actval, Plotyp);
    SCDGETC(id, "FITYP", 1, 60, &actval, Fityp);
    SCDGETC(id, "RESPONSE", 1, 60, &actval, Response);
    SCDRDI(id, "FITD", 1, 1, &actval, &Fitd, &unit, &nulval);
    SCDRDR(id, "SMOOTH", 1, 1, &actval, &Smooth, &unit, &nulval);

/* extraction form */
    SCDGETC(id, "EXTMTD", 1, 10, &actval, Extmtd);
    SCDRDI(id, "LOWSKY", 1, 2, &actval, Lowsky, &unit, &nulval);
    SCDRDI(id, "UPPSKY", 1, 2, &actval, Uppsky, &unit, &nulval);
    SCDRDI(id, "OBJECT", 1, 2, &actval, Objlim, &unit, &nulval);
    SCDRDI(id, "SKYORD", 1, 1, &actval, &Skyord, &unit, &nulval);
    SCDRDI(id, "ORDER", 1, 1, &actval, &Order, &unit, &nulval);
    SCDRDI(id, "NITER", 1, 1, &actval, &Niter, &unit, &nulval);
    SCDRDI(id, "RADIUS", 1, 1, &actval, &Radius, &unit, &nulval);
    SCDRDI(id, "SKYMOD", 1, 1, &actval, &Skymod, &unit, &nulval);
    SCDRDR(id, "RON", 1, 1, &actval, &Ron, &unit, &nulval);
    SCDRDR(id, "GAIN", 1, 1, &actval, &Gain, &unit, &nulval);
    SCDRDR(id, "SIGMA", 1, 1, &actval, &Sigma, &unit, &nulval);

    TCTCLO(id);

    if ( Tol >= 0.0 )
	TolPixels = TRUE;
    else {
	TolPixels = FALSE;
	Tol = -Tol;
    }
}

void DisplayParamsLong()
{
    int guess_selected;
    char str[MAXLINE];

    UpdateToggle = FALSE;  /* ==> the interface doesn't send SET/LONG */

/* main form */
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_session")), Session);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_instrume")), Instrume);
    GetCdesc(Wlc, "IDENT", str);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_wlc")), str);
    sprintf(str, "%d", Ystart);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_ystart")), str);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_lincat")), Lincat);
    sprintf(str, "%d", Wrang[0]);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_wrang1")), str);
    sprintf(str, "%d", Wrang[1]);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_wrang2")), str);
    sprintf(str, "%.5g", Imin);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_imin")), str);

/* search form */
    TOGGLE_STATE("rb_seamtd_gaus", !strncmp(Seamtd, "GAUS", 4), False);
    TOGGLE_STATE("rb_seamtd_grav", !strncmp(Seamtd, "GRAV", 4), False);
    TOGGLE_STATE("rb_seamtd_maxi", !strncmp(Seamtd, "MAXI", 4), False);
    sprintf(str, "%d", Ywidth);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_ywidth")), str);
    sprintf(str, "%d", Ystep);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_ystep")), str);
    sprintf(str, "%.1f", Thres);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_thres")), str);
    sprintf(str, "%d", Width);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_width")), str);

/* wavelength calibration form */
    sprintf(str, "%.2f", Tol);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_tol")), str);
    sprintf(str, "%d", Dcx[0]);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_dcx1")), str);
    sprintf(str, "%d", Dcx[1]);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_dcx2")), str);
    sprintf(str, "%d", Wlcniter[0]);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_wlcniter1")), str);
    sprintf(str, "%d", Wlcniter[1]);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_wlcniter2")), str);
    sprintf(str, "%.1f", Alpha);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_alpha")), str);
    sprintf(str, "%.1f", Maxdev);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_maxdev")), str);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_guess")), Guess);
/* later
    sprintf(str, "%.1f", Shift);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_shift")), str);
*/
    TOGGLE_STATE("tg_coropt", !strncmp(Coropt, "YE", 2), False);
    TOGGLE_STATE("tg_twodopt", !strncmp(Twodopt, "YE", 2), False);

    guess_selected = !strncmp(Wlcmtd, "GUES", 4);
    TOGGLE_STATE("rb_wlcmtd_iden", !guess_selected, True);
    TOGGLE_STATE("rb_wlcmtd_gues", guess_selected, True);
    SET_SENSITIVE("guess_session_label", guess_selected);
    SET_SENSITIVE("tf_guess", guess_selected);
/* later
    SET_SENSITIVE("shift_label", guess_selected);
    SET_SENSITIVE("tf_shift", guess_selected);
*/
    SET_SENSITIVE("tg_coropt", guess_selected);

    if ( TolPixels )
	UxPutMenuHistory(UxFindSwidget("mn_tol"), "mn_tol_pixels");
    else
	UxPutMenuHistory(UxFindSwidget("mn_tol"), "mn_tol_angstroms");

/* rebin form */
    sprintf(str, "%.2f", Rebstrt);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_rebstrt")), str);
    sprintf(str, "%.2f", Rebend);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_rebend")), str);
    sprintf(str, "%.6g", Rebstp);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_rebstp")), str);
    TOGGLE_STATE("rb_rebmtd_line", !strncmp(Rebmtd, "LINE", 4), False);
    TOGGLE_STATE("rb_rebmtd_quad", !strncmp(Rebmtd, "QUAD", 4), False);
    TOGGLE_STATE("rb_rebmtd_spli", !strncmp(Rebmtd, "SPLI", 4), False);

    UpdateToggle = TRUE;  /* ==> the interface can send SET/LONG again */

/* flux calibration form */
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_extin_tbl")), Extab);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_flux_tbl")), Fluxtab);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_output_resp")), Response);
    TOGGLE_STATE("rb_plotyp_rati", !strncmp(Plotyp, "RATI", 4), False);
    TOGGLE_STATE("rb_plotyp_colo", !strncmp(Plotyp, "COLO", 4), False);
    TOGGLE_STATE("rb_fityp_poly", !strncmp(Fityp, "POLY", 4), False);
    TOGGLE_STATE("rb_fityp_spli", !strncmp(Fityp, "SPLI", 4), False);
    sprintf(str, "%d", Fitd);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_fitd")), str);
    sprintf(str, "%.2f", Smooth);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_smooth")), str);

/* extraction form */
    sprintf(str, "%d", Lowsky[0]);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_lowsky1")), str);
    sprintf(str, "%d", Lowsky[1]);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_lowsky2")), str);
    sprintf(str, "%d", Uppsky[0]);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_uppsky1")), str);
    sprintf(str, "%d", Uppsky[1]);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_uppsky2")), str);
    sprintf(str, "%d", Objlim[0]);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_object1")), str);
    sprintf(str, "%d", Objlim[1]);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_object2")), str);
    sprintf(str, "%d", Skyord);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_skyord")), str);
    sprintf(str, "%d", Order);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_order")), str);
    sprintf(str, "%d", Niter);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_niter")), str);
    sprintf(str, "%d", Radius);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_radius")), str);
    sprintf(str, "%g", Ron);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_ron")), str);
    sprintf(str, "%g", Gain);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_gain")), str);
    sprintf(str, "%g", Sigma);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_sigma")), str);
    TOGGLE_STATE("rb_extmtd_line", !strncmp(Extmtd, "LINE", 4), False);
    TOGGLE_STATE("rb_extmtd_aver", !strncmp(Extmtd, "AVER", 4), False);
    TOGGLE_STATE("rb_skymod_0", !Skymod, False);
    TOGGLE_STATE("rb_skymod_1", Skymod, False);
    XmTextSetString(UxGetWidget(UxFindSwidget("tf_sky")), DEFAULT_SKY);
}

int GetCoords( data, ncoords )
int data[];
int ncoords;
{
    int nulval, sortcol, aw, ar, ncols, nrows;
    char str[MAXLINE];
    int aux, i, id, col_yw;

    if ( ! file_exists( Coorfil, ".tbl" ) ) {  /* do nothing */
	sprintf(str, "*** Error: table %s could not be opened ***", Coorfil);
	SCTPUT(str);
        return FALSE;
    }

    TCTOPN(Coorfil, F_I_MODE, &id);

    TCIGET(id, &ncols, &nrows, &sortcol, &aw, &ar);
    if ( nrows < ncoords ) {
	sprintf(str, "*** Error: only %d points given ***", nrows);
	SCTPUT(str);
    	TCTCLO(id);
        return FALSE;
    }
    TCCSER(id, ":y_wcoord", &col_yw);
    if ( col_yw == -1 ) {
	SCTPUT("*** Error: missing column :y_wcoord in 'COORTAB' ***");
    	TCTCLO(id);
        return FALSE;
    }

    for ( i = 0; i < ncoords; i++ )
        TCERDI(id, i+1, col_yw, &data[i], &nulval);

    /* Now order from less to greater by pairs */
    for ( i = 0; i < ncoords - 1; i += 2 )
	if ( data[i] > data[i+1] ) {
	    aux = data[i+1];
	    data[i+1] = data[i];
	    data[i] = aux;
	}

    TCTCLO(id);

    return TRUE;
}

/******************************************************************************
 exist_airmass(): checks if the descriptor O_AIRM or AIRMASS exists in 'image'.
                  if it exists, returns the value in the variable 'airmass'.
*/
int exist_airmass( image, airmass )
char *image;
float *airmass;
{
    int nulval; 
    char descnam[10];
    int unit;
    int id;

    if ( exist_descriptor(image, "O_AIRM") )
        strcpy(descnam, "O_AIRM");
    else if ( exist_descriptor(image, "AIRMASS") )
        strcpy(descnam, "AIRMASS");
    else
        return FALSE;

    SCFOPN(image, D_R4_FORMAT, 0, F_IMA_TYPE, &id);
    SCDRDR( id, descnam, 1, 1, &nulval, airmass, &unit, &nulval );
    SCFCLO(id);

    return TRUE;
}

void WriteKeyword( text, keyword_cmd )
char *text;
char *keyword_cmd;
{
    char command[MAXLINE];

    sprintf(command, "%s%s", keyword_cmd, text);
    AppendDialogText(command);
}

/*******************************************************************

  Routines and variables needed to display the line catalog table in
  a selection list.

********************************************************************/

static LCTAB *  Lc = NULL;      /* Line catalog table */
static char *   List[MAXTEXT];
static int      LincatAllocated = FALSE;

float *fvector();
int *ivector();
char **cmatrix();

void free_catalog_table();
void free_lincat();

/*****************************************************************
 * read_lincat_table(): reads line catalog named by 'Lincat' and
 * stores the values in the 'Lc' structure, under the
 * restrictions Wrang & Imin.
 *****************************************************************/
int read_lincat_table()
{
    if ( ! file_exists( Lincat, ".tbl" ) ) {
        SCTPUT( "*** Line catalogue doesn't exist ***" );
        return(FALSE);
    }

    if ( Lc != NULL ) /* deallocate space */
        free_catalog_table(Lc);

    Lc  = (LCTAB *)osmmget( sizeof(LCTAB) );

    if( !read_catalog_table( Lc, Lincat, Wrang, Imin ) ) {
        Lc = NULL;

        return FALSE;
    }
    return TRUE;
}

void display_lincat_table( wlist )
Widget wlist;
{
    int i;
    XmStringTable str_list;

    if ( LincatAllocated )
        free_lincat();
    LincatAllocated = TRUE;

    for ( i = 0; i < Lc->nrows; i++ )
        List[i] = (char *)osmmget( 80 );
    List[Lc->nrows] = NULL;

    for ( i = 0; i < Lc->nrows; i++ )
        sprintf( List[i], "    %8.2f", Lc->wave[i]);

    str_list = (XmStringTable)XtMalloc(Lc->nrows * sizeof(XmString *));
    for ( i = 0; i < Lc->nrows; i++ )
        str_list[i] = XmStringCreateSimple(List[i]);

    XmListSetPos(wlist, 1);
    XmListDeleteAllItems(wlist);
    XmListAddItems(wlist, str_list, Lc->nrows, 1);

    for ( i = 0; i < Lc->nrows; i++ )
        XmStringFree(str_list[i]);
    XtFree((char *)str_list);
}

void free_lincat()
{
    int i;

    for ( i = 0; i < Lc->nrows; i++ )
        osmmfree( List[i] );
}

