// Dawid Seredyński    5. semestr, ECY
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

using namespace std;

void test_callback (ios_base::event ev, ios_base& iosobj, int index)
{
  switch (ev)
  {
    case ios_base::copyfmt_event:
      cout << "copyfmt_event\n"; break;
    case ios_base::imbue_event:
      cout << "imbue_event\n"; break;
    case ios_base::erase_event:
		if(&iosobj!=(ios_base*)&cout)
			cout << "erase_event\n";
		break;
  }
}

int main()
{
	stringbuf sb,sb2;

	// utworzenie strumieni i powiązanie ich z buforami typu stringbuf
	ostream os(&sb);				// utworzenie strumienia przypisanego
							// do bufora pliku
	ostream os2(&sb2);				// utworzenie strumienia przypisanego
							// do bufora pliku

	// ustawieni funkcji wywoływanej przy niektórych zdarzeniach
	os.register_callback (test_callback,0);

	// powiązanie dwóch strumieni
	// każda operacja i/o na strumieniu os będzie wpisywana do os2
	os.tie(&os2);
	os << "Test sentence\n";

	// os będzie pisać do bufora cout
	os.rdbuf(cout.rdbuf());
	os<<"uzycie innego strumienia do wypisania tekstu na konsole"<<endl;
	// os będzie pisać do bufora sb
	os.rdbuf(&sb);

	// metoda zapisująca napis jako tablicę bajtów
	os.write ("This is an apple",16);
	os.flush();
	// odczytanie pozycji wskaźnika zapisu
	int pos=os.tellp();
	// przesunięcie wskaźnika zapisu o 7 bajtów do tyłu
	os.seekp (pos-7);
	os.write (" sam",4);
	// przesunięcie wskaźnika na koniec pliku
	os.seekp(0,ios_base::end);
	// zapis pojedynczego znaku
	os.put('\n');
	// zapis formatowanego tekstu
	os<<"test"<<endl;
	// wyświetlenie wartości znacznika końca stumienia - w przypadku
	// strumienia wyjściowego, zawsze równego 0
	cout<<os.eof()<<endl;

	// ustawienie stałej, określonej szerokości pola przy formatowaniu liczb
	os.width(10);
	// ustawienie wypełnienia pola liczy
	os.fill('#');

	// skopiowanie stylu formatowania liczb do strumienia cout
	cout.copyfmt(os);

	// dla obu strumieni liczba zostanie sformatowana w ten sam sposób
	cout<<25<<endl;
	os<<25<<endl;

	// wyjustowanie do lewej
	cout.setf ( ios::left, ios::adjustfield );
	// ustawienie szerokości pola liczby
	cout.width(10);
	// ustawienie wypełnienia niezapisanych znaków pola liczby
	cout.fill('#');
	cout<<25<<endl;
	cout<<25<<endl;
	cout.flush();

	cout.width(0);
	// liczby formatowane do systemu szesnastkowego
	cout.setf ( ios::hex, ios::basefield );
	// wyswietl 0x przed liczbą szesnastkową
	cout.setf ( ios::showbase );
	cout << 100 << endl;
	// nie wyświetlaj 0x przed liczbą szesnastkową
	cout.setf ( (std::_Ios_Fmtflags)0,ios::showbase );
	cout << 100 << endl;
	// liczby formatowane do systemu dziesiętnego
	cout.setf ( ios::dec, ios::basefield );
	cout<<"flags: "<<cout.flags()<<endl;
	cout << 100 << endl;

	// ustawienie sposobu formatowania liczb w zależności od lokalnych ustawień
	{
		locale mylocale("");
		cout.imbue( mylocale );
		cout<<3.1415<<endl;
	}
	{
		locale mylocale("C");
		cout.imbue( mylocale );
		cout<<3.1415<<endl;
	}

	// zmiana dokładności formatowanych liczb zmiennopozycyjnych
	// dla notacji (default) określa całkowitą liczbę wypisanych cyfr
	cout.precision(3);
	cout<<13.1415<<endl;

	// zmiana dokładności formatowanych liczb zmiennopozycyjnych
	// dla notacji (fixed) określa liczbę wypisanych cyfr po przecinku
	cout.setf(ios::fixed,ios::floatfield);
	cout.precision(3);
	cout<<13.1415<<endl;

	// FUNKCJE OPERUJĄCE NA ZNACZNIKACH BŁĘDÓW
	// początkowe ustawienie znaczników błędów
	os.clear();
	cout<<"clear()"<<endl;
	// sprawdzenie, czy poprzednia operacja zakończyła się poważnym błędem
	cout<<"bad(): "<<os.bad()<<endl;
	// sprawdzenie, czy poprzednia operacja nie powiodła się
	cout<<"fail(): "<<os.fail()<<endl;
	// sprawdzenie, czy strumień jest ok.
	cout<<"good(): "<<os.good()<<endl;
	// odczytanie zmiennej stanu, zawierającej znaczniki błędów
	cout<<"rdstate(): "<<os.rdstate()<<endl;

	cout<<endl<<"wlaczenie generowania wyjatkow..."<<endl;
	// włączenie generowania wyjątków przez strumień
	os.exceptions(ios::eofbit | ios::failbit | ios::badbit);
	try
	{
		// cofnięcie wskaźnika pozycji w pliku do niedozwolonej wartości
		cout<<"seek(-1000)"<<endl;
		os.seekp(-1000);
	}
	catch(ifstream::failure e)
	{
		cout<<"zlapano wyjatek: "<<e.what()<<endl;
	}

	cout<<endl<<"wylaczenie generowania wyjatkow..."<<endl;
	// wyłączenie generowania wyjątków przez strumień
	os.exceptions(ios::goodbit);
	// cofnięcie wskaźnika pozycji w pliku do niedozwolonej wartości
	cout<<"seek(-1000)"<<endl;
	os.seekp(-1000);
	// sprawdzenie, czy poprzednia operacja zakończyła się poważnym błędem
	cout<<"bad(): "<<os.bad()<<endl;
	// sprawdzenie, czy poprzednia operacja nie powiodła się
	cout<<"fail(): "<<os.fail()<<endl;
	// działanie operatora ! jest takie samo jak metody fail()
	cout<<"operator!: "<<!os<<endl;
	// sprawdzenie, czy strumień jest ok.
	cout<<"good(): "<<os.good()<<endl;
	// działanie operatora (void*) jest podobne do metody good()
	cout<<"operator (void*): "<<(void*)os<<endl;
	// odczytanie zmiennej stanu, zawierającej znaczniki błędów
	cout<<"rdstate(): "<<os.rdstate()<<endl;

	// 'wyczyszczenie' znaczników
	os.clear();
	// ustawienie niedozwolonego bufora (NULL)
	os.rdbuf(0);
	// zapis danych
	os<<"A";
	cout<<endl<<"wykonanie niedozwolonej operacji - zapis do nieistniejacego bufora"<<endl;
	// sprawdzenie, czy poprzednia operacja zakończyła się poważnym błędem
	cout<<"bad(): "<<os.bad()<<endl;
	// sprawdzenie, czy poprzednia operacja nie powiodła się
	cout<<"fail(): "<<os.fail()<<endl;
	// sprawdzenie, czy strumień jest ok.
	cout<<"good(): "<<os.good()<<endl;
	// odczytanie zmiennej stanu, zawierającej znaczniki błędów
	cout<<"rdstate(): "<<os.rdstate()<<endl;

	return 0;
}
