/*

	GRP.C

   Oliver Kraus
   kraus@lrs.e-technik.uni-erlangen.de

*/


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "grp.h"

int map_name_compare(char *n1, char *n2);


/* global vars */

char *grp_id_str = "KenSilverman";
#define GRP_ID_SIZE 12

grp_type qsort_grp;

int grp_dir_cmp( void *elem1, void *elem2 )
{
   int i1 = *(int *)(elem1);
   int i2 = *(int *)(elem2);
   return map_name_compare(qsort_grp->dir_list_ptr[i1].label,
                           qsort_grp->dir_list_ptr[i2].label);
}

int is_grp_file(char *name)
{
	FILE *fp;
	char s[GRP_ID_SIZE];

	fp = fopen(name, "rb");
	if ( fp == NULL )
		return 0;

	if ( fread(s, GRP_ID_SIZE, 1, fp) != 1 )
	{
		fclose(fp);
		return 0;
	}
	if ( strncmp(s, grp_id_str, GRP_ID_SIZE) != 0 )
	{
		fclose(fp);
		return 0;
	}
	fclose(fp);
	return 1;
}

grp_type grp_Open(char *fname)
{
	grp_type grp;
	grp = (grp_type)malloc(sizeof(grp_struct));
	if ( grp != NULL )
	{
		grp->fname = (char *)malloc(strlen(fname)+1);
		if ( grp->fname != NULL )
		{
			strcpy(grp->fname, fname);
			grp->fp = fopen(fname, "rb");
			if ( grp->fp != NULL )
			{
				grp->is_id_ok = 0;
				grp->dir_list_len = 0L;
				grp->dir_list_ptr = NULL;
            grp->dir_list_idx = NULL;
				grp->is_dir_ok = 0;
				return grp;
			}
			free(grp->fname);
		}
		free(grp);
	}
	return NULL;
}

void grp_Close(grp_type grp)
{
	if ( grp != NULL )
	{
		if ( grp->dir_list_ptr != NULL )
			free(grp->dir_list_ptr);
      if ( grp->dir_list_idx != NULL )
         free(grp->dir_list_idx);
		fclose(grp->fp);
		free(grp->fname);
		free(grp);
	}
}

int grp_SeekFile(grp_type grp, long n)
{
   long pos, i;
   if ( n >= grp->dir_list_len )
      return 0;
   pos = GRP_ID_SIZE;
   pos += sizeof(long);
   pos += (long)sizeof(grp_dir_struct)*grp->dir_list_len;
   for( i = 0; i < n; i++ )
   {
      pos += grp->dir_list_ptr[i].size;
   }
   if ( fseek(grp->fp, pos, SEEK_SET) != 0 )
   {
      perror("seek within grp file");
		return 0;
   }
   return 1;
}

int grp_LoadId(grp_type grp)
{
	char *task = "grp file identifier";
	char s[GRP_ID_SIZE];

	if ( fseek(grp->fp, 0L, SEEK_SET) != 0 )
	{
		perror(task);
		return 0;
	}
	if ( fread(s, GRP_ID_SIZE, 1, grp->fp) != 1 )
	{
		perror(task);
		return 0;
	}
	if ( strncmp(s, grp_id_str, GRP_ID_SIZE) != 0 )
	{
		fprintf(stderr, "%s: wrong identifier in file %s\n", task, grp->fname);
		return 0;
	}
	grp->is_id_ok = 1;
	return 1;
}

int grp_LoadDirectory(grp_type grp)
{
	char *task = "grp directory";

	if ( grp->is_id_ok == 0 )
		if ( grp_LoadId(grp) == 0 )
			return 0;

	if ( fseek(grp->fp, GRP_ID_SIZE, SEEK_SET) != 0 )
	{
		perror(task);
		return 0;
	}

	if (fread(&(grp->dir_list_len), sizeof (long), 1, grp->fp) != 1)
	{
		perror(task);
		return 0;
	}

	if ( grp->dir_list_ptr != NULL )
		free(grp->dir_list_ptr);
	grp->dir_list_ptr =
		(grp_dir_struct *)malloc(grp->dir_list_len*sizeof(grp_dir_struct));
	if ( grp->dir_list_ptr == NULL )
	{
		fprintf(stderr, "%s: out of memory for directory of %s\n", task, grp->fname);
		return 0;
   }
   grp->dir_list_idx =
      (long *)malloc(grp->dir_list_len*sizeof(long));
   if ( grp->dir_list_idx == NULL )
	{
      fprintf(stderr, "%s: out of memory for directory-index of %s\n", task, grp->fname);
		return 0;
   }

	{
		long i;
		for ( i = 0; i < grp->dir_list_len; i++ )
      {
         grp->dir_list_idx[i] = i;
			if (fread(grp->dir_list_ptr+i, sizeof(grp_dir_struct), 1, grp->fp) != 1)
			{
				perror(task);
				return 0;
			}
		}
   }

   qsort_grp = grp;
   qsort( grp->dir_list_idx, grp->dir_list_len, sizeof(long),
            grp_dir_cmp);

	grp->is_dir_ok = 1;

	return 1;
}
