#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

#include "strutil.h"
#include "nomfits2.h"
#include "datime.h"

/* 
++ 
  Module	Aide au codage des noms Fits (C).
  Lib	LibsUtil
  include	nomfits2.h

	Pour aider a coder et decoder les noms de fichiers Fits Eros 1 et 2.
	Pour verifier la bonne sante d'un fichier Fits.
--
*/
/* ----------------------------------------------------------------- */
/* Reza+farhang, Avril 2007, copie depuis Peida/LibsUtil/datime.h .c */
/*
++
  int DecodeStrgtoJMAHMS(const char* strg, JMA* jma, HMS* hms)
	Decodage d'une chaine sous forme "yyyy-mm-ddThh:mm:ss.s" ou "dd/mm/yy" ou
	"yy/mm/dd" (si yy > 31) ou "yyyy-mm-dd" ou "dd/mm/yyThh:mm:ss.s" en 
	structure JMA et HMS. Si yy < 100 , 1900 est ajoute a l'annee.
	Les argumets "jma" ou "hms" peuvenet etre nuls. 
	Code de retour :
|	Bit 0 ( -> 1) :  Decodage date OK
|	Bit 1 ( -> 2) :  DecodaGE Heure OK

--
*/
/* Nouvelle-Fonction */
int DecodeStrgtoJMAHMS(const char* strg, JMA* jma, HMS* hms)
{
JMA lj;
HMS lh;
int i,j,l,rc;
int tiret;
int T;
char buff[256];

if (jma == NULL) jma = &lj;
if (hms == NULL) hms = &lh;

/* Initialisation de la date et de l'heure */
rc = 0;
hms->Heures = 0;
hms->Minutes = 0;
hms->Secondes = 0.;
jma->Annee = 0;
jma->Mois = 0;
jma->Jour = 0;


l = strlen(strg);
tiret = T = -1;
for(i=0,j=0; i<l; i++) {
  if (j > 254)  break;
  if (strg[i] == ' ') continue;
  buff[j] = strg[i];
  if (buff[j] == '-')  { buff[j] = ' '; tiret = 1;  } /* Date code avec un tiret  */
  if (buff[j] == 'T')  T = j;      /*  Heure code dans la chaine  */
  j++;
  }  

buff[j] ='\0';
if (T >= 0)  { 
  buff[T] ='\0';
  sscanf(buff+T+1,"%d:%d:%lf", &(hms->Heures),&(hms->Minutes),&(hms->Secondes));
  if ( (hms->Heures>=0.) && (hms->Heures<24.)  && 
       (hms->Minutes>=0.) && (hms->Minutes<60.) &&
       (hms->Secondes>=0.) && (hms->Secondes<60.) )  rc += 2;
  }
if (tiret < 0) {  
  sscanf(buff,"%d/%d/%d", &(jma->Jour),&(jma->Mois),&(jma->Annee));
  /* Jour > 31 -> On tente yy/mm/dd  */
  if (jma->Jour>31) sscanf(buff,"%d/%d/%d", &(jma->Annee),&(jma->Mois),&(jma->Jour));
  }
else { /* Date code avec un tiret  */
  sscanf(buff,"%d %d %d", &(jma->Annee),&(jma->Mois),&(jma->Jour));
  }
if (jma->Annee < 100)  jma->Annee += 1900;
if ( (jma->Mois >= 1) && (jma->Mois <= 12) && (jma->Jour >= 1) && (jma->Jour <= 31) ) rc += 1;
return(rc);
}
/* --- fin ajout depuis Peida/LibsUtil/datime.h ----- */


