/*
 * © Copyright 1996-2012 ECMWF.
 *
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 * In applying this licence, ECMWF does not waive the privileges and immunities
 * granted to it by virtue of its status as an intergovernmental organisation nor
 * does it submit to any jurisdiction.
 */

/*****************************************************************************

  These routines implemente a C access to COS blocked files

  B.Raoult

  Thu May  9 09:36:24 BST 1991

*****************************************************************************/

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include "cos.h"

#define CRAYBLK		4096

/*****************************************************************************

  This routine checks if the current control word is a valid BCW
  It needs to be improved.

*****************************************************************************/

static int validate_bcw(cf)
COSFILE *cf;
{
	if(M(cf->cw)==0) /* is it a BCW ? */
	{
		if(BN(cf->cw) != cf->block) return FALSE;
		cf->block++;
		return TRUE;
	}
	else return FALSE;
}

/*****************************************************************************

  This routine checks if the current control word is a valid RCW
  It needs to be improved.

*****************************************************************************/

static int validate_rcw(cf)
COSFILE *cf;
{
	if(M(cf->cw)!=0) /* is it a RCW ? */
	{
		return TRUE;
	}
	else return FALSE;
}

/*****************************************************************************

  Reads a control word. Checks if is it a valid block.

*****************************************************************************/

static void read_control_word(cf,blocktype)
COSFILE *cf;
int     blocktype;
{

	int validflag = FALSE;

	if(!fread(&(cf->cw),sizeof(crayword),1,cf->f))
		cf->err = errno?errno:-1;
	else {

		if(blocktype & BCW) validflag = validate_bcw(cf);
		if(blocktype & RCW) validflag = validflag | validate_rcw(cf);

		if(!validflag)
		{
			cf->err = -1;
			fprintf(stderr,"Bad control word file %s\n",cf->fname);
			/* exit(1); it is a fatal error  */
		}
	}

}

/*****************************************************************************

   opening a cos blocked file.

*****************************************************************************/

COSFILE *cos_open(const char *fname)
{
	COSFILE 	*cf = (COSFILE*)malloc(sizeof(COSFILE));

	if(cf==NULL)
	{
		/* perror("Opening file"); */
		return NULL;
	}

	cf->f = fopen(fname,"r");

	cf->buffer = NULL;
	cf->cnt    = CRAYBLK;

	if(cf->f==NULL)
	{
		free(cf);
		perror("Opening file");
		return NULL;
	}

	cf->err   = 0;
	cf->block = 0;
	cf->fname = (char*)strdup(fname);

	read_control_word(cf,BCW);
	if(cf->err)
	{
		cos_close(cf);
		return NULL;
	}

	return cf;
}

/*****************************************************************************

   reading a cos blocked file. On exit buf contains the data,
   len the number of bytes read. The return code is 0 if all Ok,
   -1 if  end of file, anything else otherwise.


   Note: buf must be big enough to hold the data.

*****************************************************************************/

int cos_read(cf,buf,len)
COSFILE *cf;
char *buf;
long *len;
{
	long		offset;

	*len = 0;

	do
	{
		offset = FWI(cf->cw);
		if(offset)
		{
			if(!fread(buf,offset,1,cf->f))
			{
				/* perror("Reading data"); */
				cf->err = errno?errno:-1;
				return cf->err;
			}
			*len += offset;
			buf  += offset;
		}
		read_control_word(cf,BCW | RCW);

	}while(M(cf->cw)==0);

	if(M(cf->cw) == COSEOF) return EOF;
	return 0;

}

/*****************************************************************************
******************************************************************************/

int cos_write(cf,buf,len)
COSFILE *cf;
char *buf;
long len;
{

	if(len==0)return 0;
	if(!cf->buffer)
	{
		cf->cnt    = CRAYBLK;
		cf->buffer = (char*) malloc(CRAYBLK);
		if(!cf->buffer) return -1;
	}




	return 0;
}


/*****************************************************************************

   Close a cos blocked file.

*****************************************************************************/

int cos_close(cf)
COSFILE *cf;
{
	fclose(cf->f);
	if(cf->buffer) free(cf->buffer);
	free(cf->fname);
	free(cf);
	return errno;
}


/****************************************************************************


  FORTRAN interface :

  CALL COSOPEN(ICF,'MYFILE',IERR)
  CALL COSREAD(ICF,IARRAY,ILEN,IERR)
  CALL COSCLOSE(ICF,IERR)

*****************************************************************************/

void COSOPEN(filedesc,fname,e)
char	*fname;
long	*e;
COSFILE **filedesc;
{
	COSFILE *cf ;

	cf = *filedesc = cos_open(fname);
	if (cf == NULL) *e = errno?errno:1;
	else *e = cf->err;
}

void COSCLOSE(filedesc,e)
long	*e;
COSFILE **filedesc;
{
	*e = cos_close(*filedesc);
}

void COSREAD(filedesc,buffer,len,e)
char	*buffer;
long	*e;
long	*len;
COSFILE **filedesc;
{
	*e=cos_read(*filedesc,buffer,len);

}
