/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* .COPYRIGHT   (C) 1994-2009 European Southern Observatory     */
/* .IDENT       changedef.c                                */
/* .AUTHORS     Sabine Moehler   (LSW)                     */
/* .KEYWORDS    Spectroscopy, Long-Slit, MOS               */
/* .PURPOSE     Change of sky resp. objects definitions    */
/*              for MOS spectra                            */
/*                                                         */
/*
   .INPUT/OUTPUT:
       POSR/R/1/3   :  positions of objects/sky to be added/deleted/changed
       PATH/I/1/2   :  Action to be taken:
                       1: delete object
                       2: add object
                       3: delete sky
                       4: add sky
                       5: change sky
                       Number of slitlet

.VERSION     1.0  Creation  18-JAN-1994  

 090804		last modif
   -------------------------------------------------------
*/

#include <tbldef.h>
#include <midas_def.h>
#include <ok.h>

#include <stdio.h>



#define MAXSLITS 100
#define MAXNUM 500

int   min_dist,min_sky,tidwin, wrow, kunit, knul; 
int   os_col, o1_col, o2_col, s1_col, s2_col, ss_col;
char  text[120];

#ifdef __STDC__
int check_sky(float [], int [], int []);
int check_slit(float [], int [], int [], int);
#else
int check_sky();
int check_slit();
#endif

void check_obj();



int main()

