/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * filename: m-xtract.c                                                    *
 *                                                                         *
 * UTIL C-source: Medical Image Conversion Utility                         *
 *                                                                         *
 * purpose      : extract specified images                                 *
 *                                                                         *
 * project      : (X)MedCon by Erik Nolf                                   *
 *                                                                         *
 * Functions    : MdcGetImagesToExtract() - Ask images to extract          *
 *                MdcExtractImages()      - Extract/Reorder the images     *
 *                                                                         *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
 */

/*
   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 "medcon.h"

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

MdcExtractInputStruct mdcextractinput;

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

int MdcGetImagesToExtract(FILEINFO *fi, MdcExtractInputStruct *input)
{
   Uint32 images=1;
   Uint32 *frames, *planes, *gates, *beds;
   Uint32 p,f,g,b;
   Uint32 it, bt;
   char *msg;

   /* initialize the extract input structure */
   input->style = MDC_INPUT_NORM_STYLE;
   input->inrs = NULL;
   input->num_p = 1;
   input->num_f = 1;
   input->num_g = 1;
   input->num_b = 1;

   if (input->INTERACTIVE == MDC_YES) {
     MdcPrintLine('-',MDC_FULL_LENGTH);
     MdcPrntScrn("\tEXTRACT IMAGES\t\tFILE: %s\n",fi->ifname);
     MdcPrintLine('-',MDC_FULL_LENGTH);

     input->style = MdcGetSelectionType();
   }

   if ( input->style == MDC_INPUT_ECAT_STYLE ) { /* ecat input type */

     if (input->INTERACTIVE == MDC_NO) return(MDC_NO);

     MdcPrntScrn("\n\n\t");
     MdcPrntScrn("Input notes: a) Any number must be one-based (0 = All)");
     MdcPrntScrn("\n\t");
     MdcPrntScrn("             b) Syntax of range   : X...Y or X-Y");
     MdcPrntScrn("\n\t");
     MdcPrntScrn("             c) Syntax of interval: X:S:Y    (S = step)");
     MdcPrntScrn("\n\t");
     MdcPrntScrn("             d) Just type <enter> for entire range\n");
     MdcPrntScrn("\n\t");
     MdcPrntScrn("Example    : 1 3 5...10 12:2:20\n");

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

     MdcPrntScrn("\n\tGive planes list [1...%u]: ",fi->dim[3]);
     MdcGetStrInput(mdcbufr,MDC_2KB_OFFSET);

     if ((msg=MdcHandleEcatList(mdcbufr,&planes,(Uint32)fi->dim[3])) != NULL) {
       MdcFree(planes); MdcFree(frames); MdcFree(gates); MdcFree(beds);
       MdcPrntWarn(msg); return(MDC_BAD_CODE);
     }

     MdcPrntScrn("\n\tGive frames list [1...%u]: ",fi->dim[4]);
     MdcGetStrInput(mdcbufr,MDC_2KB_OFFSET);

     if ((msg=MdcHandleEcatList(mdcbufr,&frames,(Uint32)fi->dim[4])) != NULL) {
       MdcFree(planes); MdcFree(frames); MdcFree(gates); MdcFree(beds);
       MdcPrntWarn(msg); return(MDC_BAD_CODE);
     }

     MdcPrntScrn("\n\tGive gates  list [1...%u]: ",fi->dim[5]);
     MdcGetStrInput(mdcbufr,MDC_2KB_OFFSET);

     if ((msg=MdcHandleEcatList(mdcbufr,&gates,(Uint32)fi->dim[5])) != NULL) {
       MdcFree(planes); MdcFree(frames); MdcFree(gates); MdcFree(beds);
       MdcPrntWarn(msg); return(MDC_BAD_CODE);
     }

     MdcPrntScrn("\n\tGive beds  list [1...%u]: ",fi->dim[6]);
     MdcGetStrInput(mdcbufr,MDC_2KB_OFFSET);

     if ((msg=MdcHandleEcatList(mdcbufr,&beds,(Uint32)fi->dim[6])) != NULL) {
       MdcFree(planes); MdcFree(frames); MdcFree(gates); MdcFree(beds);
       MdcPrntWarn(msg); return(MDC_BAD_CODE);
     }

     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) {
       MdcFree(planes); MdcFree(frames); MdcFree(gates); MdcFree(beds);
       MdcPrntWarn("Couldn't malloc images number buffer");
       return(MDC_BAD_ALLOC);
     }

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

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

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

     }

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

   }else{  /* normal input type */

     if ((input->inrs=(Uint32 *)malloc(MDC_BUF_ITMS*sizeof(Uint32)))==NULL) {
       MdcPrntWarn("Couldn't allocate images number buffer");
       return(MDC_BAD_ALLOC);
     }

     if (input->INTERACTIVE == MDC_YES) {
       MdcPrntScrn("\n\t");
       MdcPrntScrn("Input notes: a) Any number must be one-based ");
       MdcPrntScrn("(0 = All reversed)");
       MdcPrntScrn("\n\t");
       MdcPrntScrn("             b) Syntax of range   : X...Y or X-Y");
       MdcPrntScrn("\n\t");
       MdcPrntScrn("             c) Syntax of interval: X:S:Y     (S = step)");
       MdcPrntScrn("\n\t");
       MdcPrntScrn("             d) The list is sequence sensitive!");
       MdcPrntScrn("\n\t");
       MdcPrntScrn("             e) Just type <enter> for all reversed\n");
       MdcPrntScrn("\n\t");
       MdcPrntScrn("Example    : 1 3 4:2:11 12...6\n");
       MdcPrntScrn("\n\t");
       MdcPrntScrn("Your input [1...%u]: ",fi->number);
       MdcGetStrInput(input->list,MDC_MAX_LIST);
     }

     it = 1; bt = 2;
     msg = MdcHandleNormList(input->list,&input->inrs,&it,&bt,fi->number);
     if (msg != NULL) {
       MdcFree(input->inrs);
       MdcPrntWarn(msg);
       return(MDC_BAD_CODE);
     }

   }

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

   if (input->INTERACTIVE == MDC_YES) MdcPrintLine('-',MDC_FULL_LENGTH);

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

   return(MDC_YES);

}

