/*****************************************************************************
 *   File name: kfeedback.cpp                                                *
 *   Summary: User feedback form                                             *
 *   License: LGPL - See file COPYING.LIB for details.                       *
 *   Author: Stefan Hundhammer <sh@suse.de>                                  *
 *   Author: Christoph Thielecke <crissi99@gmx.de>                           *
 *                                                                           *
 *   Updated: 2009-08-26                                                     *
 *****************************************************************************/

#include "kfeedback.h"

#include <QVBoxLayout>

#include <QTextEdit>
#include <QRadioButton>
#include <QtGui/QLabel>
#include <QtGui/QLayout>
#include <QHeaderView>

#include <kaboutdata.h>
#include <kapplication.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <klocale.h>
#include <ktoolinvocation.h>
#include <kurl.h>
#include <kvbox.h>
#include <kpushbutton.h>

KFeedbackDialog::KFeedbackDialog(const QString & feedbackMailAddress, const QString & helpTopic)
{
    QWidget *page = new QWidget();
    QVBoxLayout * layout = new QVBoxLayout(page);

    if (! helpTopic.isEmpty())
        setHelp(helpTopic);

    _form = new KFeedbackForm(feedbackMailAddress, 0);
    Q_CHECK_PTR(_form);

    layout->addWidget(_form);
    //checkSendButton();

    connect(this,  SIGNAL(okClicked()),
            _form, SLOT(sendMail()));

    connect(_form, SIGNAL(mailSent()),
            this,  SLOT(hide()));

    connect(_form, SIGNAL(mailSent()),
            this,  SIGNAL(mailSent()));

    connect(_form, SIGNAL(checkComplete()),
            this,  SLOT(checkSendButton()));

    setMainWidget(page);
	setButtons( KDialog::Ok | KDialog::Cancel );
	setButtonText(KDialog::Ok, i18n("&Mail this..."));
	button(KDialog::Ok)->setEnabled(false);
}


KFeedbackDialog::~KFeedbackDialog()
{
    // NOP
}


void KFeedbackDialog::checkSendButton()
{
	bool readyToSend = _form->readyToSend();
	button(KDialog::Ok)->setEnabled(readyToSend);
}


KFeedbackForm::KFeedbackForm(const QString & feedbackMailAddress,
                             QWidget *  parent)
        : KVBox(parent)
        , _feedbackMailAddress(feedbackMailAddress)
{
    //
    // Explanation above the question list
    //

    QLabel * label = new QLabel(i18n("<p><b>Please tell us your opinion about this program.</b></p>"
                                     "<p>You will be able to review everything in your mailer "
                                     "before any mail is sent.<br/>"
                                     "Nothing will be sent behind your back.</p>"
                                    ), this);
    //
    // Question list
    //

    _questionList = new KFeedbackQuestionList(this);
    Q_CHECK_PTR(_questionList);

    connect(_questionList, SIGNAL(checkComplete()),
            this,     SLOT(slotCheckComplete()));


    //
    // Explanation below the question list
    //

    KHBox * hbox = new KHBox(this);
    Q_CHECK_PTR(hbox);

    QSizePolicy pol(QSizePolicy::Fixed, QSizePolicy::Fixed);   // hor / vert

    label = new QLabel(i18n("Questions marked with "), hbox);
    Q_CHECK_PTR(label);
    label->setSizePolicy(pol);

    label = new QLabel(hbox);
    Q_CHECK_PTR(label);
    label->setPixmap(KIconLoader().loadIcon(QString("dialog-information"), KIconLoader::Small));
    label->setSizePolicy(pol);

    label = new QLabel(i18n(" must be answered before a mail can be sent.") , hbox);
    Q_CHECK_PTR(label);
    label->setSizePolicy(pol);

    new QWidget(hbox);   // Fill any leftover space to the right.


    //
    // Free-text comment field
    //

    label = new QLabel("\n" + i18n("&Additional Comments:"), this); Q_CHECK_PTR(label);
    _comment = new QTextEdit(this);    Q_CHECK_PTR(_comment);

    label->setBuddy(_comment);
#if (QT_VERSION < 300)
    _comment->setFixedVisibleLines(5);
#endif
    _comment->setLineWrapMode(QTextEdit::FixedColumnWidth);
    _comment->setLineWrapColumnOrWidth(70);
}


KFeedbackForm::~KFeedbackForm()
{
    // NOP
}


