/*
 *   File name: kfeedback.h
 *   Summary: User feedback form and mailing utilities
 *   License: LGPL - See file COPYING.LIB for details.
 *   Author: Stefan Hundhammer <sh@suse.de>
 *   Author: Christoph Thielecke <crissi99@gmx.de>
 *   Updated: 2009-08-26 (rewrite to plain kde4)
 */

#ifndef KFeedback_h
#define KFeedback_h

#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QRadioButton>
#include <QObject>

#include <kdialog.h>
#include <kvbox.h>

class KFeedbackForm;
class KFeedbackQuestionList;
class KFeedbackQuestion;
class KFeedbackAnswer;
class QTextEdit;



/**
 * Dialog containing a @ref KFeedbackForm and all the infrastructure for
 * sending a mail etc.
 **/
class KFeedbackDialog: public KDialog
{
    Q_OBJECT

public:

    /**
     * Constructor.
     **/
    KFeedbackDialog(const QString & feedbackMailAddress,
                    const QString & helpTopic = QString::null);

    /**
     * Destructor.
     **/
    virtual ~KFeedbackDialog();

    /**
     * Returns the internal @KFeedbackForm
     **/
    KFeedbackForm *form() {
        return _form;
    }

public slots:

    /**
     * Check if sufficient information is available to send a mail now and
     * enable / disable the "send mail" button accordingly.
     **/
    void checkSendButton();

Q_SIGNALS:
    /**
     * Emitted when the user has sent the feedback mail - i.e. when he clicked
     * on the "Send mail" button and the mail has successfully been forwarded
     * to the mailer. He can still choose not to send the mail from within the
     * mailer, though.
     **/
    void mailSent();

protected:

    KFeedbackForm * _form;
};

/**
 * User feedback form:
 *
 * User is asked a list of questions, the answers of which will be sent via
 * mail back to a feedback mail address.
 **/
class KFeedbackForm: public KVBox
{
    Q_OBJECT

public:
    /**
     * Constructor.
     **/
    KFeedbackForm(const QString & feedbackMailAddress,
                  QWidget *  parent);

    /**
     * Destructor.
     **/
    virtual ~KFeedbackForm();

public Q_SLOTS:

    /**
     * Compose a mail from the user's answers and send it to the feedback mail
     * address passed to the constructor.
     *
     * This method will check with @ref readyToSend() if the mail can be sent
     * with the questions answered until now and prompt the user to answer more
     * questions if not.
     *
     * Connect the @ref mailSent() signal if you are interested when exactly
     * all this was successful.
     **/
    virtual void sendMail();

public:

    /**
     * Checks if the mail is ready to send, i.e. if all required fields are
     * filled.
     **/
    virtual bool readyToSend();

    /**
     * Returns the @ref KFeedbackQuestionList .
     **/
    KFeedbackQuestionList * questionList() {
        return _questionList;
    }

Q_SIGNALS:
    /**
     * Emitted when the user has sent the feedback mail - i.e. when he clicked
     * on the "Send mail" button and the mail has successfully been forwarded
     * to the mailer. He can still choose not to send the mail from within the
     * mailer, though.
     **/
    void mailSent();

    /**
     * Emitted when it is time to check for completeness of all information in
     * this form: Either when a new question is added or when a question is
     * answered.
     **/
    void checkComplete();

protected Q_SLOTS:
    /**
     * Check for completeness of this form.
     **/
    void slotCheckComplete();

protected:

    /**
     * Format the "personal comments" field for sending mail.
     **/
    QString formatComment();

    QString   _feedbackMailAddress;
    KFeedbackQuestionList * _questionList;
    QTextEdit *  _comment;
};

/**
 * List of feedback questions presented in a @ref QListView widget.
 **/
class KFeedbackQuestionList: public QTreeWidget
{
    Q_OBJECT

public:

    /**
     * Constructor.
     **/
    KFeedbackQuestionList(QWidget *parent);

    /**
     * Destructor.
     **/
    virtual ~KFeedbackQuestionList();

    /**
     * Returns whether or not this question list is answered satisfactorily,
     * i.e. if all questions marked as "required" are answered.
     **/
    virtual bool isComplete();

    /**
     * The result of all answered questions in ASCII.
     **/
    QString result();

    /**
     * Add a yes/no question to the list.
     *
     * 'text' is the text the user will see (in his native language).
     *
     * 'id' is what will be sent with the feedback mail, thus it should be
     * unique within the application, yet human readable (preferably English)
     * and not contain any weird characters that might confuse scripts that are
     * later used to automatically parse those mails.
     * Examples: "would_recommend_to_a_friend"
     *
     * Set 'required' to 'true' if answering this question is required to
     * successfully complete this form.
     *
     * Returns a pointer to this question so you can add answers.
     **/
    KFeedbackQuestion * addQuestion(const QString &  text,
                                    const QString & id,
                                    bool  exclusiveAnswer = true,
                                    bool   required = false);

