/*
 * export a KEduVocDocument to a KVTML file
 * SPDX-FileCopyrightText: 2007 Jeremy Whiting <jpwhiting@kde.org>
 * SPDX-FileCopyrightText: 2007-2010 Frederik Gladhorn <gladhorn@kde.org>
 * SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "keduvockvtml2writer.h"

#include <QTextStream>

#include <QDir>
#include <QDebug>

#include "keduvocdocument.h"
#include "keduvocexpression.h"
#include "keduvoclesson.h"
#include "keduvocleitnerbox.h"
#include "keduvocwordtype.h"
#include "kvtml2defs.h"
#include <kio/global.h>

KEduVocKvtml2Writer::KEduVocKvtml2Writer( QFile *file )
{
    // the file must be already open
    m_outputFile = file;
}

bool KEduVocKvtml2Writer::writeDoc( KEduVocDocument *doc, const QString &generator )
{
    if (createXmlDocument(doc, generator)) {
        QTextStream ts( m_outputFile );
        m_domDoc.save( ts, 2 );
        return true;
    }
    return false;
}

QByteArray KEduVocKvtml2Writer::toByteArray(KEduVocDocument * doc, const QString & generator)
{
    if (createXmlDocument(doc, generator)) {
        return m_domDoc.toByteArray();
    }
    return QByteArray();
}

bool KEduVocKvtml2Writer::createXmlDocument( KEduVocDocument *doc, const QString &generator )
{
    m_doc = doc;

    m_domDoc = QDomDocument( QStringLiteral("kvtml PUBLIC \"kvtml2.dtd\" \"http://edu.kde.org/kvtml/kvtml2.dtd\"") );
    m_domDoc.appendChild( m_domDoc.createProcessingInstruction( QStringLiteral("xml"), QStringLiteral("version=\"1.0\" encoding=\"UTF-8\"") ) );
    QDomElement domElementKvtml = m_domDoc.createElement( QStringLiteral("kvtml") );
    m_domDoc.appendChild( domElementKvtml );

    domElementKvtml.setAttribute( KVTML_VERSION, ( QString ) QStringLiteral("2.0") );

    // information group
    QDomElement currentElement = m_domDoc.createElement( KVTML_INFORMATION );
    writeInformation( currentElement, generator );
    domElementKvtml.appendChild( currentElement );

    // identifiers
    currentElement = m_domDoc.createElement( KVTML_IDENTIFIERS );
    writeIdentifiers( currentElement );
    domElementKvtml.appendChild( currentElement );

    // entries
    currentElement = m_domDoc.createElement( KVTML_ENTRIES );
    if ( !writeEntries( currentElement ) ) {
        // at least one entry is required!
        return false;
    }
    domElementKvtml.appendChild( currentElement );

    // lessons
    currentElement = m_domDoc.createElement( KVTML_LESSONS );
    writeLessons( m_doc->lesson(), currentElement );
    if ( currentElement.hasChildNodes() ) {
        domElementKvtml.appendChild( currentElement );
    }

    // types
    currentElement = m_domDoc.createElement( KVTML_WORDTYPES );
    writeWordTypes( currentElement, m_doc->wordTypeContainer() );
    if ( currentElement.hasChildNodes() ) {
        domElementKvtml.appendChild( currentElement );
    }

    // leitner boxes
    currentElement = m_domDoc.createElement( KVTML_LEITNERBOXES );
    writeLeitnerBoxes( currentElement, m_doc->leitnerContainer() );
    if ( currentElement.hasChildNodes() ) {
        domElementKvtml.appendChild( currentElement );
    }

    writeSynonymAntonymFalseFriend(domElementKvtml);

    m_domDoc.appendChild( domElementKvtml );

    return true;
}

bool KEduVocKvtml2Writer::writeInformation( QDomElement &informationElement, const QString &generator )
{
    QDomElement currentElement;
    QDomText textNode;

    // generator
    informationElement.appendChild( newTextElement( KVTML_GENERATOR, generator ) );

    // title
    if ( !m_doc->title().isEmpty() ) {
        informationElement.appendChild( newTextElement( KVTML_TITLE, m_doc->title() ) );
    }

    // author
    if ( !m_doc->author().isEmpty() ) {
        informationElement.appendChild( newTextElement( KVTML_AUTHOR, m_doc->author() ) );
    }

    // author contact (mail/homepage)
    if ( !m_doc->authorContact().isEmpty() ) {
        informationElement.appendChild( newTextElement( KVTML_AUTHORCONTACT, m_doc->authorContact() ) );
    }

    // license
    if ( !m_doc->license().isEmpty() ) {
        informationElement.appendChild( newTextElement( KVTML_LICENSE, m_doc->license() ) );
    }

    // comment
    if ( !m_doc->documentComment().isEmpty() ) {
        informationElement.appendChild( newTextElement( KVTML_COMMENT, m_doc->documentComment() ) );
    }

    QDate today = QDate::currentDate();
    informationElement.appendChild( newTextElement( KVTML_DATE, today.toString(QStringLiteral("yyyy-MM-dd")) ) );

    // category
    if ( !m_doc->category().isEmpty() ) {
        informationElement.appendChild( newTextElement( KVTML_CATEGORY, m_doc->category() ) );
    }

    return true;
}


bool KEduVocKvtml2Writer::writeIdentifiers( QDomElement &identifiersElement )
{
    for ( int i = 0; i < m_doc->identifierCount(); ++i ) {
        // create the node
        QDomElement identifier = m_domDoc.createElement( KVTML_IDENTIFIER );

        // set the id
        identifier.setAttribute( KVTML_ID, QString::number( i ) );

        // record the identifier as the locale for now
        // TODO: when support for more parts of the identifier is in the document class (name, type, etc.) store those here as well
        identifier.appendChild( newTextElement( KVTML_NAME, m_doc->identifier( i ).name() ) );

        identifier.appendChild( newTextElement( KVTML_LOCALE, m_doc->identifier( i ).locale() ) );

        // record articles
        QDomElement article = m_domDoc.createElement( KVTML_ARTICLE );
        writeArticle( article, i );
        if ( article.hasChildNodes() ) {
            identifier.appendChild( article );
        }

        // record personalpronouns
        QDomElement personalpronouns = m_domDoc.createElement( KVTML_PERSONALPRONOUNS );
        writePersonalPronoun( personalpronouns, m_doc->identifier(i).personalPronouns() );
        if ( personalpronouns.hasChildNodes() ) {
            identifier.appendChild( personalpronouns );
        }

        // tenses
        foreach(const QString &tense, m_doc->identifier(i).tenseList() ) {
            if ( !( tense.isNull() ) ) {
                identifier.appendChild( newTextElement( KVTML_TENSE, tense ) );
            }
        }
        // add this identifier to the group
        identifiersElement.appendChild( identifier );
    }
    return true;
}

bool KEduVocKvtml2Writer::writeLessons( KEduVocLesson *parentLesson, QDomElement &lessonsElement )
{
    // iterate over child lessons.
    // the first time this is called with the root lesson which does not have a <lesson> entry.
    for( int i = 0; i < parentLesson->childContainerCount(); i++ ) {
        KEduVocLesson *lesson = static_cast<KEduVocLesson*>(parentLesson->childContainer(i));
        // make lesson element
        QDomElement thisLessonElement = m_domDoc.createElement( KVTML_CONTAINER );

        // add a name
        thisLessonElement.appendChild( newTextElement( KVTML_NAME, lesson->name() ) );

        // add a inquery tag
        if ( lesson->inPractice() ) {
            thisLessonElement.appendChild( newTextElement( KVTML_INPRACTICE, KVTML_TRUE ) );
        }

        // child lessons
        writeLessons(lesson, thisLessonElement);

        // child entries
        foreach(KEduVocExpression *entry, lesson->entries()) {
            QDomElement entryElement = m_domDoc.createElement( KVTML_ENTRY );
            entryElement.setAttribute( KVTML_ID, QString::number(m_allEntries.indexOf(entry)) );
            thisLessonElement.appendChild(entryElement);
        }
        lessonsElement.appendChild( thisLessonElement );
    }
    return true;
}



void KEduVocKvtml2Writer::writeSynonymAntonymFalseFriend(QDomElement & parentElement)
{
    QList< KEduVocTranslation* > currentList;
    QDomElement synonymElement;
    // synonym, antonym, false friend
    for(int type = KEduVocTranslation::Synonym; type <= KEduVocTranslation::FalseFriend; type++) {
        switch (type) {
            case KEduVocTranslation::Synonym:
                synonymElement = m_domDoc.createElement( KVTML_SYNONYM );
                currentList = m_synonyms;
                break;
            case KEduVocTranslation::Antonym:
                synonymElement = m_domDoc.createElement( KVTML_ANTONYM );
                currentList = m_antonyms;
                break;
            case KEduVocTranslation::FalseFriend:
                synonymElement = m_domDoc.createElement( KVTML_FALSEFRIEND );
                currentList = m_falseFriends;
                break;
        }

        while (!currentList.isEmpty()) {
            // after writing a translation, remove it from the list
            KEduVocTranslation* translation = currentList.takeFirst();


            QDomElement relatedElement;
            QList <KEduVocTranslation*> list;
            switch (type) {
            case KEduVocTranslation::Synonym:
                list = translation->synonyms();
                break;
            case KEduVocTranslation::Antonym:
                list = translation->antonyms();
                break;
            case KEduVocTranslation::FalseFriend:
                list = translation->falseFriends();
                break;
            }
            foreach (KEduVocTranslation* synonym, list) {
                // if it is not in the list it has already been written and we can move on
                if (currentList.contains(synonym)) {
                    relatedElement = m_domDoc.createElement( KVTML_PAIR );

		    // fill the entry element but only add later if it is valid
		    QDomElement entryElement = m_domDoc.createElement( KVTML_ENTRY );
		    entryElement.setAttribute( KVTML_ID, QString::number(m_allEntries.indexOf(translation->entry())) );
		    // find out which id that is... silly
		    foreach(int index, translation->entry()->translationIndices()) {
			if (translation->entry()->translation(index) == translation) {
			    // create <translation id="123">
			    QDomElement translationElement = m_domDoc.createElement( KVTML_TRANSLATION );
			    translationElement.setAttribute( KVTML_ID, QString::number(index) );
			    entryElement.appendChild(translationElement);
			    break;
			}
		    }

                    relatedElement.appendChild(entryElement);


                    QDomElement partnerElement = m_domDoc.createElement( KVTML_ENTRY );
                    partnerElement.setAttribute( KVTML_ID, QString::number(m_allEntries.indexOf(synonym->entry())) );
                    // find out which id that is
                    foreach(int index, synonym->entry()->translationIndices()) {
                        if (synonym->entry()->translation(index) == synonym) {
                            // create <translation id="123">
                            QDomElement translationElement = m_domDoc.createElement( KVTML_TRANSLATION );
                            translationElement.setAttribute( KVTML_ID, QString::number(index) );
                            partnerElement.appendChild(translationElement);
                            break;
                        }
                    }
                    relatedElement.appendChild( partnerElement );
		    synonymElement.appendChild(relatedElement);
                }
            }

        }
        if (synonymElement.hasChildNodes()) {
            parentElement.appendChild( synonymElement );
        }
    } // iterate over types
}
/*
bool KEduVocKvtml2Writer::writeRelated(QDomElement & parentElement, QList< KEduVocTranslation * > relatedList)
{
    foreach (KEduVocTranslation* synonym, translation->synonyms()) {
        QDomElement entryElement = m_domDoc.createElement( KVTML_ENTRY );
        entryElement.setAttribute( KVTML_ID, QString::number(m_allEntries.indexOf(translation->entry())) );

        // find out which id that is... silly
        foreach(int index, translation->entry()->translationIndices()) {
            if (translation->entry()->translation(index) == translation) {
                // create <translation id="123">
                QDomElement translationElement = m_domDoc.createElement( KVTML_TRANSLATION );
                translationElement.setAttribute( KVTML_ID, QString::number(index) );
                entryElement.appendChild(translationElement);
            }
        }
        parentElement.appendChild( entryElement );
    }
}*/