/*====================================================*/
/*
++
unsigned long int decode_zeza(const char* s, int i1, int i2)
	Pour coder (Rc) en entier decimal la chaine de caracteres
	comprise entre `s[i1]' et `s[i2]' interpretee comme
	une suite de Zezas (base 36 : 0 a z).
--
*/
unsigned long int decode_zeza(const char* s, int i1, int i2)
{
  unsigned long int D, ibase = 1;
  int i, i0, sic;

  if( i1 < 0 ) i1 = 0;
  if( i2 > strlen(s) ) i2 = strlen(s);
  if( i2 < i1 ) return(0);
  for(i=i1; i<=i2; i++) if( ! isalnum((int) s[i]) ) break;
  i2 = i-1;
  /* printf("s=%s i1=%d i2=%d\n",s,i1,i2); */
  if( i2 < i1 ) return(0);

  D = 0;
  for(i=i2; i>=i1; i--) {
    sic = (int) s[i];
    if( islower(sic) ) i0 = (int) 'a' - 10;
      else if( isupper(sic) ) i0 = (int) 'A' - 10;
        else i0 = (int) '0';
    D += (unsigned long int) ( sic - i0 ) * ibase;
    /* printf("-- s[%d]=%c sic=%d i0=%d D=%ld\n",i,s[i],sic,i0,D); */
    ibase *= 36;
  }
  return( D );
}

/*====================================================*/
/*
++
char * dec2zeza(unsigned long z, char *s, int n)
	Pour coder en Zeza (base 36) dans la chaine de characteres
	`s' de longeur maximum `n' le nombre entier decimal `z'.
--
*/
char * dec2zeza(unsigned long z, char *s, int n)
{
int r,i,j;
char sz[16];
if(n<2) return NULL;
sz[0] = '0'; sz[1] = '\0';
i=0;
while (z) {
  r = z%36;
  if(r<10) sz[i] = '0'+r; else sz[i] = 'a'+r-10;
  z /= 36;
  i++;
  }
for(j=0;j<i && j<n-1;j++) s[j] = sz[i-j-1];
s[j] = '\0';

return( s );
} 

/*====================================================*/
/*
++
int qSort_fits2(const void *x1,const void *x2)
	Pour trier avec `qsort' un tableau de pointeurs sur
	des chaines de caracteres de noms de fichiers fits Eros2.
	Le tri s'effectue dans l'ordre canonique suivant,
	apres convertion des chaines de caracteres
	interpretees comme des Zezas en entier decimal:
| nom = oo ccc C c s f t dddd sss
|   1- sur la date dddd,
|   2- sur l'objet oo,
|   3- sur le champ ccc,
|   4- sur le numero de camera C
|   5- sur le nom du filtre f,
|   6- sur le type de traitement t,
|   7- sur le numero de sequence sss,
|   8- sur le numero de sous-image s,
|   9- sur le numero de ccd c.
--
*/
int qSort_fits2(const void *x1,const void *x2)
/*  oo ccc c c s f t dddd sss  */
/*  bb hhh a c s i r aaaa eee  */
/*  jj ppp m d i l a tttt qqq  */
/*  */
/*  01 234 5 6 7 8 9 1111 111  */
/*                   0123 456  */
{
unsigned long int i,j;
char *s1, *s2;

s1 = *((char **) x1);
s2 = *((char **) x2);

/* tri par date */
i = decode_zeza(s1,10,13);
j = decode_zeza(s2,10,13);
if(i<j) return(-1); else if(i>j) return(1);

/* puis tri par objet*/
i = decode_zeza(s1,0,1);
j = decode_zeza(s2,0,1);
if(i<j) return(-1); else if(i>j) return(1);

/* puis tri par champ */
i = decode_zeza(s1,2,4);
j = decode_zeza(s2,2,4);
if(i<j) return(-1); else if(i>j) return(1);

/* puis tri par camera */
i = decode_zeza(s1,5,5);
j = decode_zeza(s2,5,5);
if(i<j) return(-1); else if(i>j) return(1);

/* puis tri par filtre */
i = decode_zeza(s1,8,8);
j = decode_zeza(s2,8,8);
if(i<j) return(-1); else if(i>j) return(1);

/* puis tri par traitement */
i = decode_zeza(s1,9,9);
j = decode_zeza(s2,9,9);
if(i<j) return(-1); else if(i>j) return(1);

/* puis tri par sequence */
i = decode_zeza(s1,14,999);
j = decode_zeza(s2,14,999);
if(i<j) return(-1); else if(i>j) return(1);

/* puis tri par sous-image */
i = decode_zeza(s1,7,7);
j = decode_zeza(s2,7,7);
if(i<j) return(-1); else if(i>j) return(1);

/* puis tri par ccd */
i = decode_zeza(s1,6,6);
j = decode_zeza(s2,6,6);
if(i<j) return(-1); else if(i>j) return(1);

/* Ici les noms sont identiques. */
return(0);
}



