/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * filename: xextract.c                                                    *
 *                                                                         *
 * UTIL C-source: Medical Image Conversion Utility                         *
 *                                                                         *
 * purpose      : extract images routines                                  *
 *                                                                         *
 * project      : (X)MedCon by Erik Nolf                                   *
 *                                                                         *
 * Functions    : XMdcExtractNotBussy()               - Check for bussy    *
 *                XMdcExtractImages()                 - Extract the images *
 *                XMdcHandleEcatList()                - Handle Ecat list   *
 *                XMdcHandleNormList()                - Handle Norm list   *
 *                XMdcGetImagesCallbackApply()        - Get Apply callback *
 *                XMdcGetImages()                     - Get the images     *
 *                XMdcExtractStyleSelCallbackApply()  - Apply   callback   *
 *                XMdcExtractStyleSel()               - Extract Style Sel  *
 *                                                                         *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
 */

/*
   Copyright (C) 1997-2026 by Erik Nolf

   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, 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 Place - Suite 330, Boston, MA 02111-1307, USA.  */

/****************************************************************************
                              H E A D E R S
****************************************************************************/

#include "m-depend.h"

#include <stdio.h>
#ifdef LIBMDC_HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef LIBMDC_HAVE_STRING_H
#include <string.h>
#endif
#ifdef LIBMDC_HAVE_STRINGS_H
#ifndef _WIN32
#include <strings.h>
#endif
#endif

#include "xmedcon.h"

/****************************************************************************
                              D E F I N E S
****************************************************************************/

static int BUSSY = MDC_NO;

/****************************************************************************
                            F U N C T I O N S
****************************************************************************/

gboolean XMdcExtractNotBussy(GtkWidget *widget, gpointer data)
{
  BUSSY = MDC_NO; return(FALSE);
}

void XMdcExtractImages(void)
{
  char *msg;
  XMdcProgressBar(MDC_PROGRESS_BEGIN,0.,"Extracting images:");

  XMdcViewerHide();
  XMdcViewerEnableAutoShrink();
  XMdcViewerReset();

  msg = MdcExtractImages(my.fi);
  if (msg != NULL) XMdcDisplayErr("Extract - %s",msg);

  XMdcDisplayImages();

  XMdcProgressBar(MDC_PROGRESS_END,0.,NULL);

  XMDC_FILE_TYPE = XMDC_EXTRACT;

}

int XMdcHandleEcatList(char *s, Uint32 **list, Uint32 max)
{
  char *msg;

  msg = MdcHandleEcatList(s, list, max);

  if (msg != NULL) { XMdcDisplayErr(msg); return(MDC_NO); }

  return(MDC_YES);
}


int XMdcHandleNormList(char *s, Uint32 **inrs,Uint32 *it,Uint32 *bt,Uint32 max)
{
  char *msg;

  msg = MdcHandleNormList(s, inrs, it, bt, max);

  if (msg != NULL) { XMdcDisplayErr(msg); return(MDC_NO); }

  return(MDC_YES);
}