bool KEduVocKvtml2Writer::writeArticle( QDomElement &articleElement, int language )
{
    ///@todo only write if not empty
    QMap<int, KEduVocWordFlag::Flags> numbers;
    numbers[0] = KEduVocWordFlag::Singular;
    numbers[1] = KEduVocWordFlag::Dual;
    numbers[2] = KEduVocWordFlag::Plural;
    QMap<int, KEduVocWordFlag::Flags> genders;
    genders[0] = KEduVocWordFlag::Masculine;
    genders[1] = KEduVocWordFlag::Feminine;
    genders[2] = KEduVocWordFlag::Neuter;
    QMap<int, KEduVocWordFlag::Flags> defs;
    defs[0] = KEduVocWordFlag::Definite;
    defs[1] = KEduVocWordFlag::Indefinite;

    for (int num = 0; num <= 2; num++)
    {
        QDomElement numberElement = m_domDoc.createElement( KVTML_GRAMMATICAL_NUMBER[num] );

        for (int def = 0; def <= 1; def++) {
            QDomElement defElement = m_domDoc.createElement( KVTML_GRAMMATICAL_DEFINITENESS[def] );

            for (int gen = 0; gen <= 2; gen++)
            {
                QString articleString = m_doc->identifier(language).article().article(numbers[num] | genders[gen] | defs[def]);
                if ( !articleString.isEmpty() ) {
                    defElement.appendChild( newTextElement( KVTML_GRAMMATICAL_GENDER[gen], articleString ) );
                }
            }
            if ( defElement.hasChildNodes() ) {
                numberElement.appendChild( defElement );
            }
        }
        if ( numberElement.hasChildNodes() ) {
            articleElement.appendChild( numberElement );
        }
    }
    return true;
}


