/*
 * Copyright (C) 2011 Elvis Stansvik <elvstone@gmail.com>
 *
 * For general Scribus (>=1.3.2) copyright and licensing information please refer
 * to the COPYING file provided with the program. Following this notice may exist
 * a copyright and/or license notice that predates the release of Scribus 1.3.2
 * for which a new license (GPL+exception) is in place.
 */

#include "cmdtable.h"
#include "cmdutil.h"
#include "pageitem_table.h"
#include "pyesstring.h"

PyObject *scribus_gettablerows(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	if (!PyArg_ParseTuple(args, "|es", "utf-8", name.ptr()))
	{
		name.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;

	const PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get table row count of non-table item.","python error").toUtf8().constData());
		return nullptr;
	}
	return PyLong_FromLong(static_cast<long>(table->rows()));
}

PyObject *scribus_gettablecolumns(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	if (!PyArg_ParseTuple(args, "|es", "utf-8", name.ptr()))
	{
		name.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;

	const PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get table column count of non-table item.","python error").toUtf8().constData());
		return nullptr;
	}
	return PyLong_FromLong(static_cast<long>(table->columns()));
}

PyObject *scribus_inserttablerows(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	int index, numRows;
	if (!PyArg_ParseTuple(args, "ii|es", &index, &numRows, "utf-8", name.ptr()))
	{
		name.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;
	PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot insert rows on a non-table item.","python error").toUtf8().constData());
		return nullptr;
	}
	if (index < 0 || index > table->rows())
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("Table row index out of bounds, must be >= 0 and < %1", "python error").arg(table->rows()).toUtf8().constData());
		return nullptr;
	}
	if (numRows < 1)
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("Table row count out of bounds, must be >= 1", "python error").toUtf8().constData());
		return nullptr;
	}
	table->insertRows(index, numRows);
	Py_RETURN_NONE;
}

PyObject *scribus_removetablerows(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	int index, numRows;
	if (!PyArg_ParseTuple(args, "ii|es", &index, &numRows, "utf-8", name.ptr()))
	{
		name.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;
	PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot remove rows from a non-table item.","python error").toUtf8().constData());
		return nullptr;
	}
	if (index < 0 || index >= table->rows())
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("Table row index out of bounds, must be >= 0 and < %1", "python error").arg(table->rows()).toUtf8().constData());
		return nullptr;
	}
	if (numRows < 1 || numRows >= table->rows())
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("Table row count out of bounds, must be >= 1 and < %1", "python error").arg(table->rows()).toUtf8().constData());
		return nullptr;
	}
	if (index + numRows > table->rows())
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("Row deletion range out of bounds, index + numRows must be <= %1", "python error").arg(table->rows()).toUtf8().constData());
		return nullptr;
	}
	table->removeRows(index, numRows);
	Py_RETURN_NONE;
}

PyObject *scribus_gettablerowheight(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	int row;
	if (!PyArg_ParseTuple(args, "i|es", &row, "utf-8", name.ptr()))
	{
		name.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;
	const PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get row height from non-table item.","python error").toUtf8().constData());
		return nullptr;
	}
	return PyFloat_FromDouble(table->rowHeight(row));
}

PyObject *scribus_resizetablerow(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	int row;
	double height;
	if (!PyArg_ParseTuple(args, "id|es", &row, &height, "utf-8", name.ptr()))
	{
		name.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;
	PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot resize row on a non-table item.","python error").toUtf8().constData());
		return nullptr;
	}
	if (row < 0 || row >= table->rows())
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("Table row index out of bounds, must be >= 0 and < %1", "python error").arg(table->rows()).toUtf8().constData());
		return nullptr;
	}
	if (height <= 0.0)
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("Table row height must be > 0.0", "python error").toUtf8().constData());
		return nullptr;
	}
	table->resizeRow(row, height);
	Py_RETURN_NONE;
}

PyObject *scribus_inserttablecolumns(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	int index, numColumns;
	if (!PyArg_ParseTuple(args, "ii|es", &index, &numColumns, "utf-8", name.ptr()))
	{
		name.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;
	PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot insert columns on a non-table item.","python error").toUtf8().constData());
		return nullptr;
	}
	if (index < 0 || index > table->columns())
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("Table column index out of bounds, must be >= 0 and < %1", "python error").arg(table->columns()).toUtf8().constData());
		return nullptr;
	}
	if (numColumns < 1)
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("Table column count out of bounds, must be >= 1", "python error").toUtf8().constData());
		return nullptr;
	}
	table->insertColumns(index, numColumns);
	Py_RETURN_NONE;
}