/* CMV: test des conneries du serveur MG ! */

/* taille du block d'un fichier fits */
#define HEAD_SIZE_CMV 2880
/* nombre maximum permis de blocks pour le header */
#define N_BLK_HEAD_CMV 100

/*
++
int Test_NoCorrupt(const char *flnm)
	Test pour voir si le fichier Fits de nom `flnm' n'est
	pas corrompu.
| Rc =  0 : fichier OK
|      -1 : echec open
|      -2 : le buffer lu ne fait pas 80 caracteres
|      -3 : clef Fits sans signe =
|      -4 : la longueur que l'on deduit de l'entete fits
|           est incompatible avec celle du fichier.
|      -5 : il manque une clef Fits (NAXIS1,NAXIS2,NAXIS, BITPIX)
|           ou la clef BITPIX n'est pas correcte.
--
*/
int Test_NoCorrupt(const char *flnm)
{
int lp=0;
FILE *fip;
char buff[81],*c,*cval;
unsigned short naxis_set, naxis1_set, naxis2_set, bitpix_set, end_set;
int naxis1, naxis2, naxis, bitpix;
long int nbytes_head,nbytes_pix,nbytes_tot,nbytes_mes;
size_t i;

fip = fopen(flnm,"rb");
if( fip == NULL ) {
  if(lp) printf("fopen: impossible de lire %s\n",flnm);
  return(-1);
}

naxis_set = naxis1_set = naxis2_set = bitpix_set = end_set = 0;
naxis1 = naxis2 = naxis = bitpix = 0;
nbytes_head = nbytes_pix = nbytes_tot = nbytes_mes = 0;

for(;;) {

  i = fread(buff,1,80,fip);
  if(lp) printf("fread: rc=%d\n",(int) i);
  if( i != 80 ) return(-2);
  nbytes_head += (long int) i;

  if( nbytes_head / HEAD_SIZE_CMV > N_BLK_HEAD_CMV ) {
    if(lp) printf("Trop de block dans le header %d > %d\n"
            , (int) nbytes_head/HEAD_SIZE_CMV,N_BLK_HEAD_CMV);
    break;
  }

  buff[80] = '\0';
  if(lp) printf("buff=(%s)\n",buff);

  c = buff;
  strip(c,'B',' ');
  if(lp) printf("   c=(%s)\n",c);

  if(strcmp(c,"END")    == 0) {
    if(lp) printf("  END trouve\n");
    end_set = 1;
  } else {
    if( (i=posc(c,'=')) < 0 ) {
      if(lp) printf("  pas de signe =\n");
      return(-3);
    }
    *(c+i)='\0';
    cval = c+i+1;
    strip(c,'B',' ');
    strip(cval,'B',' ');
    if(lp) printf("   c=(%s) cval=(%s)\n",c,cval);
 
    if(strcmp(c,"NAXIS") == 0) {
      sscanf(cval,"%d",&naxis);
      if(lp) printf("  NAXIS trouve\n");
      naxis_set = 1;
    }
    if(strcmp(c,"NAXIS1") == 0) {
      sscanf(cval,"%d",&naxis1);
      if(lp) printf("  NAXIS1 trouve= %d\n",naxis1);
      naxis1_set = 1;
    }
    if(strcmp(c,"NAXIS2") == 0) {
      sscanf(cval,"%d",&naxis2);
      if(lp) printf("  NAXIS2 trouve= %d\n",naxis2);
      naxis2_set = 1;
    }
    if(strcmp(c,"BITPIX") == 0) {
      sscanf(cval,"%d",&bitpix);
      if(lp) printf("  BITPIX trouve= %d\n",bitpix);
      bitpix_set = 1;
    }
  }

  if(end_set) {
    if( naxis1_set && naxis2_set && bitpix_set && bitpix%8==0 ) {

      if( nbytes_head % HEAD_SIZE_CMV == 0 ) nbytes_head = nbytes_head / HEAD_SIZE_CMV;
        else  nbytes_head = nbytes_head / HEAD_SIZE_CMV + 1;
      nbytes_head = nbytes_head*HEAD_SIZE_CMV;

      if( bitpix < 0 ) bitpix *= -1;
      bitpix /= 8;
      nbytes_pix = bitpix * naxis1*naxis2;
      if( nbytes_pix % HEAD_SIZE_CMV == 0 ) nbytes_pix = nbytes_pix / HEAD_SIZE_CMV;
        else  nbytes_pix = nbytes_pix / HEAD_SIZE_CMV + 1;
      nbytes_pix = nbytes_pix*HEAD_SIZE_CMV;

      nbytes_tot = nbytes_head + nbytes_pix;

      if(lp)
        printf("Taille predite: header=%ld core=%ld tot=%ld bytes\n"
              ,nbytes_head,nbytes_pix,nbytes_tot);

      fseek(fip, 0L, SEEK_END);
      nbytes_mes = ftell(fip);
      if(lp) printf("Taille totale mesuree= %ld bytes\n",nbytes_mes);

      fclose(fip);
      if( nbytes_tot == nbytes_mes ) return(0); else return(-4);
    } else break;
  }

}

fclose(fip);
return(-5);
}
#undef HEAD_SIZE_CMV
#undef N_BLK_HEAD_CMV


