
#include "mview_cursor.h"

#include "mview_main.h"
#include "mview_slice.h"
#include "mview_view.h"
#include "mview_widgets.h"
#include "mview_misc.h"
#include "mview_macros.h"
#include "mview_spectrum.h"
#include "mview_display.h"
#include "gcore/gcomm.h"
#include "gsys/sic_util.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <math.h>
#include <sys/types.h>

#include <Xm/Text.h>

extern int cursor_mode;

extern char spectrum_translations[];
static char cursor_translations[] = "<Btn1Down>: cursor_input( )\n\
                    <Btn2Down>: cursor_input( )\n\
                    <Btn3Down>: cursor_input( )\n\
                    <Btn1Up>: cursor_input( )\n\
                    <Btn2Up>: cursor_input( )\n\
                    <Btn3Up>: cursor_input( )\n\
                    <Motion>: cursor_input( )\n";


/* Global declarations of variables that have to be known by redraws_box( ) */
static int first, last;         /* first and last subset in which the box */

                             /* is drawn */
static int prev_rx, prev_ry;    /* previous position of upper left corner */

static int prev_width, prev_height;     /* previous box width & box height */

static int enf = 0, edit = 0, mem = 0;  /* flags */



extern void change_pixmap( int z);
extern void change_tic( int z);

static int show_posx = -1;
int xoffset, yoffset;
int show_posy = -1;
int show_zposx = -1, show_zposy = -1;

char *LeftTrim(char *pString)
{
  int nLen = strlen(pString);
  size_t nPos = strspn(pString, " ");
  if ( nPos > nLen || nPos == 0 )
    return pString;
  memmove( pString, pString + nPos, nLen - nPos);
  pString[nLen-nPos] = 0;
  return pString;
}

void get_crosspos( int pos[2])
{
    pos[0] = (show_posx == -1) ? 0 : show_posx;
    pos[1] = (show_posy == -1) ? 0 : show_posy;
}

/* Manages expose events */
void redraws_box( )
{
    int z;

    if (edit) {
        for (z = first; z <= last; z++)
            BOX(POSX(prev_rx, z), POSY(prev_ry, z), prev_width, prev_height);
    }
}

void cursor( )
{
    if (cursor_mode == SUBAREA)
        return;

    XtVaSetValues( radec, XmNtranslations, XtParseTranslationTable( cursor_translations), NULL);
    XtVaSetValues( subset, XmNtranslations, XtParseTranslationTable( spectrum_translations), NULL);

    XtVaSetValues( integmean, XmNtranslations, XtParseTranslationTable( spectrum_translations), NULL);
    /*
       if (mem) {
       edit = 1;
       redraws_box( );
       }
     */
    cursor_mode = SUBAREA;

}

void reset_box( )
{                                      /* (For the display only) */
    int z;

    if (edit) {
        for (z = first; z <= last; z++)
            BOX(POSX(prev_rx, z), POSY(prev_ry, z), prev_width, prev_height);
        edit = 0;
    }
}

void clear_infos( )
{
    XmTextSetString( gridcoord, NULL);
    XmTextSetString( pixelvalue, NULL);
    XmTextSetString( axis1, NULL);
    XmTextSetString( axis2, NULL);
    XmTextSetString( axis3, NULL);
    XmTextSetString( sgridcoord, NULL);
    XmTextSetString( spixelvalue, NULL);
    XmTextSetString( saxis1, NULL);
    XmTextSetString( saxis2, NULL);
    XmTextSetString( saxis3, NULL);
}

