#include <QInputDialog>
#include <QMessageBox>

#include "sendbuttonmenu.h"
#include "psioptions.h"
#include "psiiconset.h"
#include "common.h"

SendButtonTemplatesEditor::SendButtonTemplatesEditor(QWidget* parent)
	: QDialog(parent)
{
	ui_.setupUi(this);
	setAttribute(Qt::WA_DeleteOnClose);
	// Create actions
	QAction *addRootTemplAction = new QAction(tr("Add template string"), this);
	connect(addRootTemplAction, SIGNAL(triggered()), this, SLOT(addRootTemplate()));
	addChildTemplAction = new QAction(tr("Add template string as submenu"), this);
	connect(addChildTemplAction, SIGNAL(triggered()), this, SLOT(addChildTemplate()));
	QAction *addRootSeparatorAction = new QAction(tr("Add separator"), this);
	connect(addRootSeparatorAction, SIGNAL(triggered()), this, SLOT(addRootSeparator()));
	addChildSeparatorAction = new QAction(tr("Add separator as submenu"), this);
	connect(addChildSeparatorAction, SIGNAL(triggered()), this, SLOT(addChildSeparator()));
	editAction = new QAction(IconsetFactory::icon("psi/action_templates_edit").icon(), tr("Edit"), this);
	removeAction = new QAction(IconsetFactory::icon("psi/remove").icon(), tr("Remove"), this);
	upAction = new QAction(IconsetFactory::icon("psi/arrowUp").icon(), tr("Up"), this);
	downAction = new QAction(IconsetFactory::icon("psi/arrowDown").icon(), tr("Down"), this);
	// Create Add button menu
	QMenu *add_menu = new QMenu(this);
	add_menu->addAction(addRootTemplAction);
	add_menu->addAction(addChildTemplAction);
	add_menu->addAction(addRootSeparatorAction);
	add_menu->addAction(addChildSeparatorAction);
	ui_.btnAdd->setMenu(add_menu);
	//--
	QStringList templ_list = PsiOptions::instance()->getOption("options.ui.chat.templates", QStringList()).toStringList();
	int templ_cnt = templ_list.size();
	QHash<QString, QTreeWidgetItem *> subitems;
	for (int i = 0; i < templ_cnt; i++) {
		QStringList menu_list = SendButtonTemplatesMenu::getMenuItems(templ_list.at(i));
		if (menu_list.size() == 0)
			continue;
		// find subitems if exists
		QTreeWidgetItem *item = NULL;
		QString menu_str = "";
		int j = menu_list.size() - 2;
		for (; j >= 0; j--) {
			menu_str = "";
			QString menu_str2 = "";
			for (int k = 0; k <= j; k++) {
				menu_str = menu_str2;
				menu_str2.append("/" + menu_list.at(k));
			}
			item = subitems.value(menu_str2, NULL);
			if (item) {
				menu_str = menu_str2;
				++j;
				break;
			}
		}
		if (j < 0)
			j = 0;
		// create subitems
		int sub_cnt = menu_list.size();
		for (; j < sub_cnt; j++) {
			QString str1 = menu_list.at(j);
			QTreeWidgetItem::ItemType type = QTreeWidgetItem::Type;
			if (j == (sub_cnt - 1) && str1 == "\\-") {
				str1 = tr("<separator>");
				type = QTreeWidgetItem::UserType;
			}
			if (j == 0) {
				// toplevel item
				item = new QTreeWidgetItem(ui_.lstTemplates, type);
			} else {
				item = new QTreeWidgetItem(item, type);
			}
			if (type == QTreeWidgetItem::UserType) {
				item->setFlags(item->flags() & ~Qt::ItemIsDropEnabled);
			}
			item->setText(0, SendButtonTemplatesMenu::stripSlashes(str1));
			if (j < (sub_cnt - 1)) {
				menu_str.append("/" + str1);
				subitems[menu_str] = item;
			}
		}
	}
}

void SendButtonTemplatesEditor::addRootTemplate()
{
	QString t = ui_.txtTemplate->text();
	if (t.isEmpty())
		return;
	QTreeWidgetItem *item = new QTreeWidgetItem(ui_.lstTemplates, QStringList(t), QTreeWidgetItem::Type);
	ui_.lstTemplates->addTopLevelItem(item);
	ui_.txtTemplate->setText("");
}

void SendButtonTemplatesEditor::addChildTemplate()
{
	QString t = ui_.txtTemplate->text();
	if (t.isEmpty())
		return;
	QTreeWidgetItem *curr_item = ui_.lstTemplates->currentItem();
	if (curr_item && curr_item->type() == QTreeWidgetItem::Type) {
		curr_item->addChild(new QTreeWidgetItem(QStringList(t), QTreeWidgetItem::Type));
		ui_.txtTemplate->setText("");
	}
}