PyObject *scribus_removetablecolumns(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	int index, numColumns;
	if (!PyArg_ParseTuple(args, "ii|es", &index, &numColumns, "utf-8", name.ptr()))
	{
		name.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;
	PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot remove columns from a non-table item.","python error").toUtf8().constData());
		return nullptr;
	}
	if (index < 0 || index >= table->columns())
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("Table column index out of bounds, must be >= 0 and < %1", "python error").arg(table->columns()).toUtf8().constData());
		return nullptr;
	}
	if (numColumns < 1 || numColumns >= table->columns())
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("Table column count out of bounds, must be >= 1 and < %1", "python error").arg(table->columns()).toUtf8().constData());
		return nullptr;
	}
	if (index + numColumns > table->columns())
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("Column deletion range out of bounds, index + numColumns must be <= %1", "python error").arg(table->columns()).toUtf8().constData());
		return nullptr;
	}
	table->removeColumns(index, numColumns);
	Py_RETURN_NONE;
}

PyObject *scribus_gettablecolumnwidth(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	int column;
	if (!PyArg_ParseTuple(args, "i|es", &column, "utf-8", name.ptr()))
	{
		name.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;
	const PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get column width from non-table item.","python error").toUtf8().constData());
		return nullptr;
	}
	return PyFloat_FromDouble(table->columnWidth(column));
}

PyObject *scribus_resizetablecolumn(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	int column;
	double width;
	if (!PyArg_ParseTuple(args, "id|es", &column, &width, "utf-8", name.ptr()))
	{
		name.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;
	PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot resize column on a non-table item.","python error").toUtf8().constData());
		return nullptr;
	}
	if (column < 0 || column >= table->columns())
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("Table column index out of bounds, must be >= 0 and < %1", "python error").arg(table->columns()).toUtf8().constData());
		return nullptr;
	}
	if (width <= 0.0)
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("Table column width must be > 0.0", "python error").toUtf8().constData());
		return nullptr;
	}
	table->resizeColumn(column, width);
	Py_RETURN_NONE;
}

PyObject *scribus_mergetablecells(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	int row, column, numRows, numColumns;
	if (!PyArg_ParseTuple(args, "iiii|es", &row, &column, &numRows, &numColumns, "utf-8", name.ptr()))
	{
		name.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;
	PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot merge cells on a non-table item.","python error").toUtf8().constData());
		return nullptr;
	}
	if (numRows < 1 || numColumns < 1)
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("Number of rows and columns must both be > 0.", "python error").toUtf8().constData());
		return nullptr;
	}
	if (row < 0 || row >= table->rows() || column < 0 || column >= table->columns() ||
			row + numRows - 1 < 0 || row + numRows - 1 >= table->rows() ||
			column + numColumns - 1 < 0 || column + numColumns - 1 >= table->columns())
	{
		PyErr_SetString(PyExc_ValueError, QObject::tr("The area %1,%2 %3x%4 is not inside the table.", "python error").arg(row).arg(column).arg(numColumns).arg(numRows).toUtf8().constData());
		return nullptr;
	}
	table->mergeCells(row, column, numRows, numColumns);
	Py_RETURN_NONE;
}

PyObject *scribus_gettablestyle(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	if (!PyArg_ParseTuple(args, "|es", "utf-8", name.ptr()))
	{
		name.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;
	const PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get table style on a non-table item.","python error").toUtf8().constData());
		return nullptr;
	}
	return PyUnicode_FromString(table->styleName().toUtf8());
}

PyObject *scribus_settablestyle(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	PyESString style;
	if (!PyArg_ParseTuple(args, "es|es", "utf-8", style.ptr(), "utf-8", name.ptr()))
	{
		name.resetDontFree();
		style.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;
	PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set table style on a non-table item.","python error").toUtf8().constData());
		return nullptr;
	}
	table->setStyle(QString::fromUtf8(style.c_str()));
	Py_RETURN_NONE;
}

