/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * options.h - cam - Options parsing
 */

#pragma once

#include <ctype.h>
#include <list>
#include <map>
#include <tuple>
#include <vector>

class KeyValueParser;
class OptionValue;
struct Option;

enum OptionArgument {
	ArgumentNone,
	ArgumentRequired,
	ArgumentOptional,
};

enum OptionType {
	OptionNone,
	OptionInteger,
	OptionString,
	OptionKeyValue,
};

template<typename T>
class OptionsBase
{
public:
	OptionsBase() : valid_(false) {}

	bool empty() const;
	bool valid() const;
	bool isSet(const T &opt) const;
	const OptionValue &operator[](const T &opt) const;

	void invalidate();

private:
	friend class KeyValueParser;
	friend class OptionsParser;

	bool parseValue(const T &opt, const Option &option, const char *value);

	std::map<T, OptionValue> values_;
	bool valid_;
};

class KeyValueParser
{
public:
	class Options : public OptionsBase<std::string>
	{
	};

	KeyValueParser();
	virtual ~KeyValueParser();

	bool addOption(const char *name, OptionType type, const char *help,
		       OptionArgument argument = ArgumentNone);

	virtual Options parse(const char *arguments);

private:
	KeyValueParser(const KeyValueParser &) = delete;
	KeyValueParser &operator=(const KeyValueParser &) = delete;

	friend class OptionsParser;
	unsigned int maxOptionLength() const;
	void usage(int indent);

	std::map<std::string, Option> optionsMap_;
};

class OptionsParser
{
public:
	class Options : public OptionsBase<int>
	{
	};

	OptionsParser();
	~OptionsParser();

	bool addOption(int opt, OptionType type, const char *help,
		       const char *name = nullptr,
		       OptionArgument argument = ArgumentNone,
		       const char *argumentName = nullptr, bool array = false,
		       int parent = 0);
	bool addOption(int opt, KeyValueParser *parser, const char *help,
		       const char *name = nullptr, bool array = false,
		       int parent = 0);

	Options parse(int argc, char *argv[]);
	void usage();

private:
	OptionsParser(const OptionsParser &) = delete;
	OptionsParser &operator=(const OptionsParser &) = delete;

	void usageOptions(const std::list<Option> &options, unsigned int indent);

	std::tuple<OptionsParser::Options *, const Option *>
	childOption(const Option *parent, Options *options);
	bool parseValue(const Option &option, const char *arg, Options *options);

	std::list<Option> options_;
	std::map<unsigned int, Option *> optionsMap_;
};

class OptionValue
{
public:
	enum ValueType {
		ValueNone,
		ValueInteger,
		ValueString,
		ValueKeyValue,
		ValueArray,
	};

	OptionValue();
	OptionValue(int value);
	OptionValue(const char *value);
	OptionValue(const std::string &value);
	OptionValue(const KeyValueParser::Options &value);

	void addValue(const OptionValue &value);

	ValueType type() const { return type_; }
	bool empty() const { return type_ == ValueType::ValueNone; }

	operator int() const;
	operator std::string() const;

	int toInteger() const;
	std::string toString() const;
	const KeyValueParser::Options &toKeyValues() const;
	const std::vector<OptionValue> &toArray() const;

	const OptionsParser::Options &children() const;

private:
	ValueType type_;
	int integer_;
	std::string string_;
	KeyValueParser::Options keyValues_;
	std::vector<OptionValue> array_;
	OptionsParser::Options children_;
};
up-circle.svg?h=pobrn/rebase&amp;id=c8cfa6650d6f0f665ead2070e6f2767095331084'>arrow-up-circle.svg</a></div><div class='content'>blob: 044a75d3996e9c640ce0eef01650bab3c1634611 (<a href='/libcamera/vivid.git/plain/src/qcam/assets/feathericons/arrow-up-circle.svg?h=pobrn/rebase&amp;id=c8cfa6650d6f0f665ead2070e6f2767095331084'>plain</a>)
<table summary='blob content' class='blob'>
<tr><td class='linenumbers'><pre><a id='n1' href='#n1'>1</a>
</pre></td>
<td class='lines'><pre><code><span class="hl kwa">&lt;svg</span> <span class="hl kwb">xmlns</span>=<span class="hl str">&quot;http://www.w3.org/2000/svg&quot;</span> <span class="hl kwb">width</span>=<span class="hl str">&quot;24&quot;</span> <span class="hl kwb">height</span>=<span class="hl str">&quot;24&quot;</span> <span class="hl kwb">viewBox</span>=<span class="hl str">&quot;0 0 24 24&quot;</span> <span class="hl kwb">fill</span>=<span class="hl str">&quot;none&quot;</span> <span class="hl kwb">stroke</span>=<span class="hl str">&quot;currentColor&quot;</span> <span class="hl kwb">stroke-width</span>=<span class="hl str">&quot;2&quot;</span> <span class="hl kwb">stroke-linecap</span>=<span class="hl str">&quot;round&quot;</span> <span class="hl kwb">stroke-linejoin</span>=<span class="hl str">&quot;round&quot;</span> <span class="hl kwb">class</span>=<span class="hl str">&quot;feather feather-arrow-up-circle&quot;</span><span class="hl kwa">&gt;&lt;circle</span> <span class="hl kwb">cx</span>=<span class="hl str">&quot;12&quot;</span> <span class="hl kwb">cy</span>=<span class="hl str">&quot;12&quot;</span> <span class="hl kwb">r</span>=<span class="hl str">&quot;10&quot;</span><span class="hl kwa">&gt;&lt;/circle&gt;&lt;polyline</span> <span class="hl kwb">points</span>=<span class="hl str">&quot;16 12 12 8 8 12&quot;</span><span class="hl kwa">&gt;&lt;/polyline&gt;&lt;line</span> <span class="hl kwb">x1</span>=<span class="hl str">&quot;12&quot;</span> <span class="hl kwb">y1</span>=<span class="hl str">&quot;16&quot;</span> <span class="hl kwb">x2</span>=<span class="hl str">&quot;12&quot;</span> <span class="hl kwb">y2</span>=<span class="hl str">&quot;8&quot;</span><span class="hl kwa">&gt;&lt;/line&gt;&lt;/svg&gt;</span>