#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "./gethead.c"
#include "./swapfloat.c"
#include "./swapshort.c"
#include "./getmedf.c"
#include "./getmedf2.c"
#include "./getxynum.c"
#include "./qcksort.c"

/*
recompolx3.c  
2013.4.30  improved the calculation of datanum
*/

float getavg(float mbox[], int mnum);
float mclipavg(float mbox[], int mnum, int *comnum);
float minmaxavg(float mbox[], int mnum, int *comnum, int ireject);
void mkheader(char *header, int sorf);
void edithead(char *header, int wx, int wy);

int main (int argc, char**argv)
{

  FILE   *fp;
  int    lnum,fnum;
  char   line[20],cnum[20];
  char   **numarr;
  char   band[2],pref[5],objname[30],combname[50];
  int    i,j,xynum,xsize,ysize,datanum,sdatanum;
  short  *comnum;
  int    sumnum;
  float  *alldata,*odata,*data,*diff,*comb,*mbox;
  float  med,omed,ostdev;
  char   *header,*sheader;
  int    hfact,headsize;
  int    clipnum,ic;
  int    *iclip;
  int    ireject;
  float  thresh;
  char   tmpname[30];

  if (argc < 4){
    fprintf(stderr, "usage : recompolx3 band dithimage pref flist reject");
    return 0;
  }

  sprintf(band,"%s",argv[1]);
  sprintf(objname,"%s",argv[2]);
  sprintf(pref,"%s",argv[3]);
  ireject = atoi(argv[5]);
  /* ireject = 0 : sigclip 1:minmax(nlow=0, nhigh=1) 2:minmax(nlow=1, nhigh=1)  */

  strcpy(combname,band);
  strcat(combname,pref);
  strcat(combname,objname);
  strcat(combname,".fits");

  /*
  read the list
  */

  if(NULL==(fp=fopen(argv[4],"r"))){
    printf("%s can not be opened.\n", argv[4]);
    exit(1);
  }
  lnum=0;
  while(fgets(line, sizeof(line), fp) !=NULL){
    sscanf(line, "%s", cnum);
    strcpy(tmpname,cnum);
    strcat(tmpname,".fits");
    if(access(tmpname,0)==0){
      lnum++;
    }
  }
  fclose(fp);

  printf("%d",lnum);

  numarr=(char**)malloc(lnum*sizeof(char)*20);
  fp=fopen(argv[4],"r");
  fnum=0;
  while(fgets(line, sizeof(line), fp) !=NULL){
    sscanf(line, "%s", cnum);
    numarr[fnum]=(char*)malloc(20);
    strcpy(numarr[fnum],cnum);
    strcat(numarr[fnum],".fits");
    if(access(numarr[fnum],0)==0){
      fnum++;
    }
  }
  fclose(fp);


  hfact=gethead(numarr[0]);
  headsize=hfact*2880;
  getxynum(numarr[0], &xsize, &ysize);
  xynum=xsize*ysize;

  /* 2013.4.30  improved */
  
  if (xynum*sizeof(float)%2880 == 0){
    datanum = xynum;
  } else {
    datanum = (xynum*sizeof(float)/2880+1)*2880/sizeof(float);
  }

  if (xynum*sizeof(short)%2880 == 0){
    sdatanum = xynum;
  } else {
    sdatanum = (xynum*sizeof(short)/2880+1)*2880/sizeof(short);
  }

  /*  2013.4.30   */

  alldata=(float*)malloc(lnum*xynum*sizeof(float));

  odata=(float*)malloc(xynum*sizeof(float));
  fp=fopen(numarr[0],"rb");
  fseek(fp,headsize,SEEK_SET);
  fread(odata,sizeof(float),xynum,fp);
  fclose(fp);
  for(i=0; i<xynum; i++){
    swapfloat(&odata[i]);
    alldata[i]=odata[i];
  }

  if(strcmp(pref,"q")==0 || strcmp(pref,"u")==0 || strcmp(pref,"v")==0 || strcmp(pref,"qc")==0 || strcmp(pref,"uc")==0){
      thresh=-20000;
  } else {
      getmedf2(odata,xynum,&omed,&ostdev,-100,20000);
      thresh=omed-10*ostdev;
  }

  for(j=1; j<lnum; j++){

    hfact=gethead(numarr[j]);
    headsize=hfact*2880;
    fp=fopen(numarr[j],"rb");
    fseek(fp,headsize,SEEK_SET);
    data=(float*)malloc(xynum*sizeof(float));
    fread(data,sizeof(float),xynum,fp);
    fclose(fp);

    diff=(float*)malloc(xynum*sizeof(float));
    for(i=0; i<xynum; i++){
      swapfloat(&data[i]);
      diff[i]=data[i]-odata[i];
    }
    med=getmedf(diff,xynum,-10000,10000);
    free(diff);

    for(i=0; i<xynum; i++){
      alldata[i+j*xynum]=data[i]-med;
    }

    free(numarr[j]);
    free(data);
  }

  free(numarr);


/*
  combine
*/

  comb=(float*)malloc(datanum*sizeof(float));
  comnum=(short*)malloc(sdatanum*sizeof(short));
  iclip=(int*)malloc(lnum*sizeof(int));
  for(j=0; j<xynum; j++){
    clipnum=0;
    for(i=0; i<lnum; i++){
      if(alldata[j+i*xynum] > thresh){
	iclip[i]=1;
	clipnum++;
      }else{
	iclip[i]=0;
      }
    }

    if(clipnum>0){
      mbox=(float*)malloc(clipnum*sizeof(float));
      ic=0;
      for(i=0; i<lnum; i++){
	if(iclip[i] == 1){
	  mbox[ic] = alldata[j+i*xynum];
	  ic++;
	} 
      }

      if(ireject == 0){
	/* sigclip */
	comb[j]=mclipavg(mbox, clipnum, &sumnum);
      } else {
	/* minmax */
	/* ireject = 1 : nlow = 0, nhigh = 1 */
	/* ireject = 2 : nlow = 1, nhigh = 1 */
	comb[j]=minmaxavg(mbox, clipnum, &sumnum, ireject);
      }
      comnum[j]=sumnum;
	
      free(mbox);
    } else {
      comb[j]=-100000;
      comnum[j]=0;
    }
  }
  free(iclip);

  for(i=0; i<datanum; i++){
    if (i>=xynum){
      comb[i]=0;
    }
    swapfloat(&comb[i]);
  }

  for(i=0; i<sdatanum; i++){
    if (i>=xynum){
      comnum[i]=0;
    }
    swapshort(&comnum[i]);
  }

  header=(char*)malloc(2880*sizeof(char)+1);
  mkheader(header, 1);
  edithead(header, xsize, ysize);  

  if(NULL==(fp=fopen(combname,"wb"))){
    printf("%s can not be opened.\n",combname);
    exit(1);
  }
  fwrite(header,sizeof(char),2880,fp);
  fwrite(comb,sizeof(float),datanum,fp);
  fclose(fp);

  sheader=(char*)malloc(2880*sizeof(char)+1);
  mkheader(sheader, 2);
  edithead(sheader, xsize, ysize);  

  if(NULL==(fp=fopen("count.fits","wb"))){
    printf("count.fits can not be opened.\n");
    exit(1);
  }
  fwrite(sheader,sizeof(char),2880,fp);
  fwrite(comnum,sizeof(short),sdatanum,fp);
  fclose(fp);

  free(header);
  free(sheader);
  free(comb);
  free(comnum);
  free(alldata);
  free(odata);

  return 0;

}

