/* mosslin.c								   */
/*                                                                         */
/*           Search spectral lines with median: (val - med(val)) > thres   */
/*           Center lines: center of gravity or Gaussian fitting           */
/*                                                                         */
/*           Otmar Stahl, Aug. 17, 1993                                    */

/*

.VERSION

 090728		last modif

*/


#include <tbldef.h>
#include <midas_def.h>
#include <ok.h>
#include <mutil.h>
#include <nrutil.h>
#include <fitnol.h>

#include <stdio.h>


#define max(A,B) ((A)  > (B) ? (A) : (B))
#define min(A,B) ((A)  < (B) ? (A) : (B))
#define myabs(A) ((A)  >  0 ? (A) : (-A))

#define MAXLINES 1000
#define MAXSLITS 100

#define GRAVITY 0
#define GAUSSIAN 1


double Start[2], Step[2];
float Thres, Rnull;
int Npix[2], Method, Nseq, Inull;
int Ybin, Ystep, Iwin, Width, Tid;
int YbinTMP;
double *Xgaus, *Ygaus, *A, Dnull;

#ifdef __STDC__
  void center_lines (float[], float[], float[], int[],
		   int[], int[], int, int []);
  void search_lines (float[], int[], int *);
  void fit_lines (float[], int[], float[], int, int []);
#else
  void center_lines ();
  void search_lines ();
  void fit_lines ();
#endif



int main ()

{
  int i, iav;
  int nax, kun, knul, tid2, imno;
  int col, ncol, nslits, acol, arow, nsort, param[4], select;
  int null[3], slit[MAXSLITS], upper[MAXSLITS], lower[MAXSLITS];

  int icol[5];

  char method[21], wlc_image[60], mos_table[60];
  char output_table[60], unit[64], inst[72], line[80], linem[80];

  float moscol[3];
  float *buff1, *buff2, *image;

/*         get into Midas and get parameters             */

  SCSPRO ("mosslin");

  strcpy(inst,""), strcpy(unit,"");

  SCKGETC ("IN_A", 1, 60, &iav, wlc_image);
  SCKGETC ("IN_B", 1, 60, &iav, mos_table);
  SCKGETC ("OUT_A", 1, 60, &iav, output_table);
  SCKRDI ("INPUTI", 1, 4, &iav, param, &kun, &knul);
  SCKGETC ("INPUTC", 1, 3, &iav, method);

/*          map input file                              */

  SCIGET (wlc_image, D_R4_FORMAT, F_I_MODE, F_IMA_TYPE,
	  2, &nax, Npix, Start, Step, inst, unit, (char **)&image, &imno);

  Method = GRAVITY;
  sprintf (linem, "centering method:    Gravity");
  if (!strncmp (method, "GAU", 3) || !strncmp (method, "gau", 3))
    {
      Method = GAUSSIAN;
      sprintf (linem, "centering method:    Gaussian");
    }
/*           read table MOS                            */

  TCTOPN (mos_table, F_I_MODE, &tid2);
  TCIGET (tid2, &col, &ncol, &nsort, &acol, &arow);
  TCCSER (tid2, ":slit",&icol[0]);
  TCCSER (tid2, ":ystart",&icol[1]);
  TCCSER (tid2, ":yend",&icol[2]);

  nslits = 0;
  for (i = 1; i <= ncol; i++)
    {
      TCSGET(tid2, i, &select);
      if (select) {
	TCRRDR (tid2, i, 3, icol, moscol, null);
	slit[nslits] = (int) moscol[0];
	lower[nslits] =  (int) ((moscol[1]-Start[1])/Step[1]);
	upper[nslits] =  (int) ((moscol[2]-Start[1])/Step[1]) + 1;
	nslits++;
      }
    }

  TCTCLO (tid2);

/*          open output table                         */

  TCTINI (output_table, F_TRANS, F_O_MODE, 5, MAXLINES, &Tid);
  SCDWRD (Tid, "Pixel", Step, 1, 1, &kun);
  TCCINI (Tid, D_R4_FORMAT, 1, "F10.2", "Pixel", "X", &icol[0]);
  TCCINI (Tid, D_R4_FORMAT, 1, "F10.2", "Pixel", "Y", &icol[1]);
  TCCINI (Tid, D_R4_FORMAT, 1, "E12.3", "Pixel", "Peak", &icol[2]);
  TCCINI (Tid, D_R4_FORMAT, 1, "F6.0", "None ", "Slit", &icol[3]);

  Thres = (float) param[0];
  Iwin  = param[1]/2;
  Width = 2*Iwin+1;
  Ystep = param[2];
  Ybin  = param[3]*2+1;

  SCTPUT ("search lines ");
  SCTPUT ("------------\n");
  sprintf (line, "Input image:         %s ", wlc_image);
  SCTPUT (line);
  sprintf (line, "Input table:         %s ", mos_table);
  SCTPUT (line);
  sprintf (line, "Output table:        %s\n ", output_table);
  SCTPUT (line);
  SCTPUT ("input parameters: ");
  sprintf (line, "search window:       %i pixels", Width);
  SCTPUT (line);
  sprintf (line, "detection threshold: %6.2f DN", Thres);
  SCTPUT (line);
  SCTPUT (linem);

  sprintf (line, "\naverage on:          %i scan lines", Ybin);
  SCTPUT (line);
  sprintf (line, "step:                %i scan lines\n", Ystep);
  SCTPUT (line);

  buff1  = (float *) osmmget (Npix[0] * sizeof (float));
  buff2  = (float *) osmmget (Npix[0] * sizeof (float));
  Xgaus = dvector (1, Width);
  Ygaus = dvector (1, Width);
  A     = dvector (1, 3);

  TCMNUL(&Inull,&Rnull,&Dnull);

  center_lines (image, buff1, buff2, slit, upper, lower, nslits, icol);

  sprintf (line, "\nTotal no of detections: %i lines\n", Nseq);
  SCTPUT (line);

/*          epilogue ...                 */

  TCSINI (Tid);
  TCTCLO (Tid);

  osmmfree((char *) buff1);
  osmmfree((char *) buff2);
  free_dvector(Xgaus, 1, Width);
  free_dvector(Ygaus, 1, Width);
  free_dvector(A, 1, 3);

  SCSEPI ();
return 0;
}

