//
// Config file parser
//
// Copyright 2026, Jakob Østergaard Hegelund <joe@unthought.net>
// -----------------------------------------------------------------------
// This file is part of FanMan.
//
// FanMan is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// FanMan is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with FanMan. If not, see <https://www.gnu.org/licenses/>.
// -----------------------------------------------------------------------
//
// file = line*
// line = empty | comment | decl (str | real)
// empty = /^ *$/
// comment = /^#/
// decl = /^[a-z0-9_-]+ *= */
// str = quoted string
// real = double precision real
//

#ifndef _CFGPARSER_HH
#define _CFGPARSER_HH

#include <string>
#include <string_view>
#include <initializer_list>
#include <vector>
#include <iostream>

class CfgParameterB {
public:
  // Parse line if possible; if line is a declaration that matches our
  // name, we will update our value. If line is malformed we throw.
  // Returns true if line was "consumed" (meaning, was blank, was a
  // comment, or was a declaration that matched our name)
  virtual bool parse(std::string_view line) = 0;

protected:
  CfgParameterB(std::string name) : m_name(std::move(name)) {}
  const std::string m_name;
};

// Declare configuration parameters as variables for easy access
template<typename P>
class CfgParameter : public CfgParameterB {
public:
  CfgParameter(std::string name, const P &default_value)
    : CfgParameterB(name), m_value(default_value) { }

  // Our line parser - see base for comment
  bool parse(std::string_view line) override;

  // Accessors; return value
  operator const P&() const { return m_value; }
  const P& operator=(const P &v) { m_value = v; return m_value; }
private:
  P m_value;
};

// Declare a config file - allow for parsing and re-parsing
class CfgParser {
public:
  CfgParser(std::string filename,
            std::vector<CfgParameterB*> parms)
    : m_filename(filename), m_parms(parms) { }

  // Load or re-load config; throw on error
  void reload();

  // Allow ignoring unknown parameters
  void ignore_unknown_parameters();

private:
  // Our backing file
  const std::string m_filename;
  // Our parameters
  std::vector<CfgParameterB*> m_parms;
  // Ignore unknown?
  bool m_ignore_unknown_parameters = false;
};



#endif
