using System.Xml; // XmlWriter, XmlWriterSettings
using System.IO.Compression; // BrotliStream, GZipStream, CompressionMode

using static System.Console;
using static System.Environment;
using static System.IO.Path;

PracaZTekstem();
// PracaZXML();
// PracaZKompresja();
// PracaZKompresja(useBrotli: false);

static void PracaZTekstem()
{
   // definiuje plik, z którym będziemy pracować
   string plikTekstowy = Combine(CurrentDirectory, "strumienie.txt");

   // tworzenie pliku tekstowego zwraca klasę pomocniczą
   StreamWriter tekst = File.CreateText(plikTekstowy);

   // przejdź w pętli wszystkie wywołania i wypisz je
   // w pliku, każde w osobnym wierszu
   foreach (string wywolanie in Viper.wywolania)
   {
      tekst.WriteLine(wywolanie);
   }
   tekst.Close(); // zwolnij zasoby

   // wypisz zawartość pliku w konsoli
   WriteLine("{0} ma wielkość {1:N0} bajtów.",
      arg0: plikTekstowy,
      arg1: new FileInfo(plikTekstowy).Length);

   WriteLine(File.ReadAllText(plikTekstowy));
}

static void PracaZXML()
{
   FileStream strumienPlikuXml = null;
   XmlWriter xml = null;

   try
   {
      // definiowanie pliku, do którego będziemy zapisywać
      string plikXml = Combine(CurrentDirectory, "strumienie.xml");

      // utworzenie strumienia do pliku
      strumienPlikuXml = File.Create(plikXml);

      // opakowanie strumienia pliku w obiekt pomocniczy,
      // zapisujący dane XML i automatycznie tworzący wcięcia
      xml = XmlWriter.Create(strumienPlikuXml,
         new XmlWriterSettings { Indent = true });

      // zapisanie deklaracji XML
      xml.WriteStartDocument();

      // zapisanie elementu bazowego
      xml.WriteStartElement("wywolania");

      // wypisywanie w pętli wszystkich wywołań z tablicy
      foreach (string wywolanie in Viper.wywolania)
      {
         xml.WriteElementString("wywolanie", wywolanie);
      }

      // zapisanie zamknięcia elementu bazowego
      xml.WriteEndElement();

      // zamknięcie obiektu pomocniczego i strumienia
      xml.Close();
      strumienPlikuXml.Close();

      // wypisanie zawartości pliku w konsoli
      WriteLine("{0} ma wielkość {1} bajtów.",
         arg0: plikXml,
         arg1: new FileInfo(plikXml).Length);

      WriteLine(File.ReadAllText(plikXml));
   }
   catch (Exception ex)
   {
      // jeżeli ścieżka nie istnieje, to rzucony wyjątek zostanie tutaj złapany
      WriteLine($"{ex.GetType()} says {ex.Message}");
   }
   finally
   {
      if (xml != null)
      {
         xml.Dispose();
         WriteLine("Niezarządzane zasoby obiektu pomocniczego zostały zwolnione.");
         if (strumienPlikuXml != null)
         {
            strumienPlikuXml.Dispose();
            WriteLine("Niezarządzane zasoby strumienia zostały zwolnione.");
         }
      }
   }
}


static void PracaZKompresja(bool uzyjBrotli = true)
{
   string rozszerzenie = uzyjBrotli ? "brotli" : "gzip";

   // kompresowanie wyjściowych danych XML
   string plikISciezkaGzip = Combine(
      CurrentDirectory, $"strumienie.{rozszerzenie}");

   FileStream plik = File.Create(plikISciezkaGzip);

   Stream kompresor;

   if (uzyjBrotli)
   {
      kompresor = new BrotliStream(plik, CompressionMode.Compress);
   }
   else
   {
      kompresor = new GZipStream(plik, CompressionMode.Compress);
   }

   using (kompresor)
   {
      using (XmlWriter xmlGzip = XmlWriter.Create(kompresor))
      {
         xmlGzip.WriteStartDocument();
         xmlGzip.WriteStartElement("wywolania");

         foreach (string wywolanie in Viper.wywolania)
         {
            xmlGzip.WriteElementString("wywolanie", wywolanie);
         }
      }

      // Osobne wywołanie metody WriteEndElement nie jest konieczne,
      // ponieważ zwalnianie obiektu XmlWriter powoduje automatyczne
      // domknięcie wszystkich otwartych elementów xml.

   } // zamyka też podstawowy strumień

   // wypisanie zawartości skompresowanego pliku w konsoli
   WriteLine($"{0} ma wielkość {1} bajtów.",
      0, new FileInfo(plikISciezkaGzip).Length);

   WriteLine("Skompresowana zawartość pliku:");
   WriteLine(File.ReadAllText(plikISciezkaGzip));

   // odczytanie skompresowanego pliku
   WriteLine("Odczytuję skompresowany plik XML:");
   plik = File.Open(plikISciezkaGzip, FileMode.Open);

   Stream dekompresor;
   if (uzyjBrotli)
   {
      dekompresor = new BrotliStream(plik, CompressionMode.Decompress);
   }
   else
   {
      dekompresor = new GZipStream(plik, CompressionMode.Decompress);
   }

   using (dekompresor)
   {
      using (XmlReader reader = XmlReader.Create(dekompresor))
      {
         while (reader.Read())
         {
            // sprawdzenie, czy aktualnie jesteśmy w węźle o nazwie 'wywolanie'
            if ((reader.NodeType == XmlNodeType.Element)
              && (reader.Name == "wywolanie"))
            {
               reader.Read(); // przejście do węzła tekstowego w ramach elementu
               WriteLine($"{reader.Value}"); // odczytanie wartości węzła
            }
         }
      }
   }
}


static class Viper
{
  // definiuje tablicę z wywołaniami pilotów myśliwców Viper
  public static string[] wywolania = new[]
  {
    "Husker", "Starbuck", "Apollo", "Boomer",
    "Bulldog", "Athena", "Helo", "Racetrack"
  };
}