{
 
   int   i_sky, i_obj, lim, found, i, tidmos, actvals;
   int   action, col, nslits, acol, arow, nsort;
   int   wcol, awcol, awrow, wsort;
   int   obj1[MAXNUM], obj2[MAXNUM], slitobj[MAXNUM]; 
   int   sky1[MAXNUM], sky2[MAXNUM], slitsky[MAXNUM];
   int   null, posi[2], path[2], slitnum, nsky, nobj;
   int   sl_col, up_col, lo_col;
   int   slitrow[MAXSLITS], upper[MAXSLITS], lower[MAXSLITS], slit; 
   char  mos_table[60], window_table[60];
   float posr[3];
   

   SCSPRO("changedef");

/* Read action from keyword PATH  */

   SCKRDR("POSR",  1,  3, &actvals, posr, &kunit, &knul);
   SCKRDI("PATH",  1,  2, &actvals, path, &kunit, &knul);
   SCKRDI("MIN_DIST",  1,  1, &actvals, &min_dist, &kunit, &knul);
   SCKRDI("MIN_SKY",  1,  1, &actvals, &min_sky, &kunit, &knul);
   SCKGETC("IN_B", 1, 60, &actvals, mos_table); 
   SCKGETC("OUT_A",1, 60, &actvals, window_table);
   action = path[0];
   slitnum = path[1];

/*           read table MOS                            */

   TCTOPN(mos_table,F_I_MODE,&tidmos);
   TCIGET(tidmos,&col,&nslits,&nsort,&acol,&arow);
   TCLSER(tidmos, "slit", &sl_col);
   TCLSER(tidmos, "ystart", &lo_col);
   TCLSER(tidmos, "yend", &up_col);

   for (i=1;i<=nslits;i++) 
     {
      TCERDI(tidmos, i, sl_col, &slit, &null);
      TCERDI(tidmos, i, lo_col, &lower[i-1], &null);
      TCERDI(tidmos, i, up_col, &upper[i-1], &null);
/* table row for a given slit number */
      slitrow[slit] = i-1;
     }

   TCTCLO(tidmos);

/* read table WINDOWS */

   TCTOPN(window_table,F_IO_MODE,&tidwin);
   TCIGET(tidwin,&wcol,&wrow,&wsort,&awcol,&awrow);
   TCLSER(tidwin, "Obj_Slit", &os_col);
   TCLSER(tidwin, "Obj_Strt", &o1_col);
   TCLSER(tidwin, "Obj_End", &o2_col);
   TCLSER(tidwin, "Sky_Strt", &s1_col);
   TCLSER(tidwin, "Sky_End", &s2_col);
   TCLSER(tidwin, "Sky_Slit", &ss_col);
   for (i=1;i<=wrow;i++) 
     {
      TCERDI(tidwin, i, os_col, &slitobj[i-1], &null); 
      TCERDI(tidwin, i, o1_col, &obj1[i-1], &null); 
      TCERDI(tidwin, i, o2_col, &obj2[i-1], &null); 
      TCERDI(tidwin, i, s1_col, &sky1[i-1], &null); 
      TCERDI(tidwin, i, s2_col, &sky2[i-1], &null);
      TCERDI(tidwin, i, ss_col, &slitsky[i-1], &null);  
     }
   found = 0;
   lim = 0;
   switch (action)  
     {
      case (1):   /* delete object */
        {
         found = 0;
         for (i = 0; i <= wrow-1; i++)
           {
            if (obj1[i] <=  posr[0] && obj2[i] >= posr[0])
              {
               TCEDEL(tidwin, i+1, os_col);   
               TCEDEL(tidwin, i+1, o1_col);
               TCEDEL(tidwin, i+1, o2_col);
               found = 1;
              }
           } 
         if (found == 0)
           {
            sprintf(text, "There is no object");
            SCTPUT(text);
           }
         break;
        }  

      case (2):   /* add object */
        {
/* check whether object is within slitlet  */
         lim = check_slit(posr, lower, upper, slitrow[slitnum]); 
         if (lim == 0)
           {
/* adapt sky limits for new object  */
            check_obj(posr, sky1, sky2, slitsky);

/* write new object */
            SCDRDI(tidwin, "NOBJ", 1, 1, &actvals, &nobj, &kunit, &knul);
            nobj++;
            TCEWRI(tidwin, nobj, os_col, &slitnum);
            posi[0] = (int) posr[0];
            posi[1] = (int) posr[1];
            TCEWRI(tidwin, nobj, o1_col, &posi[0]);
            TCEWRI(tidwin, nobj, o2_col, &posi[1]);
            SCDWRI(tidwin, "NOBJ", &nobj, 1, 1, &kunit); 
           }
         break;
        }  

      case (3):   /* delete sky */
        {
         for (i = 0; i <= wrow-1; i++)
           {
            if (sky1[i] <=  posr[0] && sky2[i] >= posr[0])
              {
               TCEDEL(tidwin, i+1, s1_col);   
               TCEDEL(tidwin, i+1, s2_col);
               TCEDEL(tidwin, i+1, ss_col);
               found = 1;
              }
           }
         if (found == 0)
           {
            sprintf(text, "There is no sky");
            SCTPUT(text);
           }
         break;
        }  

      case (4):   /* add sky */
        {
         found = check_sky(posr, obj1, obj2); 
         if (found == 0)
           {
/* check whether sky is within slitlet  */
            lim = check_slit(posr, lower, upper, slitrow[slitnum]); 
             
/* write new sky */
            if (lim == 0)
              {   
               posi[0] = (int) posr[0];
               posi[1] = (int) posr[1];
               SCDRDI(tidwin, "NSKY", 1, 1, &actvals, &nsky, &kunit, &knul);
               nsky++;
               TCEWRI(tidwin, nsky, s1_col, &posi[0]);
               TCEWRI(tidwin, nsky, s2_col, &posi[1]);
               TCEWRI(tidwin, nsky, ss_col, &slitnum);
               SCDWRI(tidwin, "NSKY", &nsky, 1, 1, &kunit); 
              }
           }
         break;
        }  

      case (5):   /* change object */
        {
/* find out which object shall be changed */
         i_obj = -1;
         for (i=0; i<=wrow-1; i++)
           {
            if (obj1[i] < posr[2] && obj2[i] > posr[2])
               i_obj = i;
           }
         if (i_obj < 0)
           {
            sprintf(text, "There is no object");
            SCTPUT(text);
           } 
/* check if only one limit shall be changed and adjust posr */
         if (posr[0] <= -9999.9) posr[0] = obj1[i_obj];
         if (posr[1] <= -9999.9) posr[1] = obj2[i_obj];

/* check whether object is within slitlet  */
         if (i_obj >= 0) lim = check_slit(posr, lower, upper, slitrow[slitnum]); 
         if (lim == 0 && i_obj >= 0)
           {
/* adapt sky for changed object */
            check_obj(posr, sky1, sky2, slitsky);
 
/* write changed object */
            posi[0] = (int) posr[0];
            posi[1] = (int) posr[1];
            TCEWRI(tidwin, i_obj+1, o1_col, &posi[0]);
            TCEWRI(tidwin, i_obj+1, o2_col, &posi[1]);
           }
         break;
        }  

      case (6):   /* change sky */
        {
/* find out which sky shall be changed */
         i_sky = -1;
         for (i=0; i<=wrow-1; i++)
           {
            if (sky1[i] < posr[2] && sky2[i] > posr[2])
            i_sky = i;
           }
         if (i_sky < 0)
           {
            sprintf(text, "There is no sky");
            SCTPUT(text);
           } 
/* check if only one limit shall be changed and adjust posr */
         if (posr[0] <= -9999.9) posr[0] = sky1[i_sky];
         if (posr[1] <= -9999.9) posr[1] = sky2[i_sky];

/* check that there is no object within changed sky   */
         if (i_sky >= 0) found = check_sky(posr, obj1, obj2); 
         if (found == 0 && i_sky >= 0)
           {
/* check whether sky is within slitlet  */
            lim = check_slit(posr, lower, upper, slitrow[slitnum]); 
            if (lim == 0)
              {   
/* write changed sky */
               posi[0] = (int) posr[0];
               posi[1] = (int) posr[1];
               TCEWRI(tidwin, i_sky+1, s1_col, &posi[0]);
               TCEWRI(tidwin, i_sky+1, s2_col, &posi[1]);
              }
           }
         break;
        }  
      default:
        {
         sprintf(text, "Wrong number - there is no action for this number");
         SCTPUT(text);
         break;
        }
     } 
   TCTCLO(tidwin);
   SCSEPI();
return 0;
}
/*--------------------------------------------------------------------*/
#ifdef __STDC__
void check_obj(float rpos[], int sky_strt[], int sky_end[], int sky_slit[])
#else
void check_obj(rpos, sky_strt, sky_end, sky_slit)
float rpos[];
int sky_strt[],sky_end[],sky_slit[];
#endif