void KFeedbackForm::sendMail()
{
    //
    // Build mail subject
    //

    QString subject;

    const KAboutData * aboutData = KGlobal::mainComponent().aboutData();

    if (aboutData)
        subject = aboutData->programName() + "-" + aboutData->version();
    else
        subject = kapp->objectName();

    subject = "[kde-feedback] " + subject + " user feedback";


    //
    // Build mail body
    //

    QString body = subject + "\n\n" + formatComment() + _questionList->result();


    //
    // Build "mailto:" URL from all this
    //

    KUrl mail;
    mail.setProtocol("mailto");
    mail.setPath(_feedbackMailAddress);
    mail.setQuery("?subject=" + QUrl::toPercentEncoding(subject) + "&body=" + QUrl::toPercentEncoding(body));

    // TODO: Check for maximum command line length.
    //
    // The hard part with this is how to get this from all that 'autoconf'
    // stuff into 'config.h' or some other include file without hardcoding
    // anything - this is too system dependent.


    //
    // Actually send mail
    //

    KToolInvocation::invokeMailer(mail);

    emit mailSent();
}


void KFeedbackForm::slotCheckComplete(){
    emit checkComplete();
}


QString KFeedbackForm::formatComment()
{
    QString result = _comment->toPlainText();

    if (! result.isEmpty()) {
        result = "<comment>\n" + result + "\n</comment>\n\n";
    }

    return result;
}


bool KFeedbackForm::readyToSend()
{
    return _questionList->isComplete();
}


KFeedbackQuestionList::KFeedbackQuestionList(QWidget *parent)
        : QTreeWidget(parent)
{
        setColumnCount(2);
        header()->hide();
}


KFeedbackQuestionList::~KFeedbackQuestionList()
{
    // NOP
}


bool KFeedbackQuestionList::isComplete()
{
    for (int i=0;i< topLevelItemCount(); i++) {
		KFeedbackQuestion *question = dynamic_cast<KFeedbackQuestion *>(topLevelItem(i));
        if (question->isRequired() && ! question->isAnswered()) {
			//qDebug(qPrintable("question not answered: "+QString(question->text())));
            return false;
		}
		//qDebug(qPrintable(QString("question answered, going to next question: ")));
    }
	//qDebug(qPrintable(QString("isComplete(): yes")));
    return true;
}


QString KFeedbackQuestionList::result()
{
    QString res;
	for (int i=0;i< topLevelItemCount(); i++) {
		KFeedbackQuestion *question = dynamic_cast<KFeedbackQuestion *>(topLevelItem(i));
        res += question->result();
    }

    return res;
}


KFeedbackQuestion * KFeedbackQuestionList::addQuestion(const QString &  text,
                                   const QString & id,
                                   bool  exclusiveAnswer,
                                   bool   required)
{
    KFeedbackQuestion * question = new KFeedbackQuestion(this, text, id,
            exclusiveAnswer,
            required);
    Q_CHECK_PTR(question);

    addTopLevelItem(question);
// 	question->setExpanded(required);
	question->setExpanded(true);
	question->setData(1, Qt::FontRole, QFont().bold());
	//qDebug(qPrintable("KFeedbackQuestionList::addQuestion child count: "+QString().setNum(question->QTreeWidgetItem::childCount())));
    return question;
}


void KFeedbackQuestionList::addYesNoQuestion(const QString &  text,
                                        const QString & id,
                                        bool   required)
{

    KFeedbackQuestion * question = new KFeedbackQuestion(this, text, id,
            true, // exclusive
            required);
    Q_CHECK_PTR(question);
    question->addAnswer(i18n("yes"), "yes");
    question->addAnswer(i18n("no"), "no");
}


void KFeedbackQuestionList::questionAnswered()
{
    emit checkComplete();
}

void KFeedbackQuestionList::questionAdded(KFeedbackQuestion * question)
{
	// FIXME crashes if enabled
    //if (question->isRequired())
    //    emit checkComplete();
}


static int nextNo = 0;

KFeedbackQuestion::KFeedbackQuestion(KFeedbackQuestionList * parentTreeWidget,
                                     const QString &   text,
                                     const QString &  id,
                                     bool   exclusiveAnswer,
                                     bool   required,
                                     bool   open)
	: QTreeWidgetItem()
{
	this->parentTreeWidget = parentTreeWidget;
    if (required) {
		QTreeWidgetItem::setIcon(0, KIconLoader().loadIcon(QString("dialog-information"), KIconLoader::Small));
    }

	QTreeWidgetItem::setText(1, text);

	setExpanded(required);
    _no = nextNo++;
	this->_text = text;
	this->_id = id;
	this->_required = required;

    parentTreeWidget->questionAdded(this);
}


