#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define LWORD unsigned long
#define WORD  unsigned short
#define BYTE  unsigned char

// GIF-parameter
unsigned char SuffixTable[4999], ByteBuf[2592], BlockBuf[256];
short EncodeTable[4999], PrefixTable[4999];      // have in common_use
LWORD TempCode;
short Code, RunBits, ByteCount, ShiftBits;

#define n  8192
#define m   512
char head[36][80],h[36][80],a[60],g[60];
unsigned char b[m*m];
FILE  *fp;
float d[n][n];
short id[n][n];
int bit,zero,type;
int n1,n2,n11,n22;
int i8;

main(ac,av)
int ac; char *av[];
{
  int   i,j,k,i1,j1,ip,q;
  float x,y;
  int   force=0;
  if(ac<2){
    printf("\n\t ****** shrink 1k~8k_fit to GIF, ratio 1/566 ********\n");
    printf("\n\t                             jiang, 110811\n");
    printf("\n\tUsage: g4 e*.fit ! (for all sort fitsfile of BOK & batc)\n");
    printf("\n\t                 if existed, not do; if !, force to do\n\n");
    exit(0);
  }
  if(av[ac-1][0]=='!'){ ac--; force=1; }
  if(ac<3)force=1;
  for(ip=1;ip<ac;ip++){
    strcpy(a,av[ip]); strcpy(g,a);
    k=strlen(g); g[k-3]='g'; g[k-2]='i'; g[k-1]='f'; 
    if(force==0){
      fp=fopen(g,"rb"); if(fp!=0){ fclose(fp); continue; } 
    }
    printf("%3d: %s --> ",ip,a);
    fp=fopen(a,"rb");
    if(fp==0){ printf(" file not find !\n"); continue; }
    fread(head,36,80,fp);
    sscanf(&head[1][20],"%d",&bit);
    sscanf(&head[3][20],"%d",&n1);
    sscanf(&head[4][20],"%d",&n2);
    if(n1>8192 || n2 >8192){ 
      printf(" not a 1k~8k CCD file !\n"); goto l10; }
    i8=1;
    if(n1>512  || n2 >512 )i8=2;
    if(n1>1024 || n2 >1024)i8=4;
    if(n1>2048 || n2 >2048)i8=8;
    if(n1>4096 || n2 >4096)i8=16;
 
    k=indexpos(head,"END     ",36);
    while(k==36){ fread(h,36,80,fp); k=indexpos(h,"END     ",36); } 
    if(bit!=16){
      for(j=0;j<n2;j++)fread(&d[j][0],n1,4,fp); swap4(d,n*n*4); 
    } else {
      for(j=0;j<n2;j++)fread(&id[j][0],n1,2,fp); swap2(id,n*n*2);
      k=indexpos(head,"BZERO   ",36);
      sscanf(&head[k][12],"%d",&zero);
      for(j=0;j<n2;j++)for(i=0;i<n1;i++)d[j][i]=id[j][i]+zero;
    }
    fclose(fp);
    type=0;                                                 // normal
    k=indexpos(head,"SUP_FLAT",36);  if(k!=36)type=1;       // flat 
    k=indexpos(head,"SUP_BIAS",36);  if(k!=36)type=2;       // bias
    k=indexpos(head,"SKYADU  ",36);
    if(k!=36)sscanf(&head[32][12],"%f",&y); else {
      if(n1==4072){
        for(j=0;j<n2;j++)for(i=0;i<n1;i++)d[4071-i][j]=id[j][i]+zero;
        k=n1; n1=n2; n2=k;
        printf("(turn -90 deg.) ");
        sub1(0,0,0.);
        sub1(0,n1/2,0.);
        sub1(n2/2,0,0.);
        sub1(n2/2,n1/2,0.);
      } else {
        y=10000.;
        x=d[1000][3000];  if(y>x)y=x;
        x=d[1000][1000];  if(y>x)y=x;
        x=d[3000][3000];  if(y>x)y=x;
        x=d[3000][1000];  if(y>x)y=x;
      }
    }
    if(a[0]=='e'){
        sub1(0,0,y);
        sub1(0,n1/2,y);
        sub1(n2/2,0,y);
        sub1(n2/2,n1/2,y);
    } 
    if(type==1){ y=0.; printf("(sup_plat) "); }
    if(type==2){ y=0.; printf("(sup_bias) "); }
    for(j=k=0;j<n2;j+=i8)for(i=0;i<n1;i+=i8){ x=0.;
      for(j1=j;j1<j+i8;j1++)for(i1=i;i1<i+i8;i1++)x+=d[j1][i1]-y;
      if(type==0)x/=(i8*i8);  if(type==2)x/=10.;
      x+=50.;  if(x<0.)x=0.; if(x>255.)x=255.;
      q=x; b[k++]=q;
    }
    fp=fopen(g,"wb");  printf("%s\n",g);    
    n11=n1/i8; n22=n2/i8;
    togif(b,n11,n22);
l10:
    fclose(fp);   
  }
}

