#include "Tutorial.h"

void Stream()
{
	/// .Streams basics

	/// U++ stream working with files is `FileStream`. It has 3 derived classes, `FileIn`,
	/// `FileOut` and `FileAppend`, for the most common uses.

	FileIn in(GetDataFile("test.txt"));
	if(!in) {
		LOG("Failed to open the file");
		return;
	}
	
	/// The most basic operations of streams are `Put` and `Get`. `Get` works in the same ways
	/// as good old C getc - it returns negative number on eof or error:

	String h;
	int c;
	while((c = in.Get()) >= 0)
		h.Cat(c);
	DUMP(h);

	/// U++ streams provide no formatting capabilities (that is deferred to text utilities),
	/// but they have some unique features. U++ does not distinguish between 'text' and
	/// 'binary' mode streams, methods are well suited to work with both in common mode.
	
	/// `GetLine` returns `String` of single line read (lines separator being '\n', '\r' is
	/// ignored):

	in.Seek(0);
	while(!in.IsEof())
		DUMP(in.GetLine());
	
	/// `Peek` can be used to look at the next character without actually moving on to the next
	/// one:
	
	in.Seek(0);
	DDUMP((char)in.Peek());
	DDUMP(in.GetLine());

	/// `Get` method reads at most specified number of bytes from the stream and returns them as
	/// `String`:

	in.Seek(0);
	DUMP(in.Get(10));
	
	/// If there is not enough characters in the Stream as required by Get, everything till EOF
	/// is returned:
	
	in.Seek(0);
	DUMP(in.Get(999999).GetCount());
	
	/// In contrast, `GetAll` method fails when there is not enough characters in the Stream and
	/// returns Void `String` if Stream is not in `LoadThrowing` mode:

	in.Seek(0);
	h = in.GetAll(100);
	DUMP(h.GetCount());
	
	///
	
	h = in.GetAll(999999);
	DUMP(h.IsVoid());
	
	/// In `LoadThrowing` mode, `Stream` throws `LoadingError` exception when there is problem with
	/// input `Stream`:
	
	in.LoadThrowing();
	try {
		in.GetAll(999999);
	}
	catch(LoadingError) {
		LOG("Loading error");
	}
	
	/// Template variant of `Stream::operator<<` is using `AsString` to convert data to text:

	String fn = GetHomeDirFile("test.txt");
	FileOut out(fn);
	if(!out) {
		LOG("Failed to open the file");
		return;
	}
	out << "Some number " << 321 << " and Point " << Point(1, 2);
	out.Close();
	
	/// When writing to the `Stream`, the good way to check for errors is to write all data,
	/// close the stream and then check for `IsError`:
	
	if(out.IsError()) { // check whether file was properly written
		LOG("Error");
		return;
	}
	DUMP(LoadFile(fn));
	
	/// `FileAppend` can be used to append data to the file:
	
	FileAppend out2(fn);
	out2 << "\nSomething more";
	out2.Close();
	DUMP(LoadFile(fn));
	
	/// Important and often used type of `Stream` is `StringStream` which works with `String` as
	/// input/output.
	
	/// `Stream` also provides methods to store/load primitive types, in both
	/// little-endian and big-endian modes:
	
	StringStream ss;
	ss.Put32le(0x12345678);
	ss.Put32be(0x12345678);
	DUMPHEX(ss.GetResult());

	///

	StringStream ss2(ss.GetResult());
	DUMPHEX(ss2.Get32le());
	DUMPHEX(ss2.Get32be());

	///
}