void KFeedbackQuestion::addAnswer(const QString & text,
                             const QString & id)
{
	//qDebug(qPrintable("KFeedbackQuestion::addAnswer()  (1) child count: "+QString().setNum(QTreeWidgetItem::childCount())));
    KFeedbackAnswer *item = new KFeedbackAnswer(this, text, id, _exclusiveAnswer);
    item->setText(1, text);
    item->setFlags( Qt::ItemIsEnabled);
	QTreeWidgetItem::addChild(item);
	QRadioButton *radioButton = new QRadioButton(0);
	
	radioButton->setAutoExclusive(false);
    parentTreeWidget->setItemWidget(item, 0, radioButton);
	
	if (!_exclusiveAnswer) 
		item->setIcon(0, KIconLoader().loadIcon(QString("format-list-unordered"), KIconLoader::Small));
		
	connect(radioButton, SIGNAL(clicked(bool)), this , SLOT(radioSelectionChanged(bool)));
	//qDebug(qPrintable("KFeedbackQuestion::addAnswer()  (2) child count: "+QString().setNum(QTreeWidgetItem::childCount())));
}


bool KFeedbackQuestion::isAnswered()
{
	if (QTreeWidgetItem::childCount() == 0) {
		//qDebug(qPrintable(QString("KFeedbackQuestion::isAnswered() has no childs, finished")));
		return true;
	}
	
	if (! _exclusiveAnswer ) {
        /**
         * If any number of answers is permitted for this question, this
         * question is always considered to be answered.
         **/
		//qDebug("answer is not exclusive => answered.");
        return true;
    }
	
	if ( _required) {

		/**
		* If this question requires an exclusive answer, exactly one of them
		* should be checked. We don't need to bother about more than one being
		* checked here - QListView does that for us.
		**/
		
		for (int i=0; i< QTreeWidgetItem::childCount(); i++) {
			KFeedbackAnswer *answer = dynamic_cast<KFeedbackAnswer *>(QTreeWidgetItem::child(i));
			//qDebug(qPrintable("checking answer:"+text()));
			QRadioButton *testRadioButton = dynamic_cast<QRadioButton *>(treeWidget()->itemWidget(answer,0));
			if (testRadioButton->isChecked()) {
				//qDebug(qPrintable("answer is answered:"+text()));
				return true;
			}
			else {
				//qDebug(qPrintable(QString("answer is not answered, going to next answer:"+text())));
			}
		}
		//qDebug(qPrintable(QString("question is not answered: "+text())));
		return false;
	} else {
		//qDebug("answer is not required => answered.");
		return true;
	}
}

QString KFeedbackQuestion::result()
{
    QString res;
    int answers = 0;

	for (int i=0; i< QTreeWidgetItem::childCount(); i++) {
		KFeedbackAnswer *answer = dynamic_cast<KFeedbackAnswer *>(QTreeWidgetItem::child(i));
        if (answer->isChecked()) {
            res += _id + "=\"" + answer->id() + "\"\n";
            answers++;
        }
    }

    if (answers > 1) {
        res = "\n" + res + "\n";
    }

    return res;
}


QString KFeedbackQuestion::text()
{
	return QTreeWidgetItem::text(1);
}


KFeedbackQuestionList * KFeedbackQuestion::questionList() const
{
	return dynamic_cast<KFeedbackQuestionList *>(treeWidget());
}


void KFeedbackQuestion::radioSelectionChanged(bool checked)
{
	QRadioButton *senderButton = dynamic_cast<QRadioButton *>(QObject::sender());
	bool otherChecked=false;
	if (_exclusiveAnswer) {
		for (int i=0; i < childCount();i++) {
			QRadioButton *testButton = dynamic_cast<QRadioButton *>(treeWidget()->itemWidget(QTreeWidgetItem::child(i),0));
			if (testButton != senderButton) {
				if (testButton != 0L)
					testButton->setChecked(false);
			}
				else {
					if (testButton != 0L) {
						if (!checked) {
							for (int j=0; j < childCount();j++) {
								QRadioButton *testButton2 = dynamic_cast<QRadioButton *>(treeWidget()->itemWidget(QTreeWidgetItem::child(j),0));
								if (testButton2->isChecked() && testButton2 != senderButton) {
										otherChecked = true;
										break;
								}
							}
							if (otherChecked) {
								testButton->setChecked(false);
								//qDebug("checked");
							}
							else {
									//qDebug("no other radion checked, do nothing.");
									testButton->setChecked(true);
							}
						}
						else {
							testButton->setChecked(true);
							//qDebug("unchecked");
						}
					}
				}
		}
	}
	questionList()->questionAnswered();
}

bool KFeedbackQuestion::exclusiveAnswer() {
	return _exclusiveAnswer;
}

KFeedbackAnswer* KFeedbackQuestion::firstAnswer() {
	KFeedbackAnswer *item = (KFeedbackAnswer *) QTreeWidgetItem::child(0);
	return item;
}

KFeedbackAnswer::KFeedbackAnswer(KFeedbackQuestion *  parent,
                                 const QString & text,
                                 const QString & id,
                                 bool   exclusive)
	: QTreeWidgetItem()
{
    _no = nextNo++;
	this->_id = id;
	
}


QString KFeedbackAnswer::text()
{
	return QTreeWidgetItem::text(1);
}

// EOF