bool KEduVocKvtml2Writer::writeWordTypes( QDomElement &typesElement, KEduVocWordType* parentContainer )
{
    foreach( KEduVocContainer* container, parentContainer->childContainers() ) {
        KEduVocWordType* wordType = static_cast<KEduVocWordType*>(container);

        QDomElement typeDefinitionElement = m_domDoc.createElement( KVTML_CONTAINER );
        typeDefinitionElement.appendChild( newTextElement( KVTML_NAME, wordType->name() ) );

        if (wordType->wordType().testFlag(KEduVocWordFlag::Noun))
        {
            if (wordType->wordType().testFlag(KEduVocWordFlag::Masculine))
                typeDefinitionElement.appendChild( newTextElement( KVTML_SPECIALWORDTYPE, KVTML_SPECIALWORDTYPE_NOUN_MALE ) );

            else if (wordType->wordType().testFlag(KEduVocWordFlag::Feminine))
                typeDefinitionElement.appendChild( newTextElement( KVTML_SPECIALWORDTYPE, KVTML_SPECIALWORDTYPE_NOUN_FEMALE ) );

            else if (wordType->wordType().testFlag(KEduVocWordFlag::Neuter))
                typeDefinitionElement.appendChild( newTextElement( KVTML_SPECIALWORDTYPE, KVTML_SPECIALWORDTYPE_NOUN_NEUTRAL ) );
            else
                typeDefinitionElement.appendChild( newTextElement( KVTML_SPECIALWORDTYPE, KVTML_SPECIALWORDTYPE_NOUN ) );
        }
        else if (wordType->wordType().testFlag(KEduVocWordFlag::Verb))
            typeDefinitionElement.appendChild( newTextElement( KVTML_SPECIALWORDTYPE, KVTML_SPECIALWORDTYPE_VERB ) );

        else if (wordType->wordType().testFlag(KEduVocWordFlag::Adjective))
            typeDefinitionElement.appendChild( newTextElement( KVTML_SPECIALWORDTYPE, KVTML_SPECIALWORDTYPE_ADJECTIVE ) );

        else if (wordType->wordType().testFlag(KEduVocWordFlag::Adverb))
            typeDefinitionElement.appendChild( newTextElement( KVTML_SPECIALWORDTYPE, KVTML_SPECIALWORDTYPE_ADVERB ) );

        else if (wordType->wordType().testFlag(KEduVocWordFlag::Conjunction))
            typeDefinitionElement.appendChild( newTextElement( KVTML_SPECIALWORDTYPE, KVTML_SPECIALWORDTYPE_CONJUNCTION ) );


// child entries

        // child entries
        foreach(KEduVocExpression *entry, wordType->entries()) {
            QDomElement entryElement = m_domDoc.createElement( KVTML_ENTRY );
            entryElement.setAttribute( KVTML_ID, QString::number(m_allEntries.indexOf(entry)) );
            for(int translation = 0; translation<m_doc->identifierCount(); translation++) {
                if (entry->translation(translation)->wordType()== wordType) {
                    QDomElement translationElement = m_domDoc.createElement( KVTML_TRANSLATION );
                    // create <translation id="123">
                    translationElement.setAttribute( KVTML_ID, QString::number(translation) );
                    // append both
                    entryElement.appendChild(translationElement);
                }
            }
            typeDefinitionElement.appendChild( entryElement );
        }

        writeWordTypes( typeDefinitionElement, wordType );

        typesElement.appendChild( typeDefinitionElement );
    }
    return true;
}