    /**
     * Add a yes/no question to the list.
     **/
    void addYesNoQuestion(const QString &  text,
                          const QString & id,
                          bool   required = false);

    /**
     * Notify the list that another question has been answered.
     * Emits the @ref checkComplete() signal when all required questions are
     * answered.
     **/
    void questionAnswered();

    /**
     * Notify the list that another question has been added.
     * Emits the @ref checkComplete() signal when a required question is
     * added.
     **/
    void questionAdded(KFeedbackQuestion * question);
	
	public:
		int currentAnswerIdx;

Q_SIGNALS:
    /**
     * Emitted when all required questions are answered.
     **/
    void checkComplete();
};

/**
 * A user feedback question to be inserted into a @ref KFeedbackQuestionList.
 **/
class KFeedbackQuestion: public QObject, public QTreeWidgetItem
{
	Q_OBJECT
	public:

		/**
		* Constructor.
		*
		* The parent @ref KFeedbackQuestionList assumes ownership of this object,
		* so don't delete it unless you want to delete it from the question list
		* as well.
		*
		* 'text' is the text the user will see (in his native language).
		*
		* 'id' is what will be sent with the feedback mail, thus it should be
		* unique within the application, yet human readable (preferably English)
		* and not contain any weird characters that might confuse scripts that are
		* later used to automatically parse those mails.
		* Examples: "features_not_liked", "stability"
		*
		* Set 'required' to 'true' if answering this question is required to
		* successfully complete this form.
		*
		* Set 'exclusiveAnswer' to 'true' if only one of all answers may be
		* checked at any one time, to 'false' if multiple answers are allowed.
		**/
		KFeedbackQuestion(KFeedbackQuestionList * parent,
						const QString &   text,
						const QString &  id,
						bool   exclusiveAnswer = true,
						bool   required = false,
						bool   open  = true);

		/**
		* Add an answer to this question. Again, 'text' is what the user will see
		* (translated to his native language), 'id' is what you will get back with
		* the mail. The answer IDs need only be unique for that question; answers
		* to other questions may have the same ID.
		**/
		void addAnswer(const QString & text,
					const QString & id);

		/**
		* Returns if answering this question is required.
		**/
		bool isRequired() {
			return _required;
		}

		/**
		* Returns if this question is answered satisfactorily.
		**/
		bool isAnswered();

		/**
		* The result of this question in ASCII, e.g.
		*  recommend="yes"
		* or
		*  features_i_like="builtin_tetris"
		*  features_i_like="pink_elephant"
		*  features_i_like="studlycapslyfier"
		**/
		QString result();

		/**
		* Return this question's ID.
		**/
		QString id() {
			return _id;
		}

		/**
		* Return this question's text.
		**/
		QString text();

		/**
		* Returns whether or not this question requires an exclusive answer.
		**/
		bool exclusiveAnswer();

		/**
		* Returns the first possible answer to this question.
		* Use @ref KFeedbackAnswer::nextAnswer() to get the next one.
		**/
		KFeedbackAnswer * firstAnswer();

		/**
		* Returns the @ref KFeedbackQuestionList this question belongs to or 0 if
		* the parent is no @ref KFeedbackQuestionList.
		**/
		KFeedbackQuestionList * questionList() const;

	protected:
		QString _id;
		bool _exclusiveAnswer;
		bool _required;
		int  _no;
		KFeedbackQuestionList *parentTreeWidget;
		QString _text;
	public:
		int currentAnswerIdx;

	protected slots:
		void radioSelectionChanged(bool state);
	
};

class KFeedbackAnswer: public QTreeWidgetItem
{
public:

    /**
     * Constructor.
     *
     * 'exclusive' tells the type of answer: One of many allowed or any number
     * of many.
     **/
    KFeedbackAnswer(KFeedbackQuestion *  parent,
                    const QString &  text,
                    const QString &  id,
                    bool   exclusive = true);

    /**
     * Return this answer's ID.
     **/
    QString id() {
        return _id;
    }

    /**
     * Return this answer's text.
     **/
    QString text();

    /**
     * Returns whether or not this is an exclusive answer.
     **/
    bool isExclusive() {
        return _exclusive;
    }

    /**
     * Returns whether or not this answer is checked.
     **/
    bool isChecked() {
		QRadioButton *testButton = dynamic_cast<QRadioButton *>(treeWidget()->itemWidget(this,0));
		return testButton->isChecked();
    }

    /**
     * Returns the question to this answer.
     **/
    KFeedbackQuestion * question() const {
		return (KFeedbackQuestion *) QTreeWidgetItem::parent();
    }


protected:
    QString _id;
    bool _exclusive;
    int  _no;
};

#endif // KFeedback_h