void param( int xcoord, int ycoord, int zcoord, int flag)
{
    static char dumstr[80];
    char chainx[80], chainy[80], chainz[80], chainv[80];
    double uc[3];
    int i = 0;

    xcoord++;
    ycoord++;
    zcoord++;
    phys_coord( &xcoord, &ycoord, &zcoord, uc,
               chainx, chainy, chainz, chainv, strlen( chainx), strlen( chainy), strlen( chainz), strlen( chainv));
    sprintf( dumstr, "%s %d%s%d%s%d", "POS =", xcoord, ",", ycoord, ",", zcoord);

    XmTextSetString( gridcoord, dumstr);

    if (flag)
        XmTextSetString( pixelvalue, chainv);

    XmTextSetString( axis1, chainx);
    XmTextSetString( axis2, chainy);

    while ((i < strlen( chainz)) && (chainz[i] == ' '))
        i++;

    XmTextSetString( axis3, &chainz[i]);


    if (Nsubs >= 2) {
        XmTextSetString( sgridcoord, dumstr);
        if (flag)
            XmTextSetString( spixelvalue, chainv);
        XmTextSetString( saxis1, chainx);
        XmTextSetString( saxis2, chainy);
        XmTextSetString( saxis3, &chainz[i]);
    }
}

void get_curpix( int curpix[3])
{
    char *work, c;

    work = (char *)XmTextGetString( gridcoord);
    if (strlen( work) != 0)
        sscanf( &work[6], "%d%c%d%c%d", &curpix[0], &c, &curpix[1], &c, &curpix[2]);
    else
        curpix[0] = 0;
}

void redraw_cross( )
{
    DRAWCROSS(radec, show_posx, show_posy);
}

void redraw_zcross( Widget w)
{

    if ((w == subset) && (subpixmap[0] == 0) && (show_posx != -1)) {
        DRAWCROSS(subset, (xoffset + GETX(show_posx)), (yoffset + GETY(show_posy)));
    } else {
        DRAWCROSS(w, show_zposx, show_zposy);
    }
}

void draw_cross( Widget w, int x, int y)
{
    if (w == radec) {
        if (show_posx != -1) {
            /* Errase previous cross */
            DRAWCROSS(w, show_posx, show_posy);

            if ((Nsubs >= 2) && (subpixmap[0] == 0)) {
                /* Parentheses absolutely necessary because macro DRAWCROSS */
                /* takes two lines ... */

                DRAWCROSS(subset, (xoffset + GETX(show_posx)), (yoffset + GETY(show_posy)));
            }
        }

        DRAWCROSS(w, x, y);
        if ((Nsubs >= 2) && (subpixmap[0] == 0)) {
            DRAWCROSS(subset, (xoffset + GETX(x)), (yoffset + GETY(y)));
        }
        show_posx = x;
        show_posy = y;
    } else {

        if (show_zposx != -1) {

            if (subpixmap[0] != 0) {
                DRAWCROSS(subset, show_zposx, show_zposy);
            }
            DRAWCROSS(integmean, show_zposx, show_zposy);
        }

        if (subpixmap[0] != 0) {
            DRAWCROSS(subset, x, y);
        }
        DRAWCROSS(integmean, x, y);

        show_zposx = x;
        show_zposy = y;

    }
}

extern XImage *hugeimage;
extern char *lotofpixels;
extern Widget zoomshell, zoom_w;
extern Dimension zoom_width, zoom_height;

