/*
	mpg123clr: MPEG Audio Decoder library Common Language Runtime version.

	copyright 2009-2011 by Malcolm Boczek - free software under the terms of the LGPL 2.1
	mpg123clr.dll is a derivative work of libmpg123 - all original mpg123 licensing terms apply.

	All rights to this work freely assigned to the mpg123 project.
*/
/*
	libmpg123: MPEG Audio Decoder library

	copyright 1995-2011 by the mpg123 project - free software under the terms of the LGPL 2.1
	see COPYING and AUTHORS files in distribution or http://mpg123.org

*/
/*
	1.8.1.0	04-Aug-09	Initial release.
	1.9.0.0 16-Sep-09	1.9.0 Update - add enc_from_id3, store_utf8
	1.9.0.0 24-Sep-09	Function names harmonized with libmpg123 (mb)
	1.13.0.0 13-Jan-11	release match - added strlen (mb)
*/

#pragma once

#pragma warning(disable : 4635)
#include "mpg123.h"
#pragma warning(default : 4635)

#include <string>
#include <iostream>

#include <vcclr.h>
using namespace std;
using namespace System;
using namespace System::Runtime::InteropServices;

namespace mpg123clr
{

	// Recommended usage when creating reference type on the managed heap (not using stack semantics 
	//  for reference types...) [see Destructors and Finalizers in Visual C++]
	//
	// A ^ myA = gcnew A;
	// try
	// {
	//     use myA
	// }
	// finally
	// {
	//     delete myA;
	// }


