#pragma once

#include <string>
#include <map>
#include <fstream>
#include <optional>

namespace Aftr
{

   class AftrConfigurationParser
   {
   public:
      //opt in to std::is_transparent so key type need only be able to be compared by the comparator (ie, Key could be std::string and can compare against char* w/o making a copy)
      //https://stackoverflow.com/questions/20317413/what-are-transparent-comparators
      using map_type = std::map<std::string, std::string, std::less<> >; //same as return from parseFile without the optional
      using opt_map = std::optional< map_type >; //same as return from parseFile
      
      AftrConfigurationParser() = delete;
      
      static opt_map parseFile( const std::string& filename );
      static std::string toString( map_type const& m );
      static bool toFile( map_type const& m, const std::string& fileName, bool overwriteExisting = true );
   private:
      /**
   
      If a line begins with an '#', the pair <"",""> is not returned.

      If a line contains now '=', the pair <"",""> is returned.

      Otherwise the pair will contain <everything before first equal sign, everything after first equal sign>.

      */
      static std::pair<std::string, std::string> parseLine(std::ifstream& xin);
   };

   //Pairs a filename containing a sequence of key=value lines with a std::map (specifically, the AftrConfigurationParser::map_type).
   class AftrConfigurationWithFileName
   {
   public:
      //Attempts to load an existing configuration key=value pairs from filename
      static std::optional<AftrConfigurationWithFileName> fromFile( std::string_view const filename );
      //Creates an empty map that will overwrite any existing file at filename
      static AftrConfigurationWithFileName make_empty_map_at_file( std::string_view const filename );
      /// writes current map contents to the same file from which this instance was ::New()'d
      bool toFile( bool overwriteExisting = true );
      /// Returns the underlying AftrConfigurationParser::map_type created from filename
      AftrConfigurationParser::map_type& m() noexcept { return this->map_; }
      AftrConfigurationParser::map_type const& m() const noexcept { return this->map_; }
      /// Accesses a read-only
      std::string_view getFilename() const noexcept { return std::string_view(filename); }
   private:
      AftrConfigurationParser::map_type map_; //actual map
      std::string filename; //always only associated w/ the filename with which this instance was created

      explicit AftrConfigurationWithFileName( AftrConfigurationParser::map_type&& map, std::string&& filename );
   };

}