void XMdcGetImagesCallbackApply(GtkWidget *widget, gpointer data)
{
  MdcExtractInputStruct *input = sExtractSelection.input;
  Uint32 images=1;
  Uint32 p, f, g, b;
  Uint32 it, bt;
  Uint32 *planes, *frames, *gates, *beds;
  char *entry;

  if (XMdcNoFileOpened()) return;

  if (input->style == MDC_INPUT_NORM_STYLE) {
    if ((input->inrs=(Uint32 *)malloc(MDC_BUF_ITMS*sizeof(Uint32)))==NULL) {
      XMdcDisplayErr("Couldn't alloc number buffer");
      return;
    }

    entry = g_strdup(gtk_entry_get_text(GTK_ENTRY(sExtractSelection.InputPlanes)));

    it = 1; bt = 2;
    if (XMdcHandleNormList(entry,&input->inrs,&it,&bt,my.fi->number)
         != MDC_YES) {
      MdcFree(input->inrs);
      return;
      g_free(entry);
    }
    g_free(entry);

  }else{
    if ( (planes=(Uint32 *)malloc((my.fi->dim[3]+1)*sizeof(Uint32)))==NULL ) {
      XMdcDisplayErr("Couldn't malloc planes buffer");
      return;
    }
    memset(planes,0,(my.fi->dim[3]+1)*sizeof(Uint32));
    if ( (frames=(Uint32 *)malloc((my.fi->dim[4]+1)*sizeof(Uint32)))==NULL ) {
      XMdcDisplayErr("Couldn't malloc frames buffer");
      MdcFree(planes);
      return;
    }
    memset(frames,0,(my.fi->dim[4]+1)*sizeof(Uint32));
    if ( (gates=(Uint32 *)malloc((my.fi->dim[5]+1)*sizeof(Uint32)))==NULL ) {
      XMdcDisplayErr("Couldn't malloc gates buffer");
      MdcFree(planes); MdcFree(frames);
      return;
    }
    memset(gates,0,(my.fi->dim[5]+1)*sizeof(Uint32));
    if ( (beds=(Uint32 *)malloc((my.fi->dim[6]+1)*sizeof(Uint32)))==NULL ) {
      XMdcDisplayErr("Couldn't malloc beds buffer");
      MdcFree(planes); MdcFree(frames); MdcFree(gates);
      return;
    }
    memset(beds,0,(my.fi->dim[6]+1)*sizeof(Uint32));

    entry = g_strdup(gtk_entry_get_text(GTK_ENTRY(sExtractSelection.InputPlanes)));
    if (XMdcHandleEcatList(entry,&planes,(unsigned)my.fi->dim[3]) != MDC_YES) {
      MdcFree(planes); MdcFree(frames); MdcFree(gates); MdcFree(beds);
      g_free(entry);
      return;
    }
    g_free(entry);

    entry = g_strdup(gtk_entry_get_text(GTK_ENTRY(sExtractSelection.InputFrames)));
    if (XMdcHandleEcatList(entry,&frames,(unsigned)my.fi->dim[4]) != MDC_YES) {
      MdcFree(planes); MdcFree(frames); MdcFree(gates); MdcFree(beds);
      g_free(entry);
      return;
    }
    g_free(entry);

    entry = g_strdup(gtk_entry_get_text(GTK_ENTRY(sExtractSelection.InputGates)));
    if (XMdcHandleEcatList(entry,&gates,(unsigned)my.fi->dim[5]) != MDC_YES) {
      MdcFree(planes); MdcFree(frames); MdcFree(gates); MdcFree(beds);
      g_free(entry);
      return;
    }
    g_free(entry);

    entry = g_strdup(gtk_entry_get_text(GTK_ENTRY(sExtractSelection.InputBeds)));
    if (XMdcHandleEcatList(entry,&beds,(unsigned)my.fi->dim[6]) != MDC_YES) {
      MdcFree(planes); MdcFree(frames); MdcFree(gates); MdcFree(beds);
      g_free(entry);
      return;
    }
    g_free(entry);

    MdcDebugPrint("p=%u f=%u g=%u b=%u",planes[0],frames[0],gates[0],beds[0]);

    images*=planes[0]*frames[0]*gates[0]*beds[0];

    input->num_p = planes[0];
    input->num_f = frames[0];
    input->num_g = gates[0];
    input->num_b = beds[0];

    if ((input->inrs=(Uint32 *)malloc((images+1)*sizeof(Uint32)))==NULL) {
      XMdcDisplayErr("Couldn't malloc number buffer");
      MdcFree(planes); MdcFree(frames); MdcFree(gates); MdcFree(beds);
      return;
    }

    /* get sequential image numbers (like normal selection) */
    it = 1;
    for (b=1; b<=my.fi->dim[6];b++) if (beds[b])
    for (g=1; g<=my.fi->dim[5];g++) if (gates[g])
    for (f=1; f<=my.fi->dim[4];f++) if (frames[f])
    for (p=1; p<=my.fi->dim[3];p++) if (planes[p]) {

       images = p +                     /* the image number */
                my.fi->dim[3]*( (f-1) +
                my.fi->dim[4]*( (g-1) +
                my.fi->dim[5]*( (b-1)   ) ) );

       input->inrs[it++]=images;

    }

    MdcFree(planes); MdcFree(frames); MdcFree(gates); MdcFree(beds);

  }

  input->inrs[0] = it - 1;

  if (input->inrs[0] == 0) {
    XMdcDisplayWarn("No images specified");
    MdcFree(input->inrs);
    return;
  }

  XMdcExtractImages();

}