/*====================================================*/
/*
++
uint_4 DateTstoInt(char *date,char *t)
	Pour coder la date et l'heure 
	dans un entier (TimeInfo).
| 16 bits de poids forts  : nombre de jours ecoules depuis de 1/1/90.
|                  faibles: temps en unites de 2sec.
--
*/
uint_4 DateTstoInt(const char *date,const char *ts)
{
JMA D,D0;
HMS T;
uint_4 Dj,Ts;
int_4 dDj;

/* init pout protection contre date,ts mal definis */
StrgtoJMA("01/01/1990",D);
StrgtoHMS("0:0:0",T);

StrgtoJMA(date,D);
StrgtoJMA("01/01/1990",D0);
dDj = JMAtoJ(D) - JMAtoJ(D0);
if( dDj > 32767 )  dDj = 32767;
if( dDj < -32767 ) dDj = -32767;
if (dDj >= 0) Dj = dDj;
else Dj = 32768-dDj;

StrgtoHMS(ts,T);
Ts = (uint_4)(HMStoSec(T)/2.);
if( Ts > 65535 ) Ts = 65535;

return ((Dj<<16)+Ts);
}

/*====================================================*/
/*
++
uint_4 DateTimetoInt(const char *datetime)
	Pour coder la date et l'heure 
	dans un entier (TimeInfo).
| 16 bits de poids forts  : nombre de jours ecoules depuis de 1/1/90.
|                  faibles: temps en unites de 2sec.
--
*/
uint_4 DateTimetoInt(const char *datetime)
{
JMA D,D0;
HMS T;
uint_4 Dj,Ts;
int_4 dDj;
int rc;

/* init pout protection contre date,ts mal definis */
StrgtoJMA("01/01/1990",D);
StrgtoHMS("0:0:0",T);
rc = DecodeStrgtoJMAHMS(datetime, &D, &T);
if (rc != 3) 
  printf("DateTimetoInt(%s)/Warning - incomplete Date/Time specification (Rc=%d) \n", 
         datetime, rc);
StrgtoJMA("01/01/1990",D0);
dDj = JMAtoJ(D) - JMAtoJ(D0);
if( dDj > 32767 )  dDj = 32767;
if( dDj < -32767 ) dDj = -32767;
if (dDj >= 0) Dj = dDj;
else Dj = 32768-dDj;

Ts = (uint_4)(HMStoSec(T)/2.);
if( Ts > 65535 ) Ts = 65535;

return ((Dj<<16)+Ts);
}

/*====================================================*/
/*
++
void InttoDateTs(uint_4 n,int_4 *date,int_4 *t)
	Pour decoder la date et l'heure 
	depuis un entier (TimeInfo).
| n   : entier code.
| date: nombre de jours ecoules depuis de 1/1/90.
| t   : heure en secondes (precision 2s).
--
*/
void InttoDateTs(uint_4 n,int_4 *date,int_4 *ts)
{
uint_4 dj, dt;
dt = 2 * (n & 0xFFFF);
dj = (n>>16) & 0xFFFF;
if (dj > 32767) dj = 32768 - dj;
*ts = dt;
*date = dj;
}
