#ifndef QUERYTAB_H
#define QUERYTAB_H

#include "ManagedPage.h"
#include "ASyncDBConnection.h"
#include "QueryResultModel.h"
#include "QueryExplainModel.h"
#include "stopwatch.h"
#include "tuplesresultwidget.h"

#include <QWidget>
#include <memory>

class IDatabaseWindow;

namespace Ui {
	class QueryTab;
}

namespace Pgsql {
	class ErrorDetails ;
}

class QTableView;

class QTabWidget;
class SqlSyntaxHighlighter;
class ExplainRoot;
class QueryResultModel;
class QueryExplainModel;
class PgTypeContainer;
class OpenDatabase;
class QueryParamListController;
class PgDatabaseCatalog;

class QueryTool : public ManagedPage {
	Q_OBJECT
public:
	QueryTool(IDatabaseWindow *context, QWidget *parent = nullptr);
	~QueryTool() override;

	void newdoc();
	bool load(const QString &filename);

	void explain(bool analyze);

	bool CanClose(bool prompt_user);

	void generateCode();
	void exportDataToFilename(const QString &filename);

	QString fileName() const { return m_fileName; }
	bool isChanged() const { return m_queryTextChanged; }
	bool isNew() const { return m_new; }
	void focusEditor();

	QString title() const;


public slots:
    void execute();
    /// Save the document under its current name, a file save dialog will be shown if this is a new document
	bool save();
	/// Saves the document under a new name and continue editing the document under this new name.
	bool saveAs();
	/// Save the document under a new name but continue editing the document under its old name.
	void saveCopyAs();
	void copyQueryAsCString();
	void copyQueryAsRawCppString();
	void pasteLangString();
	void cancel();
	void exportData();

private:

	using ResultTabContainer = std::vector<TuplesResultWidget*>;
	IDatabaseWindow *m_context;
	Ui::QueryTab *ui;
	SqlSyntaxHighlighter* highlighter;
	ConnectionConfig m_config;
	StopWatch m_stopwatch;

	QueryParamListController *m_queryParamListController = nullptr;

	bool m_new = true;
	QString m_fileName; ///< use setFileName function to set
	bool m_queryTextChanged = false;

	std::shared_ptr<PgDatabaseCatalog> m_catalog;
	ASyncDBConnection m_dbConnection;

	std::unique_ptr<QueryExplainModel> explainModel;
	ResultTabContainer resultList;

	void setFileName(const QString &filename);
	bool continueWithoutSavingWarning();
	bool saveSqlTo(const QString &filename);
	QString promptUserForSaveSqlFilename();

	void addLog(QString s);

	QString getCommand() const;
	std::string getCommandUtf8() const;

	void clearResult();
	void markError(const Pgsql::ErrorDetails &details);
    void updateTitle();
    void setQueryTextChanged(bool queryTextChanged);

private slots:

	void explain_ready(ExplainRoot::SPtr explain);
    void query_ready(std::shared_ptr<Pgsql::Result>, qint64 elapsedms);

	void queryTextChanged();
    void connectionStateChanged(ASyncDBConnection::StateData state);
	void receiveNotice(Pgsql::ErrorDetails notice);

	void startConnect();
};


#endif // QUERYTAB_H
