#ifndef DATABASEWORKER_H
#define DATABASEWORKER_H

#include "SqlWorker_global.hpp"
#include "DatabaseType.hpp"

#include <QCoreApplication>
#include <QList>
#include <QString>
#include <QVector>

namespace SqlWorker
{
	/**
	 * @brief Worker (API) for MySQL databases
	 */
	class SQLWORKER_EXPORT DatabaseWorker
	{
		Q_DECLARE_TR_FUNCTIONS(DatabaseWorker)

		public:
			/**
			 * @brief Constructor, setting connection details
			 * @param databaseType The underlying database type
			 * @param sqlServer MySQL-Server for Connection
			 * @param database Database to look in
			 * @param user Username for authentification
			 * @param password Password for authentification
			 */
			DatabaseWorker(
					const DatabaseType databaseType,
					const QString &sqlServer,
					const QString &database,
					const QString &user,
					const QString &password);

			/**
			 * @brief The default destructor
			 */
			~DatabaseWorker();

			/**
			 * @brief Search entries in \p table by filterin with \p filter
			 * @param table The table to search in
			 * @param filter The (column name, value) filters to use
			 * @param columns The columns to display in the result
			 * @param sortBy The column to use for ordering
			 * @param sortAscending Sort by ascending (default, <tt>true</tt>) or descending (<tt>false</tt>) order?
			 * @return List of string vectors representing the colums of the selected table
			 *
			 * This function queries the given database table for values that matches the given filter by building a SQL
			 * query of the form <tt>SELECT columns FROM table WHERE filter.keys()[0] LIKE filter.values()[0] AND ...
			 * (ORDER BY sortBy [ASC/DSC])</tt>. Thereby the <tt>ORDER BY</tt> part is only used if \p sortBy is not
			 * empty (the defualt value).
			 *
			 * If \p columns is a nullpointer the SQL query takes the form <tt>SELECT * FROM [...]</tt>. According to
			 * the [Qt-Manual](https://doc.qt.io/qt-5/qsqlquery.html#value) it is not recommended to do so, since with
			 * this the order of the columns in the result is undefined.
			 *
			 * By internal using the <tt>LIKE</tt> operator in combination with enclosing the value with percent signs
			 * this function does not perform an <i>exact</i> search, but a search in which all results are valid that
			 * <i>contain</i> the filter value (start with, end with or contain the filter value in the middle).
			 *
			 * Sorting is only provided on the basis of one column. If sorting is to be carried out on the basis of
			 * several columns, these must be entered as a comma-separated list. The same holds for the table to use:
			 * It is only intended to use one table. If further tables or more complex operators are to be the basis for
			 * the search, these further values must be used accordingly via the parameter \p table.
			 */
			QList<QVector<QString>*>* searchEntries(
					const QString &table,
					const QMap<QString,QString> *filter = nullptr,
					const QVector<QString> *columns = nullptr,
					const QString sortBy = "",
					const bool sortAscending = true);


			/**
			 * @brief Delete the entries given through \p filter
			 * @param table The table to delete from
			 * @param filter The selection filter.
			 * @return <tt>true</tt> iff executing the query was sucessfull, <tt>false</tt> otherwise
			 *
			 * This function deletes the entries which are given through \p filter. The filter therefore consists
			 * of tuples (cloumn name, value) which are used to build the SQL query in the form of <tt>DELETE [...]
			 * WHERE filter.keys()[0]=filter.values()[0] AND ...</tt>.
			 *
			 * <b>Please note:</b> This function does neither asks if you are sure to perform the deletetion nor checks
			 * how many entries will be affected! If you want to be sure to delete the right things you should perform
			 * a search before.
			 */
			bool deleteEntry(const QString &table,
							 const QMap<QString,QString> &filter);

			/**
			 * @brief Insert a new entry into \p table with given \p values
			 * @param table The table where the entry should be inserted
			 * @param valueTuples The values to insert, as (column name, value) tuples
			 * @return <tt>true</tt> on success, <tt>false</tt> otherwise
			 *
			 * This function creates a new entry in \p table through an SQL query of the form <tt>INSERT INTO table
			 * (valueTupley.keys()[0], ...) VALUES (valueTuples.values()[0], ...)</tt>.
			 */
			bool insertNewEntry(const QString &table,
								const QMap<QString,QString> &valueTuples);

			/**
			 * @brief Updating existing entries in \p table
			 * @param table The table to manipulate
			 * @param filter (cloumn name, value) tuples which are used for searching the entries which are to be
			 *				 manipulated
			 * @param newValues (column name, value) tuples which are used to update the entries found
			 * @return <tt>true</tt> if updating was sucessfull, <tt>false</tt> otherwise
			 *
			 * This function updates the entries found by a query <tt>[...] WHERE filter.keys()[0]=filter.values()[0]
			 * [...]</tt> by overwriting the value of newValues.keys()[0] with newValues.values()[0] etc. It does
			 * <i>not</i> check how many entries will be affected!
			 */
			bool updateEntries(const QString &table,
							   const QMap<QString,QString> &filter,
							   const QMap<QString,QString> &newVaules);

			/**
			 * @brief Getting the last error
			 * @return The last set error message
			 */
			QString& getLastError();

		private:
			/**
			 * @brief The last error
			 */
			QString lastError;

			/**
			 * @brief The name of the database to use
			 */
			QString databaseName;

			/**
			 * @brief Executes SQL command given in \p commandString
			 * @param commandString SQL command to execute
			 * @return <tt>true</tt> on success, <tt>false</tt> otherwise
			 */
			bool executeSQL(QString &commandString);

			/**
			 * @brief Set the last error
			 */
			void setLastError(QString additionalError);

	};
}

#endif // DATABASEWORKER_H