bool KEduVocKvtml2Writer::writeLeitnerBoxes( QDomElement &leitnerParentElement, KEduVocLeitnerBox* parentContainer )
{
    foreach( KEduVocContainer* container, parentContainer->childContainers() ) {
        KEduVocLeitnerBox* leitnerBox = static_cast<KEduVocLeitnerBox*>(container);

        QDomElement containerElement = m_domDoc.createElement( KVTML_CONTAINER );
        containerElement.appendChild( newTextElement( KVTML_NAME, leitnerBox->name() ) );

        // child entries
        foreach(KEduVocExpression *entry, leitnerBox->entries()) {
            QDomElement entryElement = m_domDoc.createElement( KVTML_ENTRY );
            entryElement.setAttribute( KVTML_ID, QString::number(m_allEntries.indexOf(entry)) );
            for(int translation = 0; translation<m_doc->identifierCount(); translation++) {
                if (entry->translation(translation)->leitnerBox()== leitnerBox) {
                    QDomElement translationElement = m_domDoc.createElement( KVTML_TRANSLATION );
                    // create <translation id="123">
                    translationElement.setAttribute( KVTML_ID, QString::number(translation) );
                    // append both
                    entryElement.appendChild(translationElement);
                }
            }
            containerElement.appendChild( entryElement );
        }

        leitnerParentElement.appendChild( containerElement );
    }
    return true;
}

