/*
    PIQt Utils - Qt utilites for PIP

    Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    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 Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef pivaluetree_edit_H
#define pivaluetree_edit_H

#include "pivaluetree.h"
#include "qad_piqt_utils_export.h"

#include <QIcon>
#include <QLabel>
#include <QMenu>
#include <QWidget>

class QGridLayout;
class QToolButton;
class QTabWidget;
class PIVariantEdit;
class PIValueTreeEditParameters;
class PIValueTreeEditReorder;
namespace Ui {
class PIValueTreeEditArray;
}

class QAD_PIQT_UTILS_EXPORT PIValueTreeEdit: public QWidget {
	Q_OBJECT
	Q_PROPERTY(Grouping grouping READ grouping WRITE setGrouping)
	Q_PROPERTY(bool fullEditMode READ isFullEditMode WRITE setFullEditMode)
	Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly)
	Q_PROPERTY(Permissions permissions READ permissions WRITE setPermissions)

public:
	PIValueTreeEdit(QWidget * parent = nullptr);
	~PIValueTreeEdit();

	enum Grouping {
		Indent,
		Groups,
		Tabs
	};
	Q_ENUM(Grouping)

	enum Permission {
		AddValue       = 0x1,
		AddGroup       = 0x2,
		AddArray       = 0x4,
		ChangeHidden   = 0x8,
		ChangeLabel    = 0x10,
		ChangeReadOnly = 0x20,
		ChangeComment  = 0x40,
		ChangeType     = 0x80,
		ChangeGrouping = 0x100,
		CanCut         = 0x200,
		CanCopy        = 0x400,
		CanPaste       = 0x800,
		CanRename      = 0x1000,
		CanRemove      = 0x2000,
		CanReorder     = 0x4000,
		PermissionsAll = 0xFFFFFFFF
	};
	Q_ENUM(Permission)
	Q_DECLARE_FLAGS(Permissions, Permission)
	Q_FLAG(Permissions)

	void setValue(const PIValueTree & v);
	PIValueTree value() const;

	Grouping grouping() const { return cur_grouping; }
	void setGrouping(Grouping g);

	bool isFullEditMode() const { return is_full_edit; }
	void setFullEditMode(bool yes);

	bool isReadOnly() const { return m_read_only; }
	void setReadOnly(bool yes);

	Permissions permissions() const { return perm; }
	void setPermissions(Permissions p);
	void setPermission(Permission p, bool on);

	void setAllowedNamesFunction(std::function<PIStringList()> f) { allowed_names = f; }
	void setValueForNameFunction(std::function<PIVariant(PIString)> f) { value_by_name = f; }

	void rollback();
	void clear();
	void retranslate();

private:
	enum class NewType {
		Value,
		Group,
		Array
	};

	void changeEvent(QEvent * e) override;

	void removeAll();
	void build();
	void applyValues() const;
	void applyPermissions();
	void actionRename(QToolButton * button, const PIString & vn);
	void actionRemove(QToolButton * button, const PIString & vn);
	void actionChange(QToolButton * button, const PIString & vn);
	void actionReorder(QToolButton * button, const PIString & vn);
	void actionCopy(QToolButton * button, const PIString & vn);
	void actionPaste(QToolButton * button, const PIString & vn, int offset);
	void actionTriggered(QToolButton * button, const PIString & vn, QAction * a);
	void checkActions();
	void newRequest(NewType type);
	PIValueTreeEdit * addTreeEdit(const PIValueTree & vt);
	PIValueTreeEdit * rootTreeEdit();
	void addValueEdit(const PIValueTree & vt);
	void applyArrayAttributes();
	QLabel * newLabel(const PIValueTree & vt);
	void applyVariantEdit(PIVariantEdit * ve, const PIValueTree & vt);
	void createTabWidget();
	void resizeArray();
	PIVariantMap attributesWithRO(const PIVariantMap & attr);

	class GridWidgets: public QWidget {
	public:
		GridWidgets(PIValueTreeEdit * p);
		~GridWidgets();
		int rowCount() const { return row_count; }
		int getRow(QWidget * w) const;
		void removeRow(int index);
		void add(const PIValueTree & vt, const PIString & label, QWidget * w, const PIString & comment, bool is_group = false);
		void add(const PIValueTree & vt, QWidget * w, bool is_group = false);
		void addRow(QWidget * w);
		QToolButton * createConfigButton(const PIValueTree & vt, bool is_group);
		void replace(int row, QWidget * w);
		void replace(int row, const PIString & label, QWidget * w, const PIString & comment);
		int beginRow(const PIValueTree & vt, bool is_group);
		void rename(const PIString & prev_name, const PIString & new_name);
		void reorder(const PIMap<int, int> & map) { simplify(map); }
		void simplify(const PIMap<int, int> & map = PIMap<int, int>());
		void clear();
		void changed();
		void retranslate();

		bool create_edit_buttons = false;
		QToolButton * button_add;

	private:
		int removeRowEdits(int row);

		int row_count     = 0;
		QGridLayout * lay = nullptr;
		PIValueTreeEdit * parent;
		QMenu menu_group, menu_conf, menu_new;
		QWidgetList widgets;
		QList<QLabel *> labels;
		QIcon icon_conf;
	};

	QWidget * widget_array        = nullptr;
	PIValueTreeEdit * parent_tree = nullptr;
	PIValueTreeEditParameters * widget_params;
	PIValueTreeEditReorder * widget_reorder;
	PIStringList root_path;
	PIString paste_name;
	PIVector<PIVariantEdit *> array_edits;
	PIMap<PIString, PIVariantEdit *> value_edits;
	PIMap<PIString, PIValueTreeEdit *> tree_edits;
	PIMap<PIString, QLabel *> comm_labels, label_labels;
	QTabWidget * tab_widget             = nullptr;
	Ui::PIValueTreeEditArray * ui_array = nullptr;
	GridWidgets * grid                  = nullptr;
	Grouping cur_grouping               = Groups;
	Permissions perm                    = PermissionsAll;
	mutable PIValueTree source, current;
	bool is_full_edit = false, m_read_only = false;
	std::function<PIStringList()> allowed_names;
	std::function<PIVariant(PIString)> value_by_name;
};

Q_DECLARE_OPERATORS_FOR_FLAGS(PIValueTreeEdit::Permissions)


#endif
