#include "PgTrigger.h"
#include "PgClassContainer.h"
#include "PgDatabaseCatalog.h"
#include "PgProcContainer.h"
#include "SqlFormattingUtils.h"
#include <QStringBuilder>

QString PgTrigger::dropSql() const
{
	if (m_dropSql.isEmpty()) {
		auto&& fqtablename = catalog().classes()->getByKey(relid)->fullyQualifiedQuotedObjectName(); // genFQTableName(catalog(), *catalog().classes()->getByKey(relid));
		m_dropSql = "DROP TRIGGER " % quotedObjectName()
			  % " ON " % fqtablename % ";";
	}
	return m_dropSql;
}

QString PgTrigger::createSql() const
{
	if (m_createSql.isEmpty()) {
		auto&& fqtablename = catalog().classes()->getByKey(relid)->fullyQualifiedQuotedObjectName(); //genFQTableName(catalog(), *catalog().classes()->getByKey(relid));
		auto&& triggername = quotedObjectName();

		if (constraint != InvalidOid)
			m_createSql += "CREATE CONSTRAINT TRIGGER ";
		else
			m_createSql += "CREATE TRIGGER ";

		m_createSql += triggername + "\n  "
			   + typeFireWhen()
			   + " " + event();

		m_createSql += "\n  ON " + fqtablename;
		if (deferrable) {
			m_createSql += " DEFERRABLE INITIALLY ";
			if (initdeferred)
				m_createSql += "DEFERRED";
			else
				m_createSql += "IMMEDIATE";
		}
		m_createSql += "\n  FOR EACH " + forEach();

		// requires atleast 8.5 don;t think we have to support older
		if (!whenclause.isEmpty())
			m_createSql += " WHEN (" + whenclause + ")";

		m_createSql += QString("\n  EXECUTE PROCEDURE %1;").arg(procedure());

		if (!enabled)
			m_createSql += QString("\nALTER TABLE %1 DISABLE TRIGGER %2;").arg(fqtablename, triggername);

//		if (!GetComment().IsEmpty())
//			sql += wxT("COMMENT ON TRIGGER ") + GetQuotedIdentifier() + wxT(" ON ") + GetQuotedFullTable()
//				   +  wxT(" IS ") + qtDbString(GetComment()) + wxT(";\n");
	}

	return m_createSql;
}


QString PgTrigger::typeFireWhen() const
{
	QString when;

	if (type & TriggerTypeBefore)
		when = "BEFORE";
	else if (type & TriggerTypeInstead)
		when = "INSTEAD OF";
	else
		when = "AFTER";
	return when;
}


QString PgTrigger::eventAbbr() const
{
	QString event;
	if (type & TriggerTypeInsert)
		event += "I";
	if (type & TriggerTypeUpdate)
		event += "U";
	if (type & TriggerTypeDelete)
		event += "D";
	if (type & TriggerTypeTruncate)
		event += "T";
	return event;
}

QString PgTrigger::event() const
{
	QString event;
	if (type & TriggerTypeInsert)
		event += "INSERT ";
	if (type & TriggerTypeUpdate) {
		if (!event.isEmpty()) event += "OR ";
		event += "UPDATE ";
	}
	if (type & TriggerTypeDelete) {
		if (!event.isEmpty()) event += "OR ";
		event += "DELETE ";
	}
	if (type & TriggerTypeTruncate) {
		if (!event.isEmpty()) event += "OR ";
		event += "TRUNCATE";
	}
	return event.trimmed();
}

QString PgTrigger::forEach() const
{
	if (isRow())
		return "ROW";
	else
		return "STATEMENT";
}

QString PgTrigger::procedure() const
{
	const PgProc *proc = catalog().procs()->getByKey(foid);
	QString func_name = proc->fullyQualifiedQuotedObjectName();
	return QString("%1(%2)").arg(func_name, arguments());
}

QString PgTrigger::arguments() const
{
	QString arglist;

	if (nargs > 0)
		arglist = args;

	QString output;
	while (!arglist.isEmpty()) {
		int pos = arglist.indexOf(QChar::Null);
		if (pos != 0) {
			QString arg;
			if (pos > 0)
				arg = arglist.left(pos);
			else
				arg = arglist;

			if (!output.isEmpty())
				output += ", ";

			bool conversion_ok = false;
			arg.toLongLong(&conversion_ok);
			if (conversion_ok)
				output += arg;
			else
				output += escapeLiteral(arg);
		}
		else {
			if (!output.isEmpty())
				output += ", ";
			output += escapeLiteral(QString());
		}
		if (pos >= 0)
			arglist = arglist.mid(pos + 4);
		else
			break;
	}
	return output;
}

QString PgTrigger::typeName() const
{
	return "TRIGGER";
}