bool KEduVocKvtml2Writer::writeEntries( QDomElement &entriesElement )
{
    m_allEntries = m_doc->lesson()->entries(KEduVocLesson::Recursive);

    // loop through entries
    for ( int i = 0; i < m_allEntries.count(); ++i ) {
        KEduVocExpression *thisEntry = m_allEntries.value(i);

        // write entry tag
        QDomElement entryElement = m_domDoc.createElement( KVTML_ENTRY );

        // add id
        entryElement.setAttribute( KVTML_ID, QString::number( i ) );

        // write deactivated
        if(!thisEntry->isActive()) {
            entryElement.appendChild( newTextElement( KVTML_DEACTIVATED, KVTML_TRUE ) );
        }

        // loop through translations
        foreach( int trans, thisEntry->translationIndices() ) {
            // write translations
            QDomElement translation = m_domDoc.createElement( KVTML_TRANSLATION );
            translation.setAttribute( KVTML_ID, QString::number( trans ) );
            writeTranslation( translation, thisEntry->translation( trans ) );
            entryElement.appendChild( translation );
        }
        // add this entry to the entriesElement
        entriesElement.appendChild( entryElement );
    }
    return true;
}


bool KEduVocKvtml2Writer::writeTranslation( QDomElement &translationElement, KEduVocTranslation* translation )
{
    // so far only for KEduVocWord - text and grades
    translation->toKVTML2(translationElement);

    // comparison
    if ( !(translation->comparativeForm().text().isEmpty() || translation->superlativeForm().text().isEmpty())) {
        qDebug() << "Write comp";
        QDomElement comparisonElement = m_domDoc.createElement( KVTML_COMPARISON );
        translationElement.appendChild(comparisonElement);

        QDomElement comparativeElement = m_domDoc.createElement( KVTML_COMPARATIVE );
        comparisonElement.appendChild(comparativeElement);
        translation->comparativeForm().toKVTML2(comparativeElement);

        QDomElement superlativeElement = m_domDoc.createElement( KVTML_SUPERLATIVE );
        comparisonElement.appendChild(superlativeElement);
        translation->superlativeForm().toKVTML2(superlativeElement);
    }

    if (translation->article().practiceCount() != 0) {
        QDomElement articleElement = m_domDoc.createElement( KVTML_ARTICLE );
        translation->article().toKVTML2(articleElement);
        translationElement.appendChild(articleElement);
    }

    // multiplechoice
    if (!translation->getMultipleChoice().isEmpty()) {
        QDomElement multipleChoiceElement = m_domDoc.createElement( KVTML_MULTIPLECHOICE );
        writeMultipleChoice( multipleChoiceElement, translation );
        translationElement.appendChild( multipleChoiceElement );
    }

    // image
    if ( !translation->imageUrl().isEmpty() ) {
        QString urlString;
        const QUrl docDirUrl = m_doc->url().adjusted(QUrl::RemoveFilename);
        if ( docDirUrl.isParentOf( translation->imageUrl()) ) {
            // try to save as relative url
            const QDir dir( docDirUrl.toLocalFile() );
            urlString = QUrl::fromLocalFile(
                dir.relativeFilePath( translation->imageUrl().toLocalFile() )
            ).url();
        } else {
            urlString =  translation->imageUrl().url();
        }
        translationElement.appendChild( newTextElement( KVTML_IMAGE, urlString ) );
    }

    // sound
    if ( !translation->soundUrl().isEmpty() ) {
        QString urlString;
        const QUrl docDirUrl = m_doc->url().adjusted(QUrl::RemoveFilename);
        if ( docDirUrl.isParentOf( translation->soundUrl()) ) {
            // try to save as relative url
            const QDir dir( docDirUrl.toLocalFile() );
            urlString = QUrl::fromLocalFile(
                dir.relativeFilePath( translation->soundUrl().toLocalFile() )
            ).url();
        } else {
            urlString = translation->soundUrl().url();
        }
        translationElement.appendChild( newTextElement( KVTML_SOUND, urlString ) );
    }


    // synonym, antonym, false friend
    // add to the list if it has any, write later since we want them separate
    if (!translation->synonyms().isEmpty()) {
        m_synonyms.append(translation);
    }
    if (!translation->antonyms().isEmpty()) {
        m_antonyms.append(translation);
    }
    if (!translation->falseFriends().isEmpty()) {
        m_falseFriends.append(translation);
    }
    return true;
}



    ///@todo write false friends
    // <falsefriend fromid="0"></falsefriend>
    // loop through the identifiers