void cursor_input( Widget w, XEvent *event)
{
    int x, y, z, d, D, n, N;
    static int xr, yr, zr;      /* reference coordinates (BUTTON PRESS event) */
    static int mot = 0;
    int xc, yc;                 /* current pointer relative position */
    static int prev_zc = -1, zc;        /* previuous and current subset position */
    static int prev_xc, prev_yc;        /* previous pointer relative position */
    static int xs[4], ys[4];    /* box corners */
    int rx, ry;                 /* current position of upper left corner */
    int width, height;          /* current box width & box height */

    int zprov;

    switch (event->type) {
    case ButtonPress:
        switch (event->xbutton.button) {
        case Button1:

            x = event->xbutton.x;
            y = event->xbutton.y;

            zc = GETZ(x, y);

            if (zc >= Nsubs)
                return;

            if (edit) {
                /* Modify first */
                if ((zc <= last) && (zc > first)) {
                    for (z = first; z < zc; z++)
                        BOX(POSX(prev_rx, z), POSY(prev_ry, z), prev_width, prev_height);
                    first = zc;
                }
                if (zc < first) {
                    for (z = zc; z < first; z++)
                        BOX(POSX(prev_rx, z), POSY(prev_ry, z), prev_width, prev_height);
                    first = zc;
                }
            }
            break;
        case Button2:
            x = event->xbutton.x;
            y = event->xbutton.y;

            zprov = GETZ(x, y);

            if (zprov >= Nsubs)
                return;

            zr = zprov;

            enf = 1;
            kill_movie( );
            new_spec( w, x, y);

            /* reference position */
            xr = GETX(x);
            yr = GETY(y);
            zc = zr;

            if (!edit) {
                /* initialize previous position */
                prev_xc = xr;
                prev_yc = yr;
                first = zr;
                last = first;
                prev_rx = xr;
                prev_ry = yr;
                prev_width = 0;
                prev_height = 0;
            }

            else {
                /* find new corner */
                D = 1E+05;
                for (n = 0; n < 4; n++) {
                    d = sqrt( (float)((ys[n] - yr) * (ys[n] - yr)
                                     + (xs[n] - xr) * (xs[n] - xr)));
                    if (d < D) {
                        D = d;
                        N = n;
                    }
                }

                switch (N) {
                case 0:
                    xr = xs[2];
                    yr = ys[2];
                    break;
                case 1:
                    xr = xs[3];
                    yr = ys[3];
                    break;
                case 2:
                    xr = xs[0];
                    yr = ys[0];
                    break;
                case 3:
                    xr = xs[1];
                    yr = ys[1];
                    break;
                }
                /* re-initialize previous position */
                prev_xc = xs[N];
                prev_yc = ys[N];
            }
            break;
        case Button3:
            x = event->xbutton.x;
            y = event->xbutton.y;

            zc = GETZ(x, y);
            if (zc >= Nsubs)
                return;

            if (edit) {
                /* Modify last */
                if ((zc >= first) && (zc < last)) {
                    for (z = zc + 1; z <= last; z++)
                        BOX(POSX(prev_rx, z), POSY(prev_ry, z), prev_width, prev_height);
                    last = zc;
                }
                if (zc > last) {
                    for (z = last + 1; z <= zc; z++)
                        BOX(POSX(prev_rx, z), POSY(prev_ry, z), prev_width, prev_height);
                    last = zc;
                }
            }
            break;
        }
        break;

    case MotionNotify:
        x = event->xmotion.x;
        y = event->xmotion.y;

        zprov = GETZ(x, y);

        if (!INMOSAIC(x, y) || (zprov >= Nsubs))
            return;

        if (!enf)
            return;

        mot = 1;
        zc = zprov;
        new_spec( w, x, y);

        /* current display position */
        xc = GETX(x);
        yc = GETY(y);

        /* clean boxes of obsolete width and height */
        if (zc > last) {
            for (z = last + 1; z <= zc; z++)
                BOX(POSX(prev_rx, z), POSY(prev_ry, z), prev_width, prev_height);
        }
        if (zc < first) {
            for (z = zc; z < first; z++)
                BOX(POSX(prev_rx, z), POSY(prev_ry, z), prev_width, prev_height);
        }

        first = min( first, zc);
        last = max( last, zc);

        rx = min( xr, xc);
        ry = min( yr, yc);

        width = abs( xc - xr);
        height = abs( yc - yr);

        if (zc == prev_zc) {
            /* Pour eviter le 'scintillement', le trace de l'ancienne boite et */
            /* l'effacement de la nouvelle pour un subset est ds la meme boucle */
            for (z = first; z <= last; z++) {
                BOX(POSX(prev_rx, z), POSY(prev_ry, z), prev_width, prev_height);
                BOX(POSX(rx, z), POSY(ry, z), width, height);
            }
        } else {

            /* On ne retrace pas forcement toutes les boites */
            for (z = first; z <= last; z++)
                BOX(POSX(prev_rx, z), POSY(prev_ry, z), prev_width, prev_height);

            if ((zc < prev_zc) && (zc >= zr))
                last = zc;
            if ((zc > prev_zc) && (zc <= zr))
                first = zc;
            if ((prev_zc > zr) && (zc < zr))
                last = zr;
            if ((prev_zc < zr) && (zc > zr))
                first = zr;

            for (z = first; z <= last; z++)
                BOX(POSX(rx, z), POSY(ry, z), width, height);
            prev_zc = zc;
        }


        prev_xc = xc;
        prev_yc = yc;
        prev_rx = rx;
        prev_ry = ry;
        prev_width = width;
        prev_height = height;


        break;
    case ButtonRelease:
        switch (event->xbutton.button) {
        case Button2:
            x = event->xbutton.x;
            y = event->xbutton.y;

            if (enf == 1) {
                xs[0] = xr;
                ys[0] = yr;
                xs[1] = prev_xc;
                ys[1] = yr;
                xs[2] = prev_xc;
                ys[2] = prev_yc;
                xs[3] = xr;
                ys[3] = prev_yc;
                edit = 1;
                if (mot)
                    mem = 1;
                enf = 0;
            }
            break;
        }
        break;
    }
}