PyObject *scribus_gettablefillcolor(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	if (!PyArg_ParseTuple(args, "|es", "utf-8", name.ptr()))
	{
		name.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;
	const PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get table fill color on a non-table item.","python error").toUtf8().constData());
		return nullptr;
	}
	return PyUnicode_FromString(table->fillColor().toUtf8());
}

PyObject *scribus_settablefillcolor(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	PyESString color;
	if (!PyArg_ParseTuple(args, "es|es", "utf-8", color.ptr(), "utf-8", name.ptr()))
	{
		name.resetDontFree();
		color.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;
	PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set table fill color on a non-table item.","python error").toUtf8().constData());
		return nullptr;
	}
	table->setFillColor(QString::fromUtf8(color.c_str()));
	Py_RETURN_NONE;
}

PyObject *scribus_settableleftborder(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	PyObject* borderLines;
	if (!PyArg_ParseTuple(args, "O|es", &borderLines, "utf-8", name.ptr()))
	{
		name.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;
	PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set table left border on a non-table item.","python error").toUtf8().constData());
		return nullptr;
	}

	bool ok = false;
	TableBorder border = parseBorder(borderLines, &ok);
	if (ok)
		table->setLeftBorder(border);
	else
		return nullptr;

	Py_RETURN_NONE;
}

PyObject *scribus_settablerightborder(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	PyObject* borderLines;
	if (!PyArg_ParseTuple(args, "O|es", &borderLines, "utf-8", name.ptr()))
	{
		name.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;
	PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set table right border on a non-table item.","python error").toUtf8().constData());
		return nullptr;
	}

	bool ok = false;
	TableBorder border = parseBorder(borderLines, &ok);
	if (ok)
		table->setRightBorder(border);
	else
		return nullptr;

	Py_RETURN_NONE;
}

PyObject *scribus_settabletopborder(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	PyObject* borderLines;
	if (!PyArg_ParseTuple(args, "O|es", &borderLines, "utf-8", name.ptr()))
	{
		name.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;
	PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set table top border on a non-table item.","python error").toUtf8().constData());
		return nullptr;
	}

	bool ok = false;
	TableBorder border = parseBorder(borderLines, &ok);
	if (ok)
		table->setTopBorder(border);
	else
		return nullptr;

	Py_RETURN_NONE;
}

PyObject *scribus_settablebottomborder(PyObject* /* self */, PyObject* args)
{
	PyESString name;
	PyObject* borderLines;
	if (!PyArg_ParseTuple(args, "O|es", &borderLines, "utf-8", name.ptr()))
	{
		name.resetDontFree();
		return nullptr;
	}
	if (!checkHaveDocument())
		return nullptr;
	PageItem *i = GetUniqueItem(QString::fromUtf8(name.c_str()));
	if (i == nullptr)
		return nullptr;
	PageItem_Table *table = i->asTable();
	if (!table)
	{
		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set table bottom border on a non-table item.","python error").toUtf8().constData());
		return nullptr;
	}

	bool ok = false;
	TableBorder border = parseBorder(borderLines, &ok);
	if (ok)
		table->setBottomBorder(border);
	else
		return nullptr;

	Py_RETURN_NONE;
}

/*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings
with header files structure untouched (docstrings are kept near declarations)
PV */
void cmdtabledocwarnings()
{
	QStringList s;
	s << scribus_gettablecolumns__doc__
	  << scribus_gettablecolumnwidth__doc__
	  << scribus_gettablefillcolor__doc__
	  << scribus_gettablerowheight__doc__
	  << scribus_gettablerows__doc__
	  << scribus_gettablestyle__doc__
	  << scribus_inserttablecolumns__doc__ 
	  << scribus_inserttablerows__doc__
	  << scribus_mergetablecells__doc__
	  << scribus_removetablerows__doc__
	  << scribus_removetablecolumns__doc__
	  << scribus_resizetablecolumn__doc__
	  << scribus_resizetablerow__doc__ 
	  << scribus_settablebottomborder__doc__
	  << scribus_settablefillcolor__doc__
	  << scribus_settableleftborder__doc__
	  << scribus_settablerightborder__doc__
	  << scribus_settablestyle__doc__
	  << scribus_settabletopborder__doc__;
}