/*---------------------------------------------------------------------------*/
#ifdef __STDC__
  void 
  center_lines (float image[], float rval[], float mval[], int slit[],
       	        int upper[], int lower[], int nslits, int icol[])
#else
  void 
  center_lines ( image, rval, mval, slit, upper, lower, nslits, icol)
  float image[],rval[], mval[];
  int   slit[],upper[],lower[],nslits,icol[];
#endif
{

  float obj[6];
  /*float buff[5];  replaced by TS-0896*/
  float *buff;
  int nact, nslit, ii, middle;
  int j, jj, k, linelist[MAXLINES];
  int iord;
  char line[80];

  Nseq = 1;

  if (Npix[1] > 1)
    {
      SCTPUT (" slit no.  detected lines ");
      SCTPUT (" --------  -------------- ");
    }

/*          loop over all slitlets                         */

  for (nslit = 0; nslit < nslits ; nslit++)
    {
      obj[3] = slit[nslit];

      /*        median Ybin rows in middle                */
      /*        changed from 5 rows to Ybin rows  TS-0896 */
      for (j = 0; j < Npix[0]; j++)
	rval[j] = 0.0;

      if (Ybin <= upper[nslit]-lower[nslit]+1) 
	{
	  middle = (int) (lower[nslit]+upper[nslit])/2 - (Ybin-1)/2; 
	  YbinTMP = Ybin;
	}
      else
	{
	  middle = 0;
	  YbinTMP = upper[nslit]-lower[nslit]+1;
	  sprintf(line," warning:  Ybin > slitlet");
	  SCTPUT(line);
	}
      buff = (float *) osmmget((YbinTMP+1)*sizeof(float));

      for (k = 0; k < Npix[0]; k++)
	{
	  for (j = middle ; j < middle + YbinTMP ; j++)
	    {
	      jj = j * Npix[0] + k;
	      ii = j-middle+1;
	      buff[ii] = image[jj];
	    }
	  mval[k] = pik_median(YbinTMP,buff);
	}
      
      /*       now search for lines   ...  */

      search_lines (mval, linelist, &nact);

      sprintf (line, "    %4i            %4i", slit[nslit], nact);
      SCTPUT (line);

      /*      now loop through the rows of one slitlet           */
      /*                  note that Ybin = 2 * radius + 1        */
      for (iord = lower[nslit]; iord <= upper[nslit]-YbinTMP+1; iord += Ystep)
	{
	  obj[1] =  (float) (iord + (YbinTMP-1)/2.) * Step[1] + Start[1];
	  /*      average scan  lines                                */

	  for (j = 0; j < Npix[0]; j++)
	    rval[j] = 0.0;
	  for (j = iord; j < iord + YbinTMP; j++)
	    {
	      for (k = 0; k < Npix[0]; k++)
		{
		  jj = j * Npix[0] + k;
		  rval[k] = rval[k] +  image[jj];
		}
	    }
	  for (k = 0; k < Npix[0]; k++) 
	    {
	      rval[k] = rval[k] / YbinTMP;
	    }

	  fit_lines (rval, linelist, obj, nact, icol);
	}
    }

  SCTPUT (" ----------------------- ");
}