	///<summary>Wrapper for mpg123_string.
	///<para>mpg123str can be used as both (publicly) an instance object and (privately) a reference object.
	/// Construction and Finalizer operations perform differently depending on the instance type...
	///</para> 
	///<para>Instanced: i.e. new mpg123str();
	/// Normal operation of any object. Construction initializes memory and Destruction frees memory.
	///</para>
	///<para>Referenced: i.e. new mpg123str(sb);
	/// Construction and Destruction have no effect on the referenced object, mpg123str objects may be freely
	///  made and deleted without affecting the referenced object.
	///</para>
	///<para>However! 
	///</para>
	///<para>All methods operate on the referenced object (and NOT a copy of the object), the underlying mpg123_string
	///  is directly modified in situ. Therefore the referenced object can be initialized and disposed by
	///  explicitly calling Init() and Free().</para>
	///<para>The length of strings is limited to a 32bit value due to limitations of the CLI marshaler.
	///</para>
	///</summary>
	[StructLayout(LayoutKind::Sequential, CharSet=CharSet::Ansi)]
	public ref struct mpg123str
	{

	public:

		///<summary>text_encoding enumeration.</summary>
		enum class text_encoding
		{
			text_unknown  = mpg123_text_unknown,	/// Unkown encoding... mpg123_id3_encoding can return that on invalid codes.
			text_utf8     = mpg123_text_utf8,		/// UTF-8
			text_latin1   = mpg123_text_latin1,		/// ISO-8859-1. Note that sometimes latin1 in ID3 is abused for totally different encodings.
			text_icy      = mpg123_text_icy,		/// ICY metadata encoding, usually CP-1252 but we take it as UTF-8 if it qualifies as such.
			text_cp1252   = mpg123_text_cp1252,		/// Really CP-1252 without any guessing.
			text_utf16    = mpg123_text_utf16,		/// Some UTF-16 encoding. The last of a set of leading BOMs (byte order mark) rules.
													/// When there is no BOM, big endian ordering is used. Note that UCS-2 qualifies as UTF-8 when
													/// you don't mess with the reserved code points. If you want to decode little endian data
													/// without BOM you need to prepend 0xff 0xfe yourself.
			text_utf16bom = mpg123_text_utf16bom,	/// Just an alias for UTF-16, ID3v2 has this as distinct code.
			text_utf16be  = mpg123_text_utf16be,	/// Another alias for UTF16 from ID3v2. Note, that, because of the mess that is reality,
													/// BOMs are used if encountered. There really is not much distinction between the UTF16 types for mpg123
													/// One exception: Since this is seen in ID3v2 tags, leading null bytes are skipped for all other UTF16
													/// types (we expect a BOM before real data there), not so for utf16be!
			text_max      = mpg123_text_max			/// Placeholder for the maximum encoding value.
		};

		///<summary>id3_enc enumeration.</summary>
		enum class id3_enc
		{
			id3_latin1   = mpg123_id3_latin1,		/// Note: This sometimes can mean anything in practice... 
			id3_utf16bom = mpg123_id3_utf16bom,		/// UTF16, UCS-2 ... it's all the same for practical purposes. 
			id3_utf16be  = mpg123_id3_utf16be,		/// Big-endian UTF-16, BOM see note for mpg123_text_utf16be. 
			id3_utf8     = mpg123_id3_utf8,			/// Our lovely overly ASCII-compatible 8 byte encoding for the world. 
			id3_enc_max  = mpg123_id3_enc_max		/// Placeholder to check valid range of encoding byte. 
		};


	private:
		mpg123_string* sb;
		bool instanced;

	internal:
		///<summary>Reference Constructor. Does nothing to referenced mpg123_string structure.
		///<para>Reference objects may be freely created and deleted without affecting the underlying mpg123_string object.
		/// However, operations on the referenced object do modify the object in-situ (i.e. 'this' is not a 'copy'), and
		/// the referenced object may be explicitly initialized and disposed by calling the appropriate methods. (Init() and Free())</para>
		///<para>Recommended usage: using(mpg123str obj = new mpg123str(sb)){ use obj here }</para>
		///</summary>
		mpg123str(mpg123_string* sb);

		///<summary>Internal Constructor.
		///<para>Only used on empty fields.</para>
		///</summary>
		mpg123str(const char* str);

	protected:
		///<summary>Finalizer.
		///<para>Cleanly handles mpg123_free_string of instanced mpg123_string object.</para>
		///<para>Does not dispose referenced mpg123_string object. Referenced objects may be explicitly disposed by using Free().</para>
		///</summary>
		/// Implementation of CLR Finalize().
		!mpg123str(void);

	public:
		///<summary>Constructor, also initializes underlying mpg123_string structure.
		///<para>Instanced objects automatically dispose of underlying mpg123_string object.</para>
		///<para>Recommended usage: using(mpg123str obj = new mpg123str(sb)){ use obj here }</para>
		///</summary>
		mpg123str(void);

		///<summary>Destructor. Used for final object deletion.
		///<para>Instance objects call the finalizer for clean disposal of internal mpg123_string object.</para>
		///<para>Reference objects may be freely deleted without affecting the underlying mpg123_string object.
		/// However, the referenced object may be explicitly disposed by calling Free()</para>
		///</summary>
		// Implementation of CLR Dispose().
		// ~Destructor and !Finalizer are the prescribed implementation of Dispose() and Finalize().
		// See Destructors and Finalizers in Visual C++
		~mpg123str(void);

		///<summary>Append a C# string to this mpg123str.
		///<para>Returns 0 on error, 1 on success.</para>
		///</summary>
		///<param name="s">String to be appended.</param>
		///<returns>0 on error, 1 on success.</returns>
		int __clrcall mpg123_add_string(String ^ s);

		///<summary>Append a C# substring to this mpg123str.
		///<para>Returns 0 on error, 1 on success.</para>
		///</summary>
		///<param name="s">String to be appended.</param>
		///<param name="from">String offset to copy from.</param>
		///<param name="count">Number of characters to copy. (a null byte is always appended)</param>
		///<returns>0 on error, 1 on success.</returns>
		int __clrcall mpg123_add_substring(String ^ s, int from, int count);

		///<summary>Copy the contents of this string to another.
		///<para>Returns 0 on error, 1 on success.</para>
		///</summary>
		///<param name="to">Where to copy this string to.</param>
		///<returns>0 on error, 1 on success.</returns>
		int __clrcall mpg123_copy_string(mpg123str^ to);

		///<summary>Free-up mempory for an existing mpg123_string.
		///</summary>
		void __clrcall mpg123_free_string(void);

		///<summary>Increase size of a mpg123_string if necessary (it may stay larger).
		///<para>Returns 0 on error, 1 on success.</para>
		///</summary>
		///<param name="newSize">Required size.</param>
		///<returns>0 on error, 1 on success.</returns>
		int __clrcall mpg123_grow_string(int newSize);

		///<summary>Change the size of a mpg123_string.
		///<para>Returns 0 on error, 1 on success.</para>
		///</summary>
		///<param name="newSize">Required size.</param>
		///<returns>0 on error, 1 on success.</returns>
		int __clrcall mpg123_resize_string(int newSize);

		///<summary>Create and allocate memory for a new mpg123_string.
		///</summary>
		void __clrcall mpg123_init_string(void);

		///<summary>Set the contents to a C# string.
		///<para>Returns 0 on error, 1 on success.</para>
		///</summary>
		///<param name="s">String to be applied.</param>
		///<returns>0 on error, 1 on success.</returns>
		int __clrcall mpg123_set_string(String ^ s);

		///<summary>Set the contents to a C# substring.
		///<para>Returns 0 on error, 1 on success.</para>
		///</summary>
		///<param name="s">String to be applied.</param>
		///<param name="from">String offset to copy from.</param>
		///<param name="count">Number of characters to copy. (a null byte is always appended)</param>
		///<returns>0 on error, 1 on success.</returns>
		int __clrcall mpg123_set_substring(String ^ s, int from, int count);

		///<summary>Count characters in a mpg123 string (non-null bytes or UTF-8 characters).
		///<para>Even with the fill property, the character count is not obvious as there could be multiple trailing null bytes.</para>
		///<para>Returns the character count.</para>
		///</summary>
		///<param name="utf8">Flag to tell if the string is in utf8 encoding.</param>
		///<returns>Character count.</returns>
		long long __clrcall mpg123_strlen(bool utf8);

		///<summary>Get the number of used bytes. (including closing zero byte).
		///<para>Property returns the number of used bytes.</para>
		///</summary>
		///<value>The number of used bytes.</value>
		property int Fill{int __clrcall get();}			// property

		///<summary>Get the number of bytes allocated.
		///<para>Property returns the number of bytes allocated.</para>
		///</summary>
		///<value>The number of bytes allocated.</value>
		property int Size{int __clrcall get();}			// property

		///<summary>Get a C# string representation of the mpg123str.
		///<para>Property returns C# string text.</para>
		///</summary>
		///<value>C# string text.</value>
		property String^ Text{String^ __clrcall get();}

// 1.9.0.0 +add

		///<summary>Convert ID3 encoding byte to mpg123 encoding index.
		///<para>Returns the text_encoding enum of the converted value.</para>
		///</summary>
		///<param name="id3_enc_byte">The ID3 encoding byte to be converted.</param>
		///<returns>The text_encoding enum of the converted value.</returns>
		static text_encoding __clrcall mpg123_enc_from_id3(unsigned char id3_enc_byte);

		///<summary>Store text data in string, after converting to UTF-8 from indicated encoding.
		///<para>A prominent error can be that you provided an unknown encoding value, or this build of libmpg123 lacks support for certain encodings (ID3 or ICY stuff missing).
		/// Also, you might want to take a bit of care with preparing the data; for example, strip leading zeroes (I have seen that).</para>
		///<para>CLR - e.g. UnicodeEncoding(true, true) works with utf16be.</para>
		///<para>Returns 0 on error, 1 on success (on error, mpg123_free_string is called on sb).</para>
		///</summary>
		///<param name="enc">Mpg123 text encoding value.</param>
		///<param name="source">Source buffer with plain unsigned bytes.</param>
		///<param name="source_size">Number of bytes in the source buffer.</param>
		///<returns>0 on error, 1 on success (on error, mpg123_free_string is called on sb).</returns>
		int __clrcall mpg123_store_utf8(text_encoding enc, const unsigned char *source, size_t source_size);

// 1.9.0.0 -add

	};

}