float minmaxavg(float mbox[], int mnum, int *comnum, int ireject)
{

  int   i,cnum,ithresh;
  float avg;
  
  if(ireject == 1){
    ithresh=1;
  } else {
    ithresh=2;
  }

  if(mnum>ithresh){

    avg = 0;
    qcksort(mbox,0,mnum-1);
    if (ireject == 1){
      /* nlow=0, nhigh=1 */
      for(i=0; i<mnum-1; i++){
	avg = avg + mbox[i];
      }
      avg = avg / (mnum-1);
      cnum = mnum-1;
    } else {
      /* nlow=1, nhigh=1 */
      for(i=1; i<mnum-1; i++){
	avg = avg + mbox[i];
      }
      avg = avg / (mnum-2);
      cnum = mnum-2;
    }

  } else {
    for(i=0; i<mnum; i++){
      avg = avg + mbox[i];
    }
    avg = avg / mnum;
    cnum = mnum;
  }

  *comnum=cnum;
  return avg;
  
}


float mclipavg(float mbox[], int mnum, int *comnum)
{

  int   i,j,k,cnum;
  float avg,rms,med;
  float *clip;
  int   *iclip;

  qcksort(mbox,0,mnum-1);
  if(mnum%2==0){
    med=0.5*(mbox[mnum/2-1]+mbox[mnum/2]);
  }else{
    med=mbox[mnum/2];
  }

  rms=0;
  for(i=0; i<mnum; i++){
    rms=rms+(mbox[i]-med)*(mbox[i]-med);
  }
  rms=sqrt(rms/mnum);

  for(k=0; k<5; k++){
    cnum=0;
    iclip=(int*)malloc(mnum*sizeof(int));
    for(i=0; i<mnum; i++){
      if(fabs(mbox[i]-med)<=3*rms){
	iclip[i]=1;
	cnum++;
      } else {
	iclip[i]=0;
      }
    }
    if(cnum>0){
      clip=(float*)malloc(cnum*sizeof(float));
      j=0;
      for(i=0; i<mnum; i++){
        if(iclip[i]==1){
          clip[j]=mbox[i];
          j++;
        }  
      }

      if(cnum%2==0){
	med=0.5*(clip[cnum/2-1]+clip[cnum/2]);
      }else{
	med=clip[cnum/2];
      }
      rms=0;
      for(i=0; i<cnum; i++){
	rms=rms+(clip[i]-med)*(clip[i]-med);
      }
      rms=sqrt(rms/cnum);

      avg=0;
      for(i=0; i<cnum; i++){
	avg=avg+clip[i];
      }
      avg=avg/cnum;

      free(iclip);
      free(clip);

    } else {
      avg=-55000;
      free(iclip);
      break;
    }
  }

  *comnum=cnum;
  return avg;

}