void get_3D_area( int box[6])
{
    char chainx[80], chainy[80], chainz[80], chainv[80];
    double uc[3];

    if (edit) {
        box[0] = incr * prev_rx / zoom + 1;     /* + 1 for x between 1 and npix[0] */
        box[1] = incr * (npix[1] - 1 - (prev_ry + prev_height) / zoom) + 1;
        box[2] = first + 1;
        box[3] = incr * (prev_rx + prev_width) / zoom + 1;
        box[4] = incr * (npix[1] - 1 - prev_ry / zoom) + 1;
        box[5] = last + 1;
    } else {
        box[0] = 1;
        box[1] = 1;
        box[2] = 1;
        box[3] = npix[0];
        box[4] = npix[1];
        box[5] = Nsubs;
    }

    phys_coord( &box[0], &box[1], &box[2], uc,
               chainx, chainy, chainz, chainv, strlen( chainx), strlen( chainy), strlen( chainz), strlen( chainv));

    phys_coord( &box[3], &box[4], &box[5], uc,
               chainx, chainy, chainz, chainv, strlen( chainx), strlen( chainy), strlen( chainz), strlen( chainv));
}

void extract_image( Widget w, XtPointer w_code, XmAnyCallbackStruct *cbs)
{
    char line[MAXBUF];
    FILE *polygon;
    char *dum;
    double uc[3];
    int x, y, z = 1, compt = 0, box[6], sub[3];
    int extremities[4];
    char chainx[80], chainy[80], chainz[80], chainv[80];
    float seuil, velo[2];
    XPoint_list xpl;
    FILE *param_file;
    char name[SIC_MAX_FILE_LENGTH];
    char tmppath[SIC_MAX_TRANSLATION_LENGTH];


    strcpy( tmppath, sic_s_get_translation( "GAG_TMP:"));
    sprintf(name,"%s%s",tmppath,"mview.tmp");    
    param_file = fopen( name, "w");

    get_image_name( name);

    switch ((long)w_code) {
    case k_spectrum:
        dum = XmTextGetString( axis1);

        if (strlen( dum) == 0)
            return;

        sprintf( chainx, "%s", dum);
        XtFree( dum);

        dum = XmTextGetString( axis2);

        sprintf( chainy, "%s", dum);
        XtFree( dum);

        fprintf( param_file, "TASK\\FILE \"Input file name\" IN$ \"%s\"\n", name);

        fprintf( param_file, "%s", "TASK\\FILE \"Output table name\" OUT$ \"\"\n");

        fprintf( param_file, "TASK\\CHARACTER \"Absolute coordinates\" COORD$ \"%s %s\"\n", LeftTrim(chainx), chainy);

        break;


    case k_spectrum_sum:
        compt = get_nsum( );

        fprintf( param_file, "TASK\\FILE \"Input file name\" IN$ \"%s\"\n", name);

        fprintf( param_file, "%s", "TASK\\FILE \"Output file name\" OUT$ \"\"\n");

        polygon = fopen( "polygon.log", "w");

        if (compt == 0) {
            x = 1;
            y = 1;
            z = 1;
            phys_coord( &x, &y, &z, uc,
                       chainx, chainy, chainz, chainv, strlen( chainx), strlen( chainy), strlen( chainz), strlen( chainv));

            fprintf( polygon, "%g %g \'%s\' \'%s\'\n", uc[0], uc[1], chainx, chainy);
            x = npix[0];
            y = 1;
            z = 1;
            phys_coord( &x, &y, &z, uc,
                       chainx, chainy, chainz, chainv, strlen( chainx), strlen( chainy), strlen( chainz), strlen( chainv));

            fprintf( polygon, "%g %g \'%s\' \'%s\'\n", uc[0], uc[1], chainx, chainy);
            x = npix[0];
            y = npix[1];
            z = 1;
            phys_coord( &x, &y, &z, uc,
                       chainx, chainy, chainz, chainv, strlen( chainx), strlen( chainy), strlen( chainz), strlen( chainv));

            fprintf( polygon, "%g %g \'%s\' \'%s\'\n", uc[0], uc[1], chainx, chainy);
            x = 1;
            y = npix[1];
            z = 1;
            phys_coord( &x, &y, &z, uc,
                       chainx, chainy, chainz, chainv, strlen( chainx), strlen( chainy), strlen( chainz), strlen( chainv));

            fprintf( polygon, "%g %g \'%s\' \'%s\'\n", uc[0], uc[1], chainx, chainy);
        } else {
            xpl = get_pol_coord( );

            while (xpl != NULL) {
                x = (xpl->xp.x) / localzoom + 1;
                y = (npix[1] - 1 - (xpl->xp.y) / localzoom) + 1;

                z = 1;
                phys_coord( &x, &y, &z, uc,
                           chainx, chainy, chainz, chainv, strlen( chainx), strlen( chainy), strlen( chainz), strlen( chainv));

                if (xpl->next != NULL)
                    fprintf( polygon, "%g %g \'%s\' \'%s\'\n", uc[0], uc[1], chainx, chainy);

                xpl = xpl->next;
            }
        }

        fclose( polygon);

        fprintf( param_file, "TASK\\FILE \"Polygon file\" POLY$ \"%s\"\n", "polygon.log");


        break;
    case k_slice:
        get_slice_extremities( extremities);

        if (extremities[0] == 0)
            return;

        fprintf( param_file, "TASK\\FILE \"Input file name\" INPUT_MAP$ \"%s\"\n", name);

        fprintf( param_file, "%s", "TASK\\FILE \"Output file name\" OUTPUT_MAP$ \"\"\n");


        phys_coord( &extremities[0], &extremities[1], &z, uc,
                   chainx, chainy, chainz, chainv, strlen( chainx), strlen( chainy), strlen( chainz), strlen( chainv));

        fprintf( param_file, "TASK\\CHARACTER \"Starting point\" START$ \"%s %s\"\n", LeftTrim(chainx), chainy);


        phys_coord( &extremities[2], &extremities[3], &z, uc,
                   chainx, chainy, chainz, chainv, strlen( chainx), strlen( chainy), strlen( chainz), strlen( chainv));

        fprintf( param_file, "TASK\\CHARACTER \"Ending point\" END$ \"%s %s\"\n", LeftTrim(chainx), chainy);

        break;

    case k_moments:
        fprintf( param_file, "TASK\\FILE \"Input file name\" IN$ \"%s\"\n", name);

        fprintf( param_file, "%s", "TASK\\FILE \"Output files name (no extension)\" OUT$ \"\"\n");

        get_planes( sub, velo);
        fprintf( param_file, "TASK\\REAL \"Velocity range\" VELOCITY$[2] %g %g\n", velo[0], velo[1]);

        get_seuil( &seuil);

        fprintf( param_file, "TASK\\REAL \"%s\" THRESHOLD$ %10.2g\n", "Absolute detection threshold", seuil);

        fprintf( param_file, "TASK\\LOGICAL \"%s\" SMOOTH$ NO\n", "Velocity smoothing ?");
        break;

    case k_map_aver:
        fprintf( param_file, "TASK\\FILE \"Input file name\" INPUT_MAP$ \"%s\"\n", name);

        fprintf( param_file, "%s", "TASK\\FILE \"Output file name\" OUTPUT_MAP$ \"\"\n");


        get_planes( sub, velo);

        fprintf( param_file, "TASK\\INTEGER \"First and last channel\" NC$[2] %d %d\n", sub[1], sub[2]);
        break;
    case k_map_sum:
        fprintf( param_file, "TASK\\FILE \"Input file name\" INPUT_MAP$ \"%s\"\n", name);

        fprintf( param_file, "%s", "TASK\\FILE \"Output file name\" OUTPUT_MAP$ \"\"\n");

        get_planes( sub, velo);
        fprintf( param_file, "TASK\\REAL \"Velocity range\" VELOCITY$[2] %g %g\n", velo[0], velo[1]);

        break;

    default:
        fprintf( param_file, "TASK\\FILE \"Input file name\" Y_NAME$ \"%s\"\n", name);

        fprintf( param_file, "%s", "TASK\\FILE \"Output file name\" X_NAME$ \"\"\n");

        sprintf( name, "%s", XtName( XtParent( XtParent( XtParent( w)))));
        if (strncmp( name, "MENUBAR", 7) == 0)
            get_3D_area( box);
        else {
            get_2D_area( box);
            get_planes( sub, velo);
            box[2] = sub[1];
            box[5] = sub[2];
        }
        fprintf( param_file, "TASK\\INTEGER \"Bottom left corner\" BLC$[4] %d %d %d %d\n", box[0], box[1], box[2], 0);
        fprintf( param_file, "TASK\\INTEGER \"Top right corner\" TRC$[4] %d %d %d %d\n", box[3], box[4], box[5], 0);

        fprintf( param_file,
                "TASK\\INTEGER \"%s\" PIXEL_IN$[4] %d %d %d %d\n",
                "Position of one pixel in input image", box[0], box[1], box[2], 0);

        fprintf( param_file, "TASK\\INTEGER \"%s\" PIXEL_OUT$[4] 1 1 1 0\n", "Position of this pixel in output image");

        fprintf( param_file, "TASK\\LOGICAL \"%s\" INITIALIZE$ YES\n", "Initialize output image");

        fprintf( param_file, "%s\n", "SIC\\IF (INITIALIZE$) THEN");

        fprintf( param_file, "TASK\\INTEGER \"Dimensions of output image\" X_DIM$[4] %d %d %d %d\n", 0, 0, 0, 0);

        fprintf( param_file, "TASK\\LOGICAL \"%s\" BLANKOUT$ NO\n", "Initialize with blanking value");

        fprintf( param_file, "%s\n", "SIC\\IF (.NOT.BLANKOUT$) THEN");

        fprintf( param_file, "TASK\\REAL \"%s\" INITVAL$ 0\n", "Initialization value");

        fprintf( param_file, "%s\n", "SIC\\ENDIF");
        fprintf( param_file, "%s\n", "SIC\\ENDIF");
        break;
    }

    fprintf( param_file, "%s\n", "TASK\\GO");

    fclose( param_file);

    switch ((long)w_code) {
    case k_spectrum:
        sprintf( line, "%s", "on error continue; run spectrum gag_tmp:mview.tmp; on error");
        break;
    case k_spectrum_sum:
        sprintf( line, "%s", "on error continue; run spectrum_sum gag_tmp:mview.tmp; on error");
        break;
    case k_slice:
        sprintf( line, "%s", "on error continue; run slice gag_tmp:mview.tmp; on error");
        break;
    case k_moments:
        sprintf( line, "%s", "on error continue; run moments gag_tmp:mview.tmp; on error");
        break;
    case k_map_aver:
        sprintf( line, "%s", "on error continue; run map_aver gag_tmp:mview.tmp; on error");
        break;
    case k_map_sum:
        sprintf( line, "%s", "on error continue; run map_sum gag_tmp:mview.tmp; on error");
        break;
    default:
        sprintf( line, "%s", "on error continue; run extract gag_tmp:mview.tmp; on error");
        break;
    }

    if (sic_post_command_text( line) == -1)
        XBell( display, 0);
}

void trap_SIGALRM(int lesignal)
{
    signal( SIGALRM, trap_SIGALRM);

    if (sic_post_command_text( "SIC\\CONTINUE") == -1)
        XBell( display, 0);
}