{
  int   actvals, nsky, i;
  
  for (i = 0; i <= wrow-1; i++)  
     {
/* check whether object is completely within sky    */
      if (sky_strt[i] <=  rpos[0]-min_dist && sky_end[i] >= rpos[1]+min_dist)
        {
         /* sprintf(text, "new object within sky\n");
         SCTPUT(text); */
         SCDRDI(tidwin, "NSKY", 1, 1, &actvals, &nsky, &kunit, &knul);
         sky_end[i] = rpos[0]-min_dist;
         sky_strt[nsky+1] = rpos[1]+min_dist;
         sky_end[nsky+1] = sky_end[i]; 
         if ((sky_end[i]-sky_strt[i]) <= min_sky-1) 
           {
            /* sprintf(text,"left sky too small   \n");
            SCTPUT(text); */
            TCEDEL(tidwin, i+1, s1_col);
            TCEDEL(tidwin, i+1, s2_col);
            TCEDEL(tidwin, i+1, ss_col);
           }
         else TCEWRI(tidwin, i+1, s2_col, &sky_end[i]);   
           
         if ((sky_end[nsky+1]-sky_strt[nsky+1]) <= min_sky-1) 
           {
            /* sprintf(text, "right sky too small   \n");
            SCTPUT(text); */
           }
         else
           {
            nsky++;
            TCEWRI(tidwin, nsky, s1_col, &sky_strt[nsky]);
            TCEWRI(tidwin, nsky, s2_col, &sky_end[nsky]);
            TCEWRI(tidwin, nsky, ss_col, &sky_slit[i]); 
            SCDWRI(tidwin, "NSKY", &nsky, 1, 1, &kunit); 
           }
        }

/* check whether right part of object is within sky     */

      if (sky_strt[i] > rpos[0]-min_dist && sky_strt[i] < rpos[1]+min_dist && sky_end[i] > rpos[1]+min_dist)
        {
         /* sprintf(text, "new object within sky\n");
         SCTPUT(text); */
         sky_strt[i] = rpos[1]+min_dist;
         if ((sky_end[i]-sky_strt[i]) <= min_sky-1) 
           {
            /* sprintf(text,"rest sky too small   \n");
            SCTPUT(text); */
            TCEDEL(tidwin, i+1, s1_col);
            TCEDEL(tidwin, i+1, s2_col);
            TCEDEL(tidwin, i+1, ss_col);   
           }
         else 
           TCEWRI(tidwin, i+1, s1_col, &sky_strt[i]);  
        }  
/*    check whether left part of object is within sky     */
      if (sky_end[i] < rpos[1]+min_dist && sky_end[i] > rpos[0]-min_dist && sky_strt[i] < rpos[0]-min_dist)
        {
         /* sprintf(text, "new object within sky\n");
         SCTPUT(text); */
         sky_end[i] = rpos[0]-min_dist;
         if ((sky_end[i]-sky_strt[i]) <= min_sky) 
           {
            /* sprintf(text,"rest sky too small   \n");
            SCTPUT(text);  */
            TCEDEL(tidwin, i+1, s1_col);
            TCEDEL(tidwin, i+1, s2_col);
            TCEDEL(tidwin, i+1, ss_col);
           }
         else TCEWRI(tidwin, i+1, s2_col, &sky_end[i]);  
        }

/*    check whether object covers sky region      */
      if (sky_strt[i] >=  rpos[0]-min_dist && sky_end[i] <= rpos[1]+min_dist)
        {
         /* sprintf(text, "new object covers sky region\n");
         SCTPUT(text); */
         TCEDEL(tidwin, i+1, s1_col);
         TCEDEL(tidwin, i+1, s2_col);
         TCEDEL(tidwin, i+1, ss_col);
        }
     }
}
/*-------------------------------------------------------------------*/
#ifdef __STDC__
int check_sky (float rpos[], int obj_strt[], int obj_end[])
#else
int check_sky (rpos, obj_strt, obj_end)
float rpos[];
int obj_strt[],obj_end[];
#endif