//     for ( int i = 0; i < m_doc->identifierCount(); ++i ) {
//         // see if this identifier has a falsefriend in this translation
//         QString thisFriend = translation->falseFriend( i );
//         if ( !thisFriend.isEmpty() ) {
//             // if so, create it, and set the fromid to i
//             QDomElement thisFriendElement = newTextElement( KVTML_FALSEFRIEND, thisFriend );
//             thisFriendElement.setAttribute( KVTML_FROMID, QString::number( i ) );
//             translationElement.appendChild( thisFriendElement );
//         }
//     }

bool KEduVocKvtml2Writer::writeMultipleChoice( QDomElement &multipleChoiceElement, KEduVocTranslation* translation )
/*
 <multiplechoice>
   <choice>good</choice>
   <choice>better</choice>
   <choice>best</choice>
   <choice>best 2</choice>
   <choice>best 3</choice>
 </multiplechoice>
*/
{
    foreach (const QString &choice, translation->getMultipleChoice()) {
        multipleChoiceElement.appendChild( newTextElement( KVTML_CHOICE, choice ) );
    }
    return true;
}

QDomElement KEduVocKvtml2Writer::newTextElement( const QString &elementName, const QString &text )
{
    QDomElement retval = m_domDoc.createElement( elementName );
    QDomText textNode = m_domDoc.createTextNode( text );
    retval.appendChild( textNode );
    return retval;
}