void SendButtonTemplatesEditor::addRootSeparator()
{
	QTreeWidgetItem *item = new QTreeWidgetItem(ui_.lstTemplates, QStringList(tr("<separator>")), QTreeWidgetItem::UserType);
	item->setFlags(item->flags() & ~Qt::ItemIsDropEnabled);
	ui_.lstTemplates->addTopLevelItem(item);
}

void SendButtonTemplatesEditor::addChildSeparator()
{
	QTreeWidgetItem *curr_item = ui_.lstTemplates->currentItem();
	if (curr_item && curr_item->type() == QTreeWidgetItem::Type) {
		QTreeWidgetItem *item = new QTreeWidgetItem(QStringList(tr("<separator>")), QTreeWidgetItem::UserType);
		item->setFlags(item->flags() & ~Qt::ItemIsDropEnabled);
		curr_item->addChild(item);
	}
}

void SendButtonTemplatesEditor::removeTemplate()
{
	QTreeWidgetItem *item = ui_.lstTemplates->currentItem();
	if (item) {
		delete item;
	}
}

void SendButtonTemplatesEditor::editTemplate()
{
	QTreeWidgetItem *item = ui_.lstTemplates->currentItem();
	if (item && item->type() == QTreeWidgetItem::Type) {
		QString templ_str = item->text(0);
		QInputDialog *editBox = new QInputDialog(this, Qt::Dialog);
		editBox->setWindowTitle(tr("Edit template"));
		editBox->setLabelText(tr("Input new template text"));
		editBox->setTextEchoMode(QLineEdit::Normal);
		editBox->setTextValue(templ_str);
		editBox->setWindowModality(Qt::WindowModal);
		if (editBox->exec() == QInputDialog::Accepted) {
			QString new_templ_str = editBox->textValue();
			if (!new_templ_str.isEmpty() && new_templ_str != templ_str) {
				item->setText(0, new_templ_str);
			}
		}
		delete editBox;
	}
}

void SendButtonTemplatesEditor::upTemplate()
{
	swapItem(-1);
}

void SendButtonTemplatesEditor::downTemplate()
{
	swapItem(1);
}

void SendButtonTemplatesEditor::selectionChanged(QTreeWidgetItem *current, QTreeWidgetItem */*previous*/)
{
	bool up_e = false;
	bool dw_e = false;
	bool ed_e = false;
	bool dl_e = false;
	QModelIndex index = ui_.lstTemplates->currentIndex();
	if (current && index.isValid()) {
		QTreeWidgetItem *parent = current->parent();
		int cnt = 0;
		if (parent) {
			cnt = parent->childCount();
		} else {
			cnt = ui_.lstTemplates->topLevelItemCount();
		}
		int row = index.row();
		if (cnt > 0) {
			if (row > 0)
				up_e = true;
			if (row < cnt - 1)
				dw_e = true;
			if (current->type() == QTreeWidgetItem::Type)
				ed_e = true;
			dl_e = true;
		}

	}
	addChildTemplAction->setEnabled(ed_e);
	addChildSeparatorAction->setEnabled(ed_e);
	ui_.btnEdit->setEnabled(ed_e);
	editAction->setEnabled(ed_e);
	ui_.btnRemove->setEnabled(dl_e);
	removeAction->setEnabled(ed_e);
	ui_.btnUp->setEnabled(up_e);
	upAction->setEnabled(up_e);
	ui_.btnDown->setEnabled(dw_e);
	downAction->setEnabled(dw_e);
}

void SendButtonTemplatesEditor::contextMenu(QPoint pos)
{
	QMenu* menu = new QMenu(this);
	menu->addAction(editAction);
	menu->addAction(removeAction);
	menu->addSeparator();
	menu->addAction(upAction);
	menu->addAction(downAction);
	QAction *result = menu->exec(ui_.lstTemplates->mapToGlobal(pos));
	if (result == editAction) {
		editTemplate();
	} else if (result == removeAction) {
		removeTemplate();
	} else if (result == upAction) {
		upTemplate();
	} else if (result == downAction) {
		downTemplate();
	}
	delete menu;
}

