//SPDX-License-Identifier: GPL-3.0-or-later
/*****************************************************************************/
/*  Copyright 2021 Avalanche Warning Service Tyrol                LWD-TIROL  */
/*****************************************************************************/
/* This file is part of INIshell.
   INIshell 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, either version 3 of the License, or
   (at your option) any later version.

   INIshell 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.

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

#include <src/panels/Copytext.h>
#include <src/main/colors.h>
#include <src/main/common.h>
#include <src/main/constants.h>
#include <src/main/inishell.h>

#include <QClipboard>
#include <QFontMetrics>
#include <QHBoxLayout>
#include <QScrollBar>
#include <QTextEdit>
#include <QVBoxLayout>

#ifdef DEBUG
	#include <iostream>
#endif //def DEBUG

/**
 * @class Copytext
 * @brief Default constructor for a Copytext.
 * @details A Copytext is used to display text that is meant to be re-used.
 * @param[in] section unused
 * @param[in] key unused
 * @param[in] options XML node responsible for this panel with all options and children.
 * @param[in] no_spacers Keep a tight layout for this panel.
 * @param[in] parent The parent widget.
 */
Copytext::Copytext(const QString &section, const QString &key, const QDomNode &options, const bool &no_spacers,
	QWidget *parent) : Atomic(section, key, parent)
{
	this->setProperty("no_ini", true); //so far only used to display text, does not contribute to INI

	clear_timer = new QTimer(this); //for temporary info messages
	clear_timer->setSingleShot(true);
	clear_timer->setInterval(Cst::msg_short_length);
	connect(clear_timer, &QTimer::timeout, this, [=]{
		if (copy_label_)
			copy_label_->setText(QString());
		else
			copy_button_->setStyleSheet(QString());
	});

	/* text box */
	bool success;
	const int height = options.toElement().attribute("height").toInt(&success);
	const bool is_onliner = success && (height == 1); //the Copytext displays a single line
	textbox_ = new QTextEdit;
	textbox_->setReadOnly(true);
	textbox_->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
	const QString size( options.toElement().attribute("size") ); //width of text box (analogous Textfield)

	textbox_->setMinimumWidth(Cst::tiny);
	if (is_onliner) { //size settings only available for single line texts
		if (size.toLower() == "small")
			textbox_->setFixedWidth(Cst::width_copytext_min);
		else if (size.toLower() != "large") //default:medium
			textbox_->setFixedWidth(Cst::width_copytext_medium);
	}

	/* action button */
	copy_button_ = new QToolButton(); //a button to copy the whole text
	copy_button_->setAutoRaise(true);
	copy_button_->setIcon(getIcon("edit-copy"));
	copy_button_->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
	connect(copy_button_, &QToolButton::clicked, this, &Copytext::onCopyButtonClicked);

	/* layouts */
	auto *main_layout (new QHBoxLayout);
	if (is_onliner) {
		main_layout->addWidget(textbox_);
		main_layout->addWidget(copy_button_);
		if (!no_spacers && size.toLower() != "large") //"large": text box extends to window width
			main_layout->addSpacerItem(buildSpacer()); //keep widgets to the left
	} else {
		auto *copy_button_layout( new QHBoxLayout );
		copy_label_ = new QLabel; //create info label
		copy_label_->setStyleSheet("color:" + colors::getQColor("info").name() + ";");
		copy_button_layout->addWidget(copy_label_, 10, Qt::AlignLeft);
		copy_button_layout->addWidget(copy_button_, 1, Qt::AlignRight);
		auto *copytext_layout( new QVBoxLayout );
		copytext_layout->addWidget(textbox_);
		copytext_layout->addLayout(copy_button_layout);
		main_layout->addLayout(copytext_layout);
	}

	setLayoutMargins(main_layout);
	addHelp(main_layout, options, no_spacers);
	this->setLayout(main_layout);
	setOptions(options);
}

/**
 * @brief Default destructor.
 */
Copytext::~Copytext()
{
	if (xml_highlighter_)
		delete xml_highlighter_;
	if (ini_highlighter_)
		delete ini_highlighter_;
}

/**
 * @brief Parse options for a Copytext from XML.
 * @param[in] options XML node holding the Copytext.
 */
void Copytext::setOptions(const QDomNode &options)
{
	if (options.toElement().attribute("wrap").toLower() != "true") //default: don't wrap (like a Helptext)
		textbox_->setLineWrapMode(QTextEdit::NoWrap);
	//the display text is queried from a <text> child node:
	textbox_->setPlainText(options.firstChildElement("text").toElement().text());

	/* choose height of text box */
	int box_height = 5; //default: display 5 lines
	const QString height_option( options.toElement().attribute("height") );
	if (!height_option.isNull()) {
		bool success;
		const int height = height_option.toInt(&success);
		if (success)
			box_height = height;
		else
			topLog(tr(R"(XML error: Could not parse height for some "Copytext" panel (must be integral))"), "error");
	}
	QFont sz_font(textbox_->font());
	if (!options.toElement().attribute("syntax").isNull())
		sz_font.setWeight(QFont::Bold); //there could be bold lines --> use this height
	const int font_height = QFontMetrics(textbox_->font()).lineSpacing() + 1; //height of one line of text
	//check if the scrollbar is visible (it is always there), and if yes, add its height:
	QScrollBar *scrollbar = textbox_->horizontalScrollBar();
	const int slider_offset = scrollbar->isVisibleTo(textbox_)? scrollbar->height() : 0; //TODO: not ideal, will give false positives

	textbox_->setFixedHeight(box_height*font_height + Cst::copytext_safety_padding + slider_offset);

	if (options.toElement().attribute("syntax").toLower() == "xml") {
		xml_highlighter_ = new XMLSyntaxHighlighter(textbox_->document()); //start XML syntax highlighting
	} else if (options.toElement().attribute("syntax").toLower() == "ini") {
		ini_highlighter_ = new INISyntaxHighlighter(textbox_->document()); //INI syntax highlighting
		textbox_->setStyleSheet("QTextEdit {background-color: " + colors::getQColor("syntax_background").name() +
			"; color: " + colors::getQColor("syntax_invalid").name() + "}");
	}
}

/**
 * @brief Event listener for the action button.
 * @details The button is used to copy the whole text.
 */
void Copytext::onCopyButtonClicked() //for now this button only pops up for coordinates
{
	QClipboard *clipboard = QGuiApplication::clipboard();
	clipboard->setText(textbox_->toPlainText());
	if (copy_label_)
		copy_label_->setText(tr("Copied to clipboard"));
	else
		copy_button_->setStyleSheet("QToolButton {background-color: " + colors::getQColor("sl_green").name() + "}");
	clear_timer->stop();
	clear_timer->start();
}