float getavg(float mbox[], int mnum)
{

  int   i,j,k,cnum;
  float avg,navg,rms;
  float *clip;
  int   *iclip;

  avg=0;
  for(i=0; i<mnum; i++){
    avg=avg+mbox[i];
  }
  avg=avg/mnum;

  rms=0;
  for(i=0; i<mnum; i++){
    rms=rms+(mbox[i]-avg)*(mbox[i]-avg);
  }
  rms=sqrt(rms/mnum);

  for(k=0; k<10; k++){
    cnum=0;
    iclip=(int*)malloc(mnum*sizeof(int));
    for(i=0; i<mnum; i++){
      if(fabs(mbox[i]-avg)<=3*rms){
	iclip[i]=1;
	cnum++;
      } else {
	iclip[i]=0;
      }
    }
    if(cnum>0){
      clip=(float*)malloc(cnum*sizeof(float));
      j=0;
      navg=0;
      for(i=0; i<mnum; i++){
        if(iclip[i]==1){
          clip[j]=mbox[i];
          navg=navg+mbox[i];
          j++;
        }  
      }
      avg=navg/cnum;
      rms=0;
      for(i=0; i<cnum; i++){
        rms=rms+(clip[i]-avg)*(clip[i]-avg);
      }
      rms=sqrt(rms/cnum);
      free(iclip);
      free(clip);
    } else {
      avg=-55000;
      free(iclip);
      break;
    }
  }

  return avg;

}


void mkheader(char *header, int sorf)
{

  int       ih;
  char      fheader[2881]="SIMPLE  =                    T / Fits standard                                  BITPIX  =                  -32 / Bits per pixel                                 NAXIS   =                    2 / Number of axes                                 NAXIS1  =                 1024 / Axis length                                    NAXIS2  =                 1024 / Axis length                                    EXTEND  =                    F / File may contain extensions                    END                                                                             ";
  char      sheader[2881]="SIMPLE  =                    T / Fits standard                                  BITPIX  =                   16 / Bits per pixel                                 NAXIS   =                    2 / Number of axes                                 NAXIS1  =                 1024 / Axis length                                    NAXIS2  =                 1024 / Axis length                                    EXTEND  =                    F / File may contain extensions                    END                                                                             ";
  char      nn[2]=" ";

  if(sorf==1){
    for(ih=0; ih<560; ih++){
      header[ih]=fheader[ih];
    }
    for(ih=560; ih<2880; ih++){
      header[ih]=nn[0];
    }
  } else if (sorf==2){
    for(ih=0; ih<560; ih++){
      header[ih]=sheader[ih];
    }
    for(ih=560; ih<2880; ih++){
      header[ih]=nn[0];
    }
  } else {
    printf("wrong type for sorf.\n");
    exit(1);
  }



}



void edithead(char *header, int wx, int wy)
{

  int    ixd4,ixd3,ixd2,ixd1;
  int    iyd4,iyd3,iyd2,iyd1;
  char   cxd4[2],cxd3[2],cxd2[2],cxd1[2];
  char   cyd4[2],cyd3[2],cyd2[2],cyd1[2];

  ixd4=wx/1000;
  ixd3=(wx-ixd4*1000)/100;
  ixd2=(wx-ixd4*1000-ixd3*100)/10;
  ixd1=wx-ixd4*1000-ixd3*100-ixd2*10;

  sprintf(cxd4, "%d", ixd4);
  sprintf(cxd3, "%d", ixd3);
  sprintf(cxd2, "%d", ixd2);
  sprintf(cxd1, "%d", ixd1);

  iyd4=wy/1000;
  iyd3=(wy-iyd4*1000)/100;
  iyd2=(wy-iyd4*1000-iyd3*100)/10;
  iyd1=wy-iyd4*1000-iyd3*100-iyd2*10;

  sprintf(cyd4, "%d", iyd4);
  sprintf(cyd3, "%d", iyd3);
  sprintf(cyd2, "%d", iyd2);
  sprintf(cyd1, "%d", iyd1);

  header[266]=cxd4[0];
  header[267]=cxd3[0];
  header[268]=cxd2[0];
  header[269]=cxd1[0];

  header[346]=cyd4[0];
  header[347]=cyd3[0];
  header[348]=cyd2[0];
  header[349]=cyd1[0];

}