void SendButtonTemplatesEditor::swapItem(int updown)
{
	QTreeWidgetItem *item = ui_.lstTemplates->currentItem();
	QModelIndex index = ui_.lstTemplates->currentIndex();
	if (item && index.isValid()) {
		int row = index.row();
		int new_pos = row + updown;
		QTreeWidgetItem * parent = item->parent();
		int cnt = 0;
		if (parent) {
			cnt = parent->childCount();
		} else {
			cnt = ui_.lstTemplates->topLevelItemCount();
		}
		if (new_pos >= 0 && new_pos < cnt) {
			if (parent) {
				parent->removeChild(item);
				parent->insertChild(new_pos, item);
			} else {
				ui_.lstTemplates->takeTopLevelItem(row);
				ui_.lstTemplates->insertTopLevelItem(new_pos, item);
			}
			ui_.lstTemplates->setCurrentItem(item);
			selectionChanged(item, item); // needed update buttons
		}
	}
}

QStringList SendButtonTemplatesEditor::genTemplatesList(QTreeWidgetItem* item, QString base_path)
{
	QStringList res_lst;
	QString new_base = base_path;
	if (!new_base.isEmpty())
		new_base.append("/");
	QString item_text = SendButtonTemplatesMenu::addSlashes(item->text(0));
	int child_cnt = item->childCount();
	if (child_cnt == 0) {
		if (item->type() != QTreeWidgetItem::Type)
			item_text = "\\-"; // Separator
		res_lst.push_back(new_base + item_text);
		return res_lst;
	}
	new_base.append(item_text);
	for (int idx = 0; idx < child_cnt; idx++) {
		res_lst.append(genTemplatesList(item->child(idx), new_base));
	}
	return res_lst;
}

void SendButtonTemplatesEditor::accept()
{
	QString t = ui_.txtTemplate->text().trimmed();
	if (!t.isEmpty()) {
		QMessageBox *msgBox = new QMessageBox(this);
		msgBox->setIcon(QMessageBox::Warning);
		msgBox->setWindowTitle(tr("Save templates"));
		msgBox->setText(tr("The template \"%1\" hasn't been saved!").arg(t));
		msgBox->setInformativeText(tr("Continue?"));
		msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
		msgBox->setDefaultButton(QMessageBox::No);
		msgBox->setWindowModality(Qt::WindowModal);
		int res = msgBox->exec();
		delete msgBox;
		if (res == QMessageBox::No) {
			return;
		}
	}
	QStringList templates;
	int top_cnt = ui_.lstTemplates->topLevelItemCount();
	for (int idx = 0; idx < top_cnt; idx++) {
		templates.append(genTemplatesList(ui_.lstTemplates->topLevelItem(idx)));
	}
	PsiOptions::instance()->setOption("options.ui.chat.templates", templates);
	QDialog::accept();
	close();
}

void SendButtonTemplatesEditor::reject()
{
	QDialog::reject();
	close();
}

//------------------------------

SendButtonTemplatesMenu::SendButtonTemplatesMenu(QWidget* parent)
	: QMenu(parent)
	, mapper(NULL)
	, ps_(false)
{
	setSeparatorsCollapsible(true);
	update();
	connect(PsiOptions::instance(), SIGNAL(optionChanged(const QString&)), SLOT(optionChanged(const QString&)));
}

void SendButtonTemplatesMenu::setParams(bool ps)
{
	if (ps_ != ps) {
		ps_ = ps;
		updatePsAction();
	}
}

void SendButtonTemplatesMenu::updatePsAction()
{
	bool ps_v = false;
	if (ps_ && !PsiOptions::instance()->getOption("options.ui.chat.disable-paste-send").toBool())
		ps_v = true;
	pasteSendAct->setVisible(ps_v);
}

/**
 * Split menu text string as submenu. Char '/' used as separator.
 */
QStringList SendButtonTemplatesMenu::getMenuItems(const QString text)
{
	QStringList res_list;
	int str_len = text.length();
	unsigned int sl_cnt = 0;
	int str_pos = 0;
	for (int i = 0; i < str_len; i++) {
		QChar ch = text.at(i);
		if (ch == '\\') {
			sl_cnt++;
		} else if (ch == '/') {
			if ((sl_cnt & 1) == 0) {
				QString str1 = text.mid(str_pos, i - str_pos).trimmed();
				if (!str1.isEmpty()) {
					res_list.push_back(str1);
					str_pos = i + 1;
				}
				str_pos = i + 1;
			}
			sl_cnt = 0;
		} else {
			sl_cnt = 0;
		}
	}
	if (str_pos < str_len) {
		QString str1 = text.mid(str_pos);
		if (!str1.isEmpty()) {
			res_list.push_back(str1);
		}
	}
	return res_list;
}