void XMdcGetImages(GtkWidget *widget, guint style)
{
   GtkWidget *window=NULL;
   GtkWidget *box1;
   GtkWidget *box2;
   GtkWidget *box3;
   GtkWidget *grid;
   GtkWidget *frame;
   GtkWidget *label;
   GtkWidget *button;
   GtkWidget *separator;
   GtkWidget *planes, *frames, *gates, *beds;
   MdcExtractInputStruct *input = sExtractSelection.input;

   if (XMdcNoFileOpened()) return;

   input->style = (Int32)style;

   window = gtk_window_new(GTK_WINDOW_TOPLEVEL); BUSSY = MDC_YES;

   g_signal_connect(window, "destroy",
                      G_CALLBACK(XMdcExtractNotBussy),NULL);
   g_signal_connect(window, "destroy",
                      G_CALLBACK(gtk_widget_destroy),NULL);

   if (input->style == MDC_INPUT_NORM_STYLE) {
     gtk_window_set_title(GTK_WINDOW(window),"Extract Input Normal");
   }else{
     gtk_window_set_title(GTK_WINDOW(window),"Extract Input Ecat");
   }
   gtk_container_set_border_width(GTK_CONTAINER(window),0);

   box1 = gtk_box_new(GTK_ORIENTATION_VERTICAL,5);
   gtk_container_add(GTK_CONTAINER(window),box1);
   gtk_container_set_border_width(GTK_CONTAINER(box1),5);
   gtk_widget_show(box1);

   frame = gtk_frame_new("Notes");
   gtk_box_pack_start(GTK_BOX(box1),frame,TRUE,TRUE,0);
   gtk_widget_show(frame);

   box2 = gtk_box_new(GTK_ORIENTATION_VERTICAL,5);
   gtk_container_add(GTK_CONTAINER(frame),box2);
   gtk_container_set_border_width(GTK_CONTAINER(box2),5);
   gtk_widget_show(box2);

   if (input->style == MDC_INPUT_NORM_STYLE) {
     /* create input notes */
     strcpy(mdcbufr,"a) Any number must be one-based     (0 = All reversed)\n" \
                    "b) Syntax of a range : X...Y or X-Y\n" \
                    "c) Syntax of interval: X:S:Y        (S = step)\n" \
                    "d) Items must be separated by spaces\n" \
                    "e) This list is sequence sensitive!\n\n" \
                    " Example: 1 3 4:2:11 12...6\n");

     label = gtk_label_new(mdcbufr);
     gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_LEFT);
     gtk_widget_set_name (label, "FixedLabel");
     gtk_box_pack_start(GTK_BOX(box2),label,TRUE,TRUE,5);
     gtk_widget_show(label);

     frame = gtk_frame_new("Entry");
     gtk_box_pack_start(GTK_BOX(box1),frame,TRUE,TRUE,0);
     gtk_widget_show(frame);

     box2 = gtk_box_new(GTK_ORIENTATION_VERTICAL,0);
     gtk_container_add(GTK_CONTAINER(frame),box2);
     gtk_container_set_border_width(GTK_CONTAINER(box2),0);
     gtk_widget_show(box2);

     box3 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,0);
     gtk_container_add(GTK_CONTAINER(box2),box3);
     gtk_container_set_border_width(GTK_CONTAINER(box3),0);
     gtk_widget_show(box3);

     sprintf(mdcbufr,"Images [1...%u]",my.fi->number);
     label = gtk_label_new(mdcbufr);
     gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_RIGHT);
     gtk_widget_set_name(label, "FixedLabel");
     gtk_box_pack_start(GTK_BOX(box3),label,TRUE,TRUE,0);
     gtk_widget_show(label);

     planes=gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(planes), 50);
     MdcDebugPrint("rc-style name = %s",gtk_widget_get_name(planes));
     gtk_entry_set_text(GTK_ENTRY(planes),"0");
     gtk_editable_select_region(GTK_EDITABLE(planes),0,-1);
     gtk_box_pack_start(GTK_BOX(box3),planes,TRUE,TRUE,0);
     gtk_widget_show(planes);
     sExtractSelection.InputPlanes=planes;

   }else{
     /* create input notes */
     strcpy(mdcbufr,"a) Any number must be one-based (0 = All)\n" \
                    "b) Syntax of range   : X...Y or X-Y\n" \
                    "c) Syntax of interval: X:S:Y    (S = step)\n" \
                    "d) Items must be separated by spaces\n\n" \
                    " Example: 1 3 5...10 12:2:20\n");

     label = gtk_label_new(mdcbufr);
     gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_LEFT);
     gtk_widget_set_name (label, "FixedLabel");
     gtk_box_pack_start(GTK_BOX(box2),label,TRUE,TRUE,5);
     gtk_widget_show(label);

     frame = gtk_frame_new("Entry");
     gtk_box_pack_start(GTK_BOX(box1),frame,TRUE,TRUE,0);
     gtk_widget_show(frame);

     grid = gtk_grid_new();
     gtk_container_add(GTK_CONTAINER(frame),grid);
     gtk_widget_show(grid);

     label = gtk_label_new("Planes");
     gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_LEFT);
     gtk_widget_set_name (label, "FixedLabel");
     gtk_grid_attach(GTK_GRID(grid),label,0,0,1,1);
     gtk_widget_show(label);
     sprintf(mdcbufr,"[1...%u]",my.fi->dim[3]);
     label = gtk_label_new(mdcbufr);
     gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_LEFT);
     gtk_widget_set_name (label, "FixedLabel");
     gtk_grid_attach(GTK_GRID(grid),label,1,0,1,1);
     gtk_widget_show(label);
     planes = gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(planes), 50);
     gtk_entry_set_text(GTK_ENTRY(planes),"0");
     gtk_editable_select_region(GTK_EDITABLE(planes),0,-1);
     gtk_grid_attach(GTK_GRID(grid),planes,2,0,1,1);
     gtk_widget_show(planes);
     sExtractSelection.InputPlanes=planes;

     label = gtk_label_new("Frames");
     gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_LEFT);
     gtk_widget_set_name (label, "FixedLabel");
     gtk_grid_attach(GTK_GRID(grid),label,0,1,1,1);
     gtk_widget_show(label);
     sprintf(mdcbufr,"[1...%u]",my.fi->dim[4]);
     label = gtk_label_new(mdcbufr);
     gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_LEFT);
     gtk_widget_set_name (label, "FixedLabel");
     gtk_grid_attach(GTK_GRID(grid),label,1,1,1,1);
     gtk_widget_show(label);
     frames = gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(frames), 50);
     gtk_entry_set_text(GTK_ENTRY(frames),"0");
     gtk_editable_select_region(GTK_EDITABLE(frames),0,-1);
     gtk_grid_attach(GTK_GRID(grid),frames,2,1,1,1);
     gtk_widget_show(frames);
     sExtractSelection.InputFrames=frames;

     label = gtk_label_new("Gates");
     gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_LEFT);
     gtk_widget_set_name (label, "FixedLabel");
     gtk_grid_attach(GTK_GRID(grid),label,0,2,1,1);
     gtk_widget_show(label);
     sprintf(mdcbufr,"[1...%u]",my.fi->dim[5]);
     label = gtk_label_new(mdcbufr);
     gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_LEFT);
     gtk_widget_set_name (label, "FixedLabel");
     gtk_grid_attach(GTK_GRID(grid),label,1,2,1,1);
     gtk_widget_show(label);
     gates = gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(gates), 50);
     gtk_entry_set_text(GTK_ENTRY(gates),"0");
     gtk_editable_select_region(GTK_EDITABLE(gates),0,-1);
     gtk_grid_attach(GTK_GRID(grid),gates,2,2,1,1);
     gtk_widget_show(gates);
     sExtractSelection.InputGates=gates;

     label = gtk_label_new("Beds");
     gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_LEFT);
     gtk_widget_set_name (label, "FixedLabel");
     gtk_grid_attach(GTK_GRID(grid),label,0,3,1,1);
     gtk_widget_show(label);
     sprintf(mdcbufr,"[1...%u]",my.fi->dim[6]);
     label = gtk_label_new(mdcbufr);
     gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_LEFT);
     gtk_widget_set_name (label, "FixedLabel");
     gtk_grid_attach(GTK_GRID(grid),label,1,3,1,1);
     gtk_widget_show(label);
     beds= gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(beds), 50);
     gtk_entry_set_text(GTK_ENTRY(beds),"0");
     gtk_editable_select_region(GTK_EDITABLE(beds),0,-1);
     gtk_grid_attach(GTK_GRID(grid),beds,2,3,1,1);
     gtk_widget_show(beds);
     sExtractSelection.InputBeds=beds;

   }

   /* create horizontal separator */
   separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
   gtk_box_pack_start(GTK_BOX(box1),separator,FALSE,FALSE,0);
   gtk_widget_show(separator);

   /* create bottom buttons */
   box2 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,0);
   gtk_box_pack_start(GTK_BOX(box1),box2,TRUE,TRUE,2);
   gtk_widget_show(box2);

   button = gtk_button_new_with_label("Apply");
   gtk_box_pack_start(GTK_BOX(box2),button,TRUE,TRUE,2);
   g_signal_connect_swapped(button, "clicked",
                      G_CALLBACK(gtk_widget_hide), window);
   g_signal_connect(button, "clicked",
                      G_CALLBACK(XMdcGetImagesCallbackApply), NULL);
   g_signal_connect_swapped(button, "clicked",
                      G_CALLBACK(gtk_widget_destroy), window);
   gtk_widget_show(button);

   button = gtk_button_new_with_label("Cancel");
   gtk_box_pack_start(GTK_BOX(box2), button, TRUE, TRUE, 2);
   g_signal_connect_swapped(button, "clicked",
                      G_CALLBACK(gtk_widget_destroy), window);
   gtk_widget_show(button);

   XMdcShowWidget(window);
}