{
  int   i, found;
  
  found = 0;
  
  for (i = 0; i <= wrow-1; i++)
     {
      if (rpos[0] <= obj_strt[i] && rpos[1] >= obj_end[i])
        {
         sprintf(text,"There is an object within the new sky region!");
         SCTPUT(text);
         sprintf(text,"Delete/change object first and then add sky");
         SCTPUT(text);
         found = 1;
        }
      if (rpos[0] >= obj_strt[i] && rpos[1] <= obj_end[i])
        {
         sprintf(text,"The new sky region lies within an object's region!");
         SCTPUT(text);
         sprintf(text,"Delete object first and then add sky");
         SCTPUT(text);
         found = 1;
        }
      if (rpos[0] > obj_strt[i] && rpos[0] <= obj_end[i] && rpos[1] >= obj_end[i])
        {
         sprintf(text,"The new sky region overlaps with an object's region!");
         SCTPUT(text);
         sprintf(text,"Delete object first and then add sky");
         SCTPUT(text);
         found = 1;
        }
      if (rpos[0] <= obj_strt[i] && rpos[1] < obj_end[i] && rpos[1] >= obj_strt[i])
        {
         sprintf(text,"The new sky region overlaps with an object's region!");
         SCTPUT(text);
         sprintf(text,"Delete object first and then add sky");
         SCTPUT(text);
         found = 1;
        }
      if (rpos[0] > obj_end[i] && rpos[0] < obj_end[i]+min_dist)
        {
         sprintf(text, "There are less than %d pixels between sky and adjacent object", min_dist);
         SCTPUT(text);
        }
      if (rpos[1] < obj_strt[i] && rpos[1] > obj_strt[i]-min_dist)
        {
         sprintf(text, "There are less than %d pixels between sky and adjacent object", min_dist);
         SCTPUT(text);
        }
     }
   return found;
}
/*--------------------------------------------------------------------------*/
#ifdef __STDC__
int check_slit (float rpos[], int slit_strt[], int slit_end[], int numslit)
#else
int check_slit (rpos, slit_strt, slit_end, numslit)
float rpos[];
int slit_strt[],slit_end[],numslit;
#endif

{
   int limit;

   limit = 0;
   if (rpos[0] < slit_strt[numslit] || rpos[0] >= slit_end[numslit]) 
     {
      sprintf(text,"Lower limit outside slitlet - no change");
      SCTPUT(text);
      limit = 1;
     }
   if (rpos[1] <= slit_strt[numslit] || rpos[1] > slit_end[numslit])
     {
      sprintf(text,"Upper limit outside slitlet - no change");
      SCTPUT(text);
      limit = 1;
     }
   return limit;
}
