/*
# PostgreSQL Database Modeler (pgModeler)
#
# Copyright 2006-2020 - Raphael Araújo e Silva <raphael@pgmodeler.io>
#
# This program 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 version 3.
#
# This program 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.
#
# The complete text of GPLv3 is at LICENSE file on source code root directory.
# Also, you can get the complete GNU General Public License at <http://www.gnu.org/licenses/>
*/

/**
\ingroup libpgmodeler
\class Reference
\brief This auxiliary class is used to define SQL/XML for views
\note <strong>Creation date:</strong> 05/09/2008
*/

#ifndef REFERENCE_H
#define REFERENCE_H

#include "table.h"
#include "schema.h"

/*! \brief This simple struct acts like a rudimentary column used by Reference and Views to represent columns
 * Note that, as intended, the struct expects that all received values are validated since they are immutable */
struct SimpleColumn {
	QString name, type, alias;
	SimpleColumn(const QString &_name, const QString &_type, const QString &_alias) :
		name(_name), type(_type), alias(_alias) {}
};

class Reference {
	private:
		//! \brief Stores the table used by the reference
		PhysicalTable *table;

		//! \brief Stores the column used by the reference
		Column *column;

		//! \brief Stores the expression that defines one reference
		QString expression,

		//! \brief Stores the alias to the expression or table
		alias,

		//! \brief Stores only the alias for the column
		column_alias,

		//! \brief Stores the alias for the reference. This text will be displayed when the view is being show in compact mode
		ref_alias;

		//! \brief Indicates if the expression is used as entire view definition
		bool is_def_expr;

		/*! \brief Stores the columns that the reference (when being an expression [is_def_expr]) generates.
		 * These columns are used when drawing a view and that has only on definition expression.
		 * By having columns, instead of drawing the expression as a column of the view, the ones in
		 * this vector are displayed */
		vector<SimpleColumn> columns;

		/*! \brief Stores the tables that the reference object is using within the expression which defines the view
		 * when is_def_expr is set. These tables are used to hint the user which tables the view is using. */
		vector<PhysicalTable *> ref_tables;

	public:
		//! \brief Constants used to define the reference type
		static constexpr unsigned ReferColumn=0, //! \brief The reference is based on a table column
		ReferExpression=1; //! \brief The reference is based on an expression

		//! \brief Constants used on the view code generation
		static constexpr unsigned SqlReferWhere=1,
		SqlReferSelect=2,
		SqlReferFrom=4,
		SqlReferEndExpr=8,
		SqlViewDefinition=16;

		Reference();

		//! \brief Creates a reference based on a table column
		Reference(PhysicalTable *table, Column *column, const QString &tab_alias, const QString &col_alias);

		//! \brief Creates a reference based on a expression
		Reference(const QString &expression, const QString &expr_alias);

		/*! \brief Changes the behavior of the expression. Calling this method will cause the
		reference to be used as the entire view SQL definition */
		void setDefinitionExpression(bool value);

		void addReferencedTable(PhysicalTable *ref_table);
		int getReferencedTableIndex(PhysicalTable *ref_table);
		void clearReferencedTables();
		vector<PhysicalTable *> getReferencedTables();

		//! \brief Gets the referenced table
		PhysicalTable *getTable();

		//! \brief Gets the referenced column
		Column *getColumn();

		//! \brief Returns the alias for the referenced column
		QString getColumnAlias();

		//! \brief Returs the reference for the table or expression
		QString getAlias();

		//! \brief Returns the expression for the reference
		QString getExpression();

		//! \brief Returns the reference typ (see REFER_??? constants)
		unsigned getReferenceType();

		void setReferenceAlias(const QString &alias);

		QString getReferenceAlias();

		//! \brief Returns the SQL code definition
		QString getSQLDefinition(unsigned sql_type);

		//! \brief Returns the XML code definition
		QString getXMLDefinition();

		//! \brief Indicates if the reference when used as expression defines the entire view (raw sql definition)
		bool isDefinitionExpression();

		//! \brief Adds a column as being generated by the reference (if it is an expression)
		void addColumn(const QString &name, PgSqlType type, const QString &alias);
		void addColumn(Column *col);

		//! \brief Clears the columns generated by the expression
		void removeColumns();

		//! \brief Returns the columns which the reference generates
		vector<SimpleColumn> getColumns();

		/*! \brief Compare the attributes of two references returning true
		 when they have the same values */
		bool operator == (Reference &refer);
};

#endif
