/*++++++++++++++
.IDENTIFICATION tycho_index.c
.LANGUAGE       C
.AUTHOR         Francois Ochsenbein [CDS]
.ENVIRONMENT    USNO-B1.0 Catalogue
.KEYWORDS       CDS Catalogue Server
.VERSION  1.0   07-Dec-2002: A test -- read home USNO-B1.0
.COMMENTS       Access to USNO-B1.0 catalogue
		This program reads the whole USNO-B1, and 
		keeps the TYCHO Indexes.
---------------*/

#include <usnob1.h>	/* Structure definitions */
#include <stdlib.h>	/* Structure definitions */
#include <stdio.h>	/* Structure definitions */
#include <time.h>	/* Structure definitions */

#define ITEMS(a)        (sizeof(a)/sizeof(a[0]))

/* An item in Tycho index is made of 3 shorts:
      TYC2 = 14 bits
      TYC2 =  4 bits
      USNO = 22 bits
      zone =  8 bits (offset from minizone)
  One TYC1 field contains a first record with
      TYC1     = 16 bits
      Number   = 16 bits
      minizone = 16 bits
*/

typedef struct {
   int order;		/* The date of creation	*/
   int TYC1;
   short minizone;	/* Lowest USNOB zone	*/
   short maxizone;	/* Lowest USNOB zone	*/
   int maxnum;		/* The largest index	*/
   int used;
   unsigned short *index;	/* List of USNO	*/
} infoTYC1;

typedef int (*SORT_FCT)(/* const void *, const void * */) ;

int usnob_options = 0;
static infoTYC1 head[500];
static int nheads;
static int order = 0;

/* The list of TYC1 contents */
static unsigned short *listTYC1[10000];

/*==================================================================
		Create a new TYC1
 *==================================================================*/

static int dif6(short *a, short *b) 
/*++++++++++++++++
.PURPOSE  Sort the table
.RETURNS  Difference
-----------------*/
{
    return(a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
}

int form_TYC1()
/*++++++++++++++++
.PURPOSE  Write the oldest infoTYC1
.RETURNS  The index in head
.REMARKS  May need to write one to file...
-----------------*/
{
  unsigned short *s;
  unsigned short *tab;
  int i,o,m;

    /* Find the oldest */
    for (o=m=9999999, i=0; i<nheads; i++) {
	if (head[i].TYC1 == 0) continue;
	if (head[i].order < o) o=head[i].order, m=i;
    }

    qsort(tab=head[m].index, head[m].used, 6, (SORT_FCT)dif6);

    /* Copy the data to a new piece of memory */
    o = head[m].TYC1;
    s = (unsigned short *)malloc(6*(head[m].used+1)) ;
    listTYC1[o] = s;
    printf("....Saving TYC1=%04d\n", o);
    s[0] = o ;		/* TYC1 */
    s[1] = head[m].used;
    s[2] = head[m].minizone;

    memcpy(s+3, tab, 6*head[m].used) ;

    /* Free the allocated items */
    free(tab);
    memset(&head[m], 0, sizeof(infoTYC1));
    return(m);
}

int new_TYC1(int TYC1)
/*++++++++++++++++
.PURPOSE  Create a new TYC1
.RETURNS  The index in head
.REMARKS  May need to write one to file...
-----------------*/
{
  int m;
    if (nheads >= ITEMS(head)) 		/* Need free space */
	m = form_TYC1();
    else m = nheads++;
    head[m].order = ++order;
    head[m].TYC1  = TYC1;
    head[m].minizone = 1800;
    head[m].maxizone = -1;
    head[m].maxnum = 10000;
    head[m].index = (unsigned short *)malloc(head[m].maxnum*6);
    memset(head[m].index, 0, head[m].maxnum*sizeof(int));
    return(m);
}

int digest(USNOBtyc *rec)
/*++++++++++++++++
.PURPOSE  The routine which gets the records
.RETURNS  -1 = STOP
.REMARKS  Recursivity = simplicity !!
-----------------*/
{
  infoTYC1 *pm;
  unsigned short *s;
  int n,m;
    if ((rec->flags&USNOB_TYC) == 0) return(0);
    for (m=0; (m<nheads) && head[m].TYC1 != rec->TYC1; m++) ;
    if (m >= nheads) m = new_TYC1(rec->TYC1);
    pm = &head[m];
    if (pm->used >= pm->maxnum) {	/* Must realloc */
	n = pm->maxnum;
	pm->maxnum = (rec->TYC2+101)/100; 
	pm->maxnum *= 100;
	printf("....Realloc TYC1=%04d with %d\n", rec->TYC1, pm->maxnum);
	pm->index = realloc(pm->index, pm->maxnum*sizeof(int));
    }
    if (pm->used == 0) pm->minizone = rec->zone;
    if (rec->zone > pm->maxizone) 
	pm->maxizone = rec->zone;
    if ((pm->maxizone-pm->minizone)&(~0xff)) printf(
       "****Too large zone TYC1=%04d Uzone=(%04d-%04d)\n", 
        pm->minizone, pm->maxizone);
    
    s = pm->index + 3*pm->used; pm->used += 1;
    s[0] = rec->TYC2;
    s[1] = (rec->TYC1-pm->minizone)<<8;
    s[1] |= rec->id>>13;
    s[2] = (rec->id<<3) | rec->TYC3;

    return(0);
}

/*==================================================================
		Main Program
 *==================================================================*/

main (argc, argv) int argc; char **argv;
{
  char buf[200];
  long o, *opos;
  unsigned short *s;
  FILE *f;
  int i, m;

    if (argc != 3) goto BadUsage;
    if (strcmp(argv[1], "-o")) goto BadUsage;
    
    f = fopen(argv[2], "w");
    if (!f) { perror(buf); exit(1); }

    /* Create the index in memory ...*/
    usnob_search((long *)0, (long *)0, digest);
    /* Close, and convert the last indexes */
    usnob_close() ;
    while (form_TYC1() >= 0) ;

    /* File out the exact size */
    for (m=ITEMS(listTYC1); !listTYC1[--m]; ); ++m;
    sprintf(buf, "USNOB1.0,indexTYCHO2(6b/rec): TYC1=0000..%04d", m);
    fprintf(f, "%s", buf);
    /* Align on a correct boundary */
    i = strlen(buf);
    while ((i&3)!=3) i++, fputc(' ', f);
    fputc('\n', f);
    fflush(f); 

    /* Write out the list of Offsets */
    o = ftell(f) + (m+1)*sizeof(long);
    opos = (long *)malloc((m+1)*sizeof(long));
    for (i=0; i<m; i++) {
	opos[i] = o;
	s = listTYC1[i];
	if (!s) continue;
	o += 6*s[1];
    }
    opos[i] = o;	/* Last+1 = Size of File */
    fwrite(opos, 4, m+1, f);
    fflush(f); o = ftell(f);

    /* Write the TYC1 indexes */
    for (i=0; i<m; i++) {
	o = ftell(f);
	if (o != opos[i]) printf(
	  "**** %04d: File position=%d, should be %d -- ", i, o, opos[i]);
	else printf(".... %04d: ", i);
	s = listTYC1[i];
	if (s) fwrite(s, 6, 1+s[1], f);
	printf("%4d stars.\n", s ? s[1] : 0);
	fflush(f);
    }
    fclose(f);

    exit(0);

  BadUsage:
    fprintf(stderr, "****Usage: %s -o TYCH-index file\n", "tycho_index");
    exit(1);
}
