// -*- C++ -*-
// $Id$

// id3lib: a C++ library for creating and manipulating id3v1/v2 tags
// Copyright 1999, 2000  Scott Thomas Haug

/* This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Library General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This library 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 Library General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/* The id3lib authors encourage improvements and optimisations to be sent to
 * the id3lib coordinator.  Please see the README file for details on where to
 * send such submissions.  See the AUTHORS file for a list of people who have
 * contributed to id3lib.  See the ChangeLog file for a list of changes to
 * id3lib.  These files are distributed with id3lib at
 * http://download.sourceforge.net/id3lib/
 */

#ifndef _ID3LIB_FIELD_IMPL_H_
#define _ID3LIB_FIELD_IMPL_H_

#include <id3/field.h>

struct	 ID3_FieldDef;
struct	 ID3_FrameDef;

class ID3_FieldImpl : public ID3_Field
{
	friend class ID3_FrameImpl;
	public:
					~ID3_FieldImpl();

		void			 Clear();

		size_t			 Size() const;
		size_t			 BinSize() const;
		size_t			 GetNumTextItems() const;

		/* Integer field functions
		 */
		ID3_Field		&operator= (uint32 val)			{ this->Set(val); return *this; }
		void			 Set(uint32);
		uint32			 Get() const;

		void			 SetInteger(uint32);
		uint32			 GetInteger() const;

		/* ASCII string field functions
		 */
		ID3_Field		&operator =(const char *s)		{ this->Set(s); return *this; }
		size_t			 Set(const char *data);
		size_t			 Get(char *, size_t) const;
		size_t			 Get(char *, size_t, size_t) const;
		const char		*GetRawText() const;
		size_t			 Add(const char * data);

		dami::String		 GetText() const;
		dami::String		 GetTextItem(size_t) const;
		size_t			 SetText(dami::String);
		size_t			 AddText(dami::String);

		/* Unicode string field functions
		 */
		ID3_Field		&operator= (const unicode_t *s)		{ this->Set(s); return *this; }
		size_t			 Set(const unicode_t*);
		size_t			 Get(unicode_t *buffer, size_t) const;
		size_t			 Get(unicode_t *buffer, size_t, size_t) const;
		size_t			 Add(const unicode_t *);
		const unicode_t		*GetRawUnicodeText() const;

		/* Binary field functions
		 */
		size_t			 Set(const uchar *buf, size_t size);
		size_t			 Set(const char *buf, size_t size)	{ return this->Set(reinterpret_cast<const uchar *>(buf), size); }
		size_t			 Get(uchar *, size_t) const;
		const uchar		*GetRawBinary() const;
		void			 FromFile(const char *);
		void			 ToFile(const char *sInfo) const;

		size_t			 SetBinary(dami::BString);
		dami::BString		 GetBinary() const;

		/* Miscelaneous functions
		 */
		ID3_Field		&operator=(const ID3_Field &);
		bool			 InScope(ID3_V2Spec spec) const		{ return _spec_begin <= spec && spec <= _spec_end; }
		ID3_V2Spec		 MinSpec() const			{ return _spec_begin; }
		ID3_V2Spec		 MaxSpec() const			{ return _spec_end; }

		ID3_FieldID		 GetID() const				{ return _id; }
		ID3_FieldID		 GetLinkedField() const			{ return _linked_field; }
		ID3_FieldType		 GetType() const			{ return _type; }
		bool			 SetEncoding(ID3_TextEnc enc);
		bool			 SetLinkedSize(size_t newfixedsize);
		bool			 HasFixedSize()				{ return _fixed_size != 0; };
		ID3_TextEnc		 GetEncoding() const			{ return _enc; }

		bool			 HasFlag(const flags_t flag) const	{ return (_flags & flag) == flag; }
		bool			 IsEncodable() const			{ return this->HasFlag(ID3FF_ENCODABLE); }

		ID3_Err			 Render(ID3_Writer &) const;
		bool			 Parse(ID3_Reader &);
		bool			 HasChanged() const;
	private:
		size_t			 SetText_i(dami::String);
		size_t			 AddText_i(dami::String);

		/* To prevent public instantiation, the constructor is made private
		 */
					 ID3_FieldImpl();
					 ID3_FieldImpl(const ID3_FieldDef&);

		const ID3_FieldID	 _id;		// the ID of this field
		const ID3_FieldType	 _type;		// what type is this field or should be
		ID3_V2Spec		 _spec_begin;	// spec end
		ID3_V2Spec		 _spec_end;	// spec begin
		const flags_t		 _flags;	// special field flags
		const ID3_FieldID	 _linked_field;	// the ID of field where fixed size comes from
		mutable bool		 _changed;	// field changed since last parse/render?

		dami::BString		 _binary;	// for binary strings
		dami::String		 _text;		// for ascii strings
		uint32			 _integer;	// for numbers

		size_t			 _fixed_size;	// for fixed length fields (0 if not)
		size_t			 _num_items;	// the number of items in the text string
		ID3_TextEnc		 _enc;		// encoding for text fields
	protected:
		void			 RenderInteger(ID3_Writer&) const;
		void			 RenderText(ID3_Writer&) const;
		void			 RenderBinary(ID3_Writer&) const;
		void			 RenderFrames(ID3_Writer&) const;

		bool			 ParseInteger(ID3_Reader&);
		bool			 ParseText(ID3_Reader&);
		bool			 ParseBinary(ID3_Reader&);
		bool			 ParseFrames(ID3_Reader&);
};

/* Ack! Not for public use
 */
ID3_FrameDef	*ID3_FindFrameDef(ID3_FrameID id);
ID3_FrameID	 ID3_FindFrameID(const char *id);

#endif /* _ID3LIB_FIELD_H_ */