QAction *SendButtonTemplatesMenu::makeAction(QString text)
{
	QString str1;
	if (text.length() > 30) {
		str1 = text.left(30).replace("&", "&&") + "...";
	} else {
		str1 = text.replace("&", "&&");
	}
	QAction *act = new QAction(str1, this);
	return act;
}

void SendButtonTemplatesMenu::update()
{
	clearMenu(this);
	if (mapper)
		delete mapper;
	mapper = new QSignalMapper(this);

	pasteSendAct = new QAction(IconsetFactory::icon("psi/action_paste_and_send").icon(), tr("Paste and &Send"), this);
	connect(pasteSendAct, SIGNAL(triggered()), SIGNAL(doPasteAndSend()));
	addAction(pasteSendAct);
	updatePsAction();
	addSeparator();

	QAction *editTemplatesAct = new QAction(IconsetFactory::icon("psi/action_templates_edit").icon(), tr("&Edit Templates"), this);
	connect(editTemplatesAct, SIGNAL(triggered()), SIGNAL(doEditTemplates()));
	addAction(editTemplatesAct);

	onlyPaste = new QAction(tr("Only &Paste"), this);
	onlyPaste->setCheckable(true);
	onlyPaste->setChecked(PsiOptions::instance()->getOption("options.ui.chat.only-paste-template").toBool());
	connect(onlyPaste, SIGNAL(triggered()), SLOT(clickOnlyPaste()));
	addAction(onlyPaste);
	addSeparator();

	QStringList templ_list = PsiOptions::instance()->getOption("options.ui.chat.templates", QStringList()).toStringList();
	int templ_cnt = templ_list.size();
	QHash<QString, QAction *> submenus;
	for (int i = 0; i < templ_cnt; i++) {
		QStringList menu_list = SendButtonTemplatesMenu::getMenuItems(templ_list.at(i));
		if (menu_list.size() == 0)
			continue;
		// find submenus if exists
		QAction *m_act = NULL;
		QString menu_str = "";
		int j = menu_list.size() - 2;
		for (; j >= 0; j--) {
			menu_str = "";
			QString menu_str2 = "";
			for (int k = 0; k <= j; k++) {
				menu_str = menu_str2;
				menu_str2.append("/" + menu_list.at(k));
			}
			m_act = submenus.value(menu_str2, NULL);
			if (m_act) {
				menu_str = menu_str2;
				++j;
				break;
			}
		}
		if (j < 0)
			j = 0;
		// create submenus
		QMenu *smenu = this;
		if (m_act) {
			smenu = m_act->menu();
			if (!smenu)
				smenu = new QMenu(this);
		}
		int sub_cnt = menu_list.size();
		for (; ; j++) {
			QString str1 = menu_list.at(j);
			if (j == (sub_cnt - 1) && str1 == "\\-") {
				smenu->addSeparator();
				break;
			}
			QAction *c_act = makeAction(SendButtonTemplatesMenu::stripSlashes(str1));
			smenu->addAction(c_act);
			if (j == (sub_cnt - 1)) {
				connect(c_act, SIGNAL(triggered()), mapper, SLOT(map()));
				mapper->setMapping(c_act, SendButtonTemplatesMenu::stripSlashes(str1));
				break;
			} else {
				smenu = new QMenu(this);
				c_act->setMenu(smenu);
				menu_str.append("/" + str1);
				submenus[menu_str] = c_act;
			}
		}
	}
	connect(mapper, SIGNAL(mapped(const QString &)), SIGNAL(doTemplateText(const QString &)));
}

void SendButtonTemplatesMenu::clickOnlyPaste()
{
	if (PsiOptions::instance()->getOption("options.ui.chat.only-paste-template").toBool())
		PsiOptions::instance()->setOption("options.ui.chat.only-paste-template", false);
	else
		PsiOptions::instance()->setOption("options.ui.chat.only-paste-template", true);
}

void SendButtonTemplatesMenu::optionChanged(const QString& option)
{
	if (option == "options.ui.chat.disable-paste-send") {
		updatePsAction();
	} else if (option == "options.ui.chat.css") {
		setStyleSheet(PsiOptions::instance()->getOption("options.ui.chat.css").toString());
	//} else if (option == "options.ui.chat.only-paste-template") {
	//	onlyPaste->setChecked(PsiOptions::instance()->getOption("options.ui.chat.only-paste-template").toBool());
	}
}

QString SendButtonTemplatesMenu::addSlashes(QString str)
{
	return str.replace("\\", "\\\\", Qt::CaseSensitive).replace("/", "\\/");
}

QString SendButtonTemplatesMenu::stripSlashes(QString str)
{
	return str.replace("\\/", "/").replace("\\\\", "\\");
}
