#ifndef CONNECTION_H
#define CONNECTION_H

#include <QByteArray>
#include <QDataStream>
#include <QMetaType>
#include <QUuid>
#include <QVector>
#include <map>
#include <vector>
#include <string>


enum class SslMode {
	disable=0,
	allow=1,
	prefer=2,
	require=3,
	verify_ca=4,
	verify_full=5
};

enum class PasswordState {
	NotNeeded, ///< the Connection doesn't require a password
	NotStored, ///< password needed but we do not know it
	SavedPasswordManager, ///< Saved in the password manager
};

class QProcessEnvironment;
class QString;

class ConnectionConfig;

/** Base class for ConnectionGroup and ConnectionConfig
 * to enable the use of RTTI in the tree model class.
 */
class ConnectionNode {
public:
	virtual ~ConnectionNode() = default;
};

class ConnectionGroup: public ConnectionNode {
public:
	int conngroup_id;
	QString name;

	using Connections = QVector<std::shared_ptr<ConnectionConfig>>;
	const Connections& connections() const { return m_connections; }
    Connections& connections() { return m_connections; }

	void erase(int idx, int count = 1);
	/// Adds cc to the group and returns the index within the group.
	int add(std::shared_ptr<ConnectionConfig> cc);
	void update(int idx, const ConnectionConfig &cc);

	bool operator==(const ConnectionGroup &rhs) const {
		return conngroup_id == rhs.conngroup_id
				&& name == rhs.name;
	}
private:
	Connections m_connections;
};

class ConnectionConfig: public ConnectionNode {
public:
	ConnectionConfig(); // Default object containing invalid uuid

	const ConnectionGroup* parent() const;
	void setParent(ConnectionGroup *grp);

	void setUuid(const QUuid &uuid);
	const QUuid &uuid() const;

	void setName(const QString& desc);
	const QString& name() const;

	void setHost(const QString& host);
    QString host() const;

	void setHostAddr(const QString& v);
    QString hostAddr() const;

	void setPort(unsigned short port);
	unsigned short port() const;

	void setUser(const QString& v);
    QString user() const;

	void setPassword(const QString& v);
    QString password() const;

	void setDbname(const QString& v);
    QString dbname() const;

	void setSslMode(SslMode m);
	SslMode sslMode() const;

    void setSslCert(const QString& v);
    QString sslCert() const;

    void setSslKey(const QString& v);
    QString sslKey() const;

    void setSslRootCert(const QString& v);
    QString sslRootCert() const;

    void setSslCrl(const QString& v);
    QString sslCrl() const;

//	const char * const * getKeywords() const;
//	const char * const * getValues() const;

    // bool isSameDatabase(const ConnectionConfig &rhs) const;

	void writeToEnvironment(QProcessEnvironment &env) const;

	bool dirty() const;
	void clean();

	bool operator==(QUuid id) const { return m_uuid == id; }

	QString makeLongDescription() const;
    const QByteArray& encodedPassword() const;
	void setEncodedPassword(const QByteArray &encodedPassword);

//	void write(QDataStream &out) const;
//	void read(QDataStream &in);

	/** Escapes a value for inclusion in a keyword value connection string.
	 *
	 * Unlikely it will be everneeded outside this class except for unit testing :)
	 */
	static QString escapeConnectionStringValue(const QString &value);
	QString connectionString() const;

    void setParameter(const QString &name, const QString &value);
    QString getParameter(const QString &name) const;
    const std::unordered_map<QString, QString>& getParameters() const
    {
        return m_parameters;
    }
private:
	QUuid m_uuid;
    QString m_name;
    // QString m_host;
    // QString m_hostaddr;
    // uint16_t m_port = 5432;

    // QString m_user;
    // QString m_password; ///< Note this is not saved in the DB only the m_encodedPassword is safed.
    // QString m_dbname;

    // SslMode m_sslMode = SslMode::prefer;
    // QString m_sslCert;
    // QString m_sslKey;
    // QString m_sslRootCert;
    // QString m_sslCrl;

    // QString m_applicationName;
	QByteArray m_encodedPassword;

    std::unordered_map<QString, QString> m_parameters;

	bool m_dirty = false;
	ConnectionGroup* m_group = nullptr;


	static void strToEnv(QProcessEnvironment &env, const QString &var, const QString &val);

//	static std::vector<const char*> s_keywords;
//	mutable std::vector<const char*> m_values;


};

Q_DECLARE_METATYPE(ConnectionConfig)

//QDataStream &operator<<(QDataStream &out, const ConnectionConfig &cc);

//QDataStream &operator>>(QDataStream &in, ConnectionConfig &cc);


#endif // CONNECTION_H