/*---------------------------------------------------------------------------*/
#ifdef __STDC__
  void 
  search_lines (float rval[], int linelist[], int *nact)
#else
  void 
  search_lines ( rval, linelist, nact )
  float rval[];
  int linelist[],*nact;
#endif

{

  int number = 0, j, i, imax;
  float diff, max_intens;

  for (j = Iwin; j < Npix[0] - Iwin; j++)
    {
      diff = rval[j] - pik_median (Width, &rval[j - Iwin]);
      if (diff > Thres)
	{
	  imax = j;
	  max_intens = rval[j];
	  for (i = j - Iwin; i <= j + Iwin; i++)
	    if (rval[i] > max_intens)
	      {
		max_intens = rval[i];
		imax = i;
	      }
	  linelist[number] = imax;
	  number++;
	}
    }

  /*       remove doublets                                  */

  i = 0;
  while (i < number - 1)
    {
      if ((linelist[i + 1] - linelist[i]) < Width)
	{
	  number--;
	  for (j = i + 1; j < number; j++)
	    {
	      linelist[j] = linelist[j + 1];
	    }
	  i--;			/* check again (more than two detections!) */
	}
      i++;
    }
  *nact = number;
}

/*---------------------------------------------------------------------------*/
#ifdef __STDC__
  void 
  fit_lines (float rval[], int linelist[], float obj[], int nact, int icol[])
#else
  void 
  fit_lines ( rval, linelist, obj, nact, icol )
  float rval[],obj[];
  int   linelist[],nact,icol[];
#endif

{

  int j, k, jj, index;
  float factor, shift, a, b, aleft, aright, minimum;
  double x_guess;

  for (jj = 0; jj < nact; jj++)
    {
      index = linelist[jj];

      /*  center of gravity                                */

      switch (Method)
	{

	case GRAVITY:

	  aleft = rval[index - 1];
	  aright = rval[index + 1];
	  factor = 1;
	  if (aleft >= aright)
	    {
	      aleft = rval[index + 1];
	      aright = rval[index - 1];
	      factor = -1;
	    }
	  a = rval[index] - aleft;
	  b = aright - aleft;
	  shift = (a + b == 0.0) ? 0.0 : Step[0] * b / (a + b);
	  obj[0] = Start[0] + Step[0] * linelist[jj] + factor * shift;
	  obj[2] = rval[index];
	  break;

	case GAUSSIAN:

	  for (k = 1, j = index - Iwin; j <= index + Iwin; j++, k++)
	    {
	      Xgaus[k] = Start[0] + Step[0] * linelist[jj] + k - Iwin - 1;
	      Ygaus[k] = rval[j];
	    }

	    /* subtract minimum */

	  minimum = 1.e34;
	  for (k = 1 ; k <= 2 * Iwin + 1; k++)
	    {
	      if(Ygaus[k] < minimum)
		{
		  minimum = Ygaus[k];
		}
	    }
	  for (k = 1 ; k <= 2 * Iwin + 1; k++)
	    {
	      Ygaus[k] = Ygaus[k]-minimum;
	    }

	  A[1] = Ygaus[Iwin+1];
	  A[2] = Start[0] + Step[0] * linelist[jj];
	  x_guess = A[2];
	  A[3] = 3*Step[0];


	  /*	  
		  for (k = 1 ; k <= 2 * Iwin + 1; k++)
		  {
		  if (Xgaus[k] > 0 && Xgaus[k] < 500) 
		  {
		  printf("%f %f %f %f %f\n",Xgaus[k],Ygaus[k],A[1],A[2],A[3]);
		  } 
		  }
	  */
	    
	  
	  fit_gauss (Xgaus, Ygaus, Width, A, 3);
	  
	  obj[0] = A[2];
	  obj[2] = A[1];

	  /* check if result out of limits */

	  if (myabs (A[2] - x_guess)  > Iwin) {
	    obj[0] = Rnull;
	    obj[2] = Rnull;
	  }
	  break;
	}

      TCRWRR (Tid, Nseq, 4, icol, obj);
      Nseq++;
    }
}