char *MdcExtractImages(FILEINFO *fi)
{
   MdcExtractInputStruct *input = &mdcextractinput;
   Uint32 i, j, bytes;
   char *msg=NULL;
   IMG_DATA id_tmp, *new_image;
   IMG_DATA *id_src, *id_dest;
   int error;

   if (MDC_FILE_STDIN == MDC_YES) return(NULL); /* stdin already in use */

   /* in GUI skip command-line questions */
   if (XMDC_GUI == MDC_NO) {
     error=MdcGetImagesToExtract(fi,input);
     if (error != MDC_YES)  return("Failure retrieving images to extract");
   }


   /* free obsolete data structs */
   MdcFreeODs(fi);

   /* handle image extractions */
   if (input->inrs[1] == 0) {

     /*
      * reverse images
      */

     for (i=0; i < (fi->number/2); i++) {
        memcpy(&id_tmp,&fi->image[i],sizeof(IMG_DATA));
        memcpy(&fi->image[i],&fi->image[fi->number-1-i],sizeof(IMG_DATA));
        memcpy(&fi->image[fi->number-1-i],&id_tmp,sizeof(IMG_DATA));
     }

   }else{

     /*
      * extract/reorder images
      */

     /* handle new IMG_DATA structs */
     new_image = (IMG_DATA *)malloc(input->inrs[0]*sizeof(IMG_DATA));
     if (new_image == NULL) {
       MdcFree(input->inrs);
       return("Couldn't alloc new IMG_DATA array");
     }

     for (i=1; i<=input->inrs[0]; i++) {

       if (MDC_PROGRESS)
         MdcProgress(MDC_PROGRESS_INCR,1./(float)input->inrs[0],NULL);

       id_dest = &new_image[i-1];
       id_src  = &fi->image[input->inrs[i]-1];
       bytes = id_src->width * id_src->height * MdcType2Bytes(id_src->type);

       /* copy IMG_DATA struct    */
       memcpy((Uint8 *)id_dest,(Uint8 *)id_src,sizeof(IMG_DATA));

       /* copy fresh image buffer */
       id_dest->buf = MdcGetImgBuffer(bytes);
       if (id_dest->buf == NULL) {
         /* free up previous allocated resources */
         for (j=0; j < i-1; j++) MdcFree(new_image[j].buf);
         MdcFree(new_image);
         MdcFree(input->inrs);

         return("Couldn't alloc new image buffer");

       }else{

         memcpy(id_dest->buf,id_src->buf,bytes);

       }

     }

     /* remove all previous images */
     for (i=0; i<fi->number; i++) MdcFree(fi->image[i].buf);

     /* re-init FI */
     MdcFree(fi->image);
     fi->number = input->inrs[0];
     if (input->style == MDC_INPUT_ECAT_STYLE) {
       /* preserve ECAT style image */
       fi->dim[0] = 6;
       fi->dim[3] = input->num_p;
       fi->dim[4] = input->num_f;
       fi->dim[5] = input->num_g;
       fi->dim[6] = input->num_b;

     }else{
       fi->dim[0] = 3;
       fi->dim[3] = fi->number;
       for (i=4; i < MDC_MAX_DIMS; i++) fi->dim[i] = 1;
     }

     fi->image = new_image;
     if (fi->acquisition_type == MDC_ACQUISITION_DYNAMIC) {
       if (fi->dim[4] > 1) {
         fi->acquisition_type = MDC_ACQUISITION_DYNAMIC;
       }else{
         fi->acquisition_type = MDC_ACQUISITION_TOMO;
       }
     }

     fi->endian = MDC_FILE_ENDIAN = MDC_HOST_ENDIAN;
     msg=MdcImagesPixelFiddle(fi);
   }

   MdcFree(input->inrs);

   if (msg != NULL) return(msg);

   return(NULL);
}