sub1(nj,ni,sky)
int nj,ni; float sky;
{
  float x,y;
  int i,j,k;
  short a[100*100];
  x=0.; k=0;
  for(j=nj+900;j<nj+1000;j++)for(i=ni+900;i<ni+1000;i++)a[k++]=d[j][i]/2.;
  white_black(a,1,k,&x,&y); x*=2.;
  for(j=nj;j<nj+n2/2;j++)for(i=ni;i<ni+n1/2;i++)d[j][i]-=(x-sky);
}

FillBlockBuf()
{
  TempCode |= (unsigned int)Code << ShiftBits;
  ShiftBits += RunBits;
  while(ShiftBits >= 8)  {
    BlockBuf[++ByteCount] = TempCode & 0x00FF;
    if(ByteCount == 255){
      BlockBuf[0] = (unsigned char)ByteCount;
      fwrite(BlockBuf, 1, ByteCount+1, fp);
      ByteCount = 0;
    }
    TempCode >>= 8;
    ShiftBits -= 8;
  }
}

togif(c256,m1,m2)
unsigned char *c256;
int m1,m2;
{
short Encode, MaxCodeSize, Width, Height, Dots, Rows;
short PrefixCode, SuffixCode, RandomIndex, Val;
short head1[7]={0x4947,0x3846,0x6137,0,0,0xf7,0};
short head2[5]={0,0,0,0,0x800};
LWORD jj;
  int i;

  head1[3]=head2[2]=Width=m1;
  head1[4]=head2[3]=Height=m2;
  fwrite(head1,1,13,fp);
  for(i=0;i<256;i++){
    ByteBuf[0]=ByteBuf[1]=ByteBuf[2]=i;
    fwrite(ByteBuf,1,3,fp);
  }
  fputc(0x2c,fp);
  fwrite(head2,2,5,fp);
  ByteCount = ShiftBits = TempCode = 0;

  Encode = 258;  RunBits = 9;  MaxCodeSize =512;
  for(i = 0; i < 4999; i++) EncodeTable[i] = 0;
  Code = 256;
  FillBlockBuf();
  for(Rows = 0; Rows < Height; Rows++)  {
    jj=(m2-1-Rows)*m1;
    for(i=0;i<m1;i++)ByteBuf[i]=c256[jj++];
    if(Rows == 0) { PrefixCode = ByteBuf[0];  Dots = 1; }
    else Dots = 0;
    while( Dots < Width)  {
      SuffixCode = ByteBuf[Dots++];
      RandomIndex = PrefixCode ^ (SuffixCode << 4);
      if(RandomIndex == 0)  Val = 1;
      else Val = 4999 - RandomIndex;
      while(1)  {
        if(EncodeTable[RandomIndex] == 0)  {
          Code = PrefixCode;
          FillBlockBuf();
          if(Encode == 4096)  {
            Code = 256;
            FillBlockBuf();
            Encode = 258;  RunBits = 9;  MaxCodeSize =512;
            for(i = 0; i < 4999; i++) EncodeTable[i] = 0;
          }
          else  {
            if(Encode == MaxCodeSize)  {
              MaxCodeSize <<= 1;
              RunBits++;
            }
            PrefixTable[RandomIndex] = PrefixCode;
            SuffixTable[RandomIndex] = (unsigned char)SuffixCode;
            EncodeTable[RandomIndex] = Encode++;
          }
          PrefixCode = SuffixCode;
          break;
        }
        if(PrefixTable[RandomIndex] == PrefixCode &&
           SuffixTable[RandomIndex] == SuffixCode)  {
          PrefixCode = EncodeTable[RandomIndex];
          break;
        }
        else  {
          RandomIndex -= Val;
          if(RandomIndex < 0)  RandomIndex += 4999;
        }
      }
    }
  }
  Code = PrefixCode;
  FillBlockBuf();
  Code = 257;
  FillBlockBuf();
  if(ShiftBits > 0 || ByteCount > 0)   {
    BlockBuf[++ByteCount] = TempCode & 0x00FF;
    BlockBuf[0] = (unsigned char)ByteCount;
    fwrite(BlockBuf, 1, ByteCount+1, fp);
    ByteCount = 0;
  }
  fputc(0, fp);  fputc(';', fp);
}
