/**********************************************************************
 *
 * Unimarc.h
 * Copyright (C) 2003  UNESCO
 *
 * A component of the Greenstone digital library software
 * from the New Zealand Digital Library Project at the
 * University of Waikato, New Zealand.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *********************************************************************/


#ifndef MARC_RECORD
#define MARC_RECORD

#define SUBFDELIM '\037'   // %
#define FIELDTERM '\036'   // $
#define RECTERM   '\035'   // # sharp

#define MARC_LEADER_LEN 24
#define MARC_DIRENT_LEN 12

#define MARC_FMT_BRIEF 0
#define MARC_FMT_FULL 1

//---------------------
// UNIMARC Record Label
//---------------------
struct  MarcLeader
{
	char	lreclen_[5];	/* logical record length */
	char	status_;		/* record status_ */
	char	type_;			/* type_ of record */
	char	bibLevel_;	    /* bibliographic level */
	char	ctrlType_;	    /* type_ of control */
	char	undPos_;		/* undefined character position */
	char	indCount_;	    /* indicator count */
	char	scd_;			/* subfield code count */
	char	base_[5];		/* base_ address of data */
	char	encLevel_;	    /* encoding level */
	char	dcf_;			/* descriptive cataloging form */
	char	lrr_;			/* linked record requirement */
	char	llof_;			/* length of the length-of-field portion */
	char	lscp_;			/* length of starting-character-position portion */
	char	lidp_;			/* length of implementation-defined portion */
	char	uep_;			/* undefined entry map character position */

	MarcLeader()
	{
		lreclen_[0]=' ';
		lreclen_[1]=' ';
		lreclen_[2]=' ';
		lreclen_[3]=' ';
		lreclen_[4]=' ';
		status_   = '0';     // New record
        type_     = '0';     // Language materials, printed
	    bibLevel_ = '0';	     // Monographic
	    ctrlType_ = '0';     // Hierarchical relationship undefined
	    undPos_   = '0';     // Undefined, contains a blank
	    indCount_ = '0';     // Invariably 2 in UNIMARC
	    scd_      = '0';     // Invariably 2 in UNIMARC
	    base_[0]  = ' ';     // Base_ address of data
		base_[1]  = ' ';
		base_[2]  = ' ';
		base_[3]  = ' ';
		base_[4]  = ' ';
	    encLevel_ = '0';     // (Blank) full level
	    dcf_      = '0';     // (Blank) record is in full ISBD form
	    lrr_      = '0';     // Undefined, contains a blank
	    llof_     = '4';     // Length of the length-of-field portion
	    lscp_     = '5';     // Length of starting-character-position portion 
	    lidp_     = '0';     // Length of implementation-defined portion
	    uep_      = '0';     // Undefined, contains a blank
	}

   friend std::ostream& operator<<(std::ostream& s, const MarcLeader& leader);
   friend std::istream& operator>>(std::istream& s, MarcLeader& leader);
};

//----------------
// Directory entry
//----------------
struct DirectoryEntry
{
	char	tag_[3];		/* tag */
	char	len_[4];		/* field length */
	char	scp_[5];		/* starting character position */
   friend std::ostream& operator<<(std::ostream& s, const DirectoryEntry& de);
   friend std::istream& operator>>(std::istream& s, DirectoryEntry& leader);
};
inline std::istream& operator>>(std::istream& s, DirectoryEntry& de)
{
	s.read(de.tag_, 3);
	s.read(de.len_, 4);
	s.read(de.scp_, 5);
	return s;
}
inline std::ostream& operator<<(std::ostream& s, const DirectoryEntry& de)
{
	s.write(de.tag_, 3);
	s.write(de.len_, 4);
	s.write(de.scp_, 5);
	return s;
}



//------------------
// Subfield item 
//------------------
struct MarcField
{
	int			len_;
	char*       data_;
};

//-------------------
// Directory entry
//-------------------
struct MarcDirectoryEntry
{
	char*                  tag_;
	std::vector<MarcField> field_;
};


//---------------------------
// UNIMARC record structure 
//---------------------------

class MarcRecord
{
protected:
	MarcLeader      leader_;
	char*           data_;
	int			    length_;
	int				dirCount_;
	int				encapsulated_;
	std::vector<MarcDirectoryEntry>   directory_;
	
    int ParseMarcRecord();
    int AddSubFields(MarcDirectoryEntry& d, char* b);
public:
    MarcRecord(char* data, int length, int copyData);
    ~MarcRecord();
    void PrintDetailed(FILE* fp);
    void Get(char* buf,int maxlen,int format);
    int  GetSubField(char* tag, char subtag, char* buf, int maxlen);
    int  GetField(char* tag, char* buf, int maxlen);
    int  GetSubFields(char* tag, char subtag, char* buf, int maxlen);

    int  HasField(char* tag);
    int  HasSubField(char* tag, char subtag);

    void Format(char* buf, int maxlen, int format);
    int  RecordLength();
    int  PrettyFormat(char* format, char* buf, int maxlen);

    void Dump ();
};
#endif