bool KEduVocKvtml2Writer::writePersonalPronoun(QDomElement & pronounElement, const KEduVocPersonalPronoun & pronoun)
{
    // general pronoun properties
    if ( pronoun.maleFemaleDifferent() ) {
        pronounElement.appendChild( m_domDoc.createElement( KVTML_THIRD_PERSON_MALE_FEMALE_DIFFERENT ) );
    }
    if ( pronoun.neutralExists() ) {
        pronounElement.appendChild( m_domDoc.createElement( KVTML_THIRD_PERSON_NEUTRAL_EXISTS ) );
    }
    if ( pronoun.dualExists() ) {
        pronounElement.appendChild( m_domDoc.createElement( KVTML_DUAL_EXISTS ) );
    }


    QMap<int, KEduVocWordFlag::Flags> numbers;
    numbers[0] = KEduVocWordFlag::Singular;
    numbers[1] = KEduVocWordFlag::Dual;
    numbers[2] = KEduVocWordFlag::Plural;
    QMap<int, KEduVocWordFlag::Flags> persons;
    persons[0] = KEduVocWordFlag::First;
    persons[1] = KEduVocWordFlag::Second;
    persons[2] = (KEduVocWordFlag::Flags)((int)KEduVocWordFlag::Third | (int)KEduVocWordFlag::Masculine);
    persons[3] = (KEduVocWordFlag::Flags)((int)KEduVocWordFlag::Third | (int)KEduVocWordFlag::Feminine);
    persons[4] = (KEduVocWordFlag::Flags)((int)KEduVocWordFlag::Third | (int)KEduVocWordFlag::Neuter);



    // the actual pronouns
    for ( int num = 0; num < 3; num++ ) {
        QDomElement numberElement = m_domDoc.createElement( KVTML_GRAMMATICAL_NUMBER[num] );
        for ( int person = 0; person < 5; person++ ) {
            QString pronounString = pronoun.personalPronoun(numbers[num] | persons[person]);
            if (!pronounString.isEmpty()) {
                numberElement.appendChild( newTextElement( KVTML_GRAMMATICAL_PERSON[person], pronounString ));
            }
        }
        if (numberElement.hasChildNodes()) {
            pronounElement.appendChild( numberElement );
        }
    }
    return true;
}

void KEduVocKvtml2Writer::appendTextElement(QDomElement & parent, const QString & elementName, const QString & text)
{
    // empty will never be written
    if (text.isEmpty()) {
        return;
    }

    QDomDocument domDoc = parent.ownerDocument();
    QDomElement element = domDoc.createElement( elementName );
    parent.appendChild( element );
    QDomText textNode = domDoc.createTextNode( text );
    element.appendChild( textNode );
}
