//person.h
#ifndef PERSON_H
#define PERSON_H

#include <QObject>
#include <QDebug>
#include <QMetaObject>
#include <QMetaEnum>
#include <QString>
#include <QDate>
#include <QFile>

static const char* BLOODTYPE = "BloodType";

class Person : public QObject
{
    Q_OBJECT
    Q_ENUMS(BloodType)
    Q_PROPERTY(QString name READ getName WRITE setName)
    Q_PROPERTY(QDate dob READ getDob WRITE setDob)
    Q_PROPERTY(Person::BloodType bloodtype READ getBloodType WRITE setBloodType)

public:
    enum BloodType {A,B,O};
    explicit Person(QObject *parent = nullptr,QString name="",QDate dob=QDate::currentDate(),BloodType bloodtype=BloodType::O);

    static int getBloodTypeCount();
    static QString getBloodType(int index);
    static QString getBloodType(BloodType bloodtype);
    static BloodType getBloodType(QString bloodtype);

    QString getName() const;
    void setName(const QString &name);

    QDate getDob() const;
    void setDob(const QDate &dob);

    BloodType getBloodType(); // get the blood type of this person
    void setBloodType(BloodType bloodtype); // set the blood type of this person

private:
    QString name;
    QDate dob;
    BloodType bloodtype;
    int bloodtypes;

signals:

};

#endif // PERSON_H


//person.cpp
#include "person.h"

Person::Person(QObject *parent, QString name, QDate dob, BloodType bloodtype) : QObject{parent}
{
    setName(name);
    setDob(dob);
    setBloodType(bloodtype);
}

int Person::getBloodTypeCount()
{
    QMetaObject mo = Person::staticMetaObject;
    QMetaEnum me = mo.enumerator(mo.indexOfEnumerator(BLOODTYPE));
    return me.keyCount();
}

QString Person::getBloodType(int index)
{
    QMetaObject mo = Person::staticMetaObject;
    QMetaEnum me = mo.enumerator(mo.indexOfEnumerator(BLOODTYPE));
    return QString(me.key(index));

}

QString Person::getBloodType(BloodType bloodtype)
{
    QMetaObject mo = Person::staticMetaObject;
    QMetaEnum me = mo.enumerator(mo.indexOfEnumerator(BLOODTYPE));
    return QString(me.key(bloodtype));
}

Person::BloodType Person::getBloodType(QString bloodtype)
{
    QMetaObject mo = Person::staticMetaObject;
    QMetaEnum me = mo.enumerator(mo.indexOfEnumerator(BLOODTYPE));
    bool OK=false;
    int val = me.keyToValue(bloodtype.toStdString().c_str(),&OK);
    //int val = me.keyToValue(bloodtype.toLatin1());

    switch(val) {
        case BloodType::A:
            return BloodType::A;
        case BloodType::B:
            return BloodType::B;
        case BloodType::O:
            return BloodType::O;
    }

}

QString Person::getName() const
{
    return name;
}

void Person::setName(const QString &name)
{
    this->name = name;
}

QDate Person::getDob() const
{
    return dob;
}

void Person::setDob(const QDate &dob)
{
    this->dob = dob;
}

Person::BloodType Person::getBloodType()
{
    return bloodtype;
}

void Person::setBloodType(BloodType bloodtype)
{
    this->bloodtype = bloodtype;
}

//main.cpp
#include <QCoreApplication>
#include "person.h"

void writeToFile(QObject* obj)
{
    QFile file("people.txt");
    file.open(QIODevice::Append);
    QTextStream stream(&file);

    const QMetaObject* mo = obj->metaObject();
    for (int i = mo->propertyOffset(); i < mo->propertyCount(); i++)
    {
        const QMetaProperty mp = mo->property(i);
        //QString name = mp.name(); // this is the property name;
        const char* name = mp.name();
        if(mp.isEnumType()) {
            qInfo() << "propname: " << name << " isEnumType: true";
            QVariant valVar = obj->property(name);
            if(valVar.isNull())
            {
                qInfo() << "propname: " << name << " isNull: true";
            }
            else
            {
                qInfo() << "propname: " << name << " isNull: false";
            }
            if(valVar.isValid())
            {
                qInfo() << "propname: " << name << " isValid: true";
            }
            else
            {
                qInfo() << "propname: " << name << " isValid: false";
            }
            bool OK = false;
            int nVal = valVar.toInt(&OK);
            if(!OK) {
                qInfo() << "valVar.toInt(&OK): false";
            }
            else {
                qInfo() << "valVar.toInt(&OK): true";
            }
            Person::BloodType bt = valVar.value<Person::BloodType>();
            qInfo() << "valVar: " << valVar;
            qInfo() << "Person::getBloodType(bt): " << Person::getBloodType(bt);
            QString valStr = Person::getBloodType(bt);
            qInfo() << name << ": " << valStr;
            stream << name << ": " << valStr << "\n";
        }
        else
        {
            qInfo() << "propname: " << name << " isEnumType: false";
            //QVariant valVar = prop.read(obj); // property value stored in a QVariant variable value
            QVariant valVar = obj->property(name);
            QString valStr = valVar.toString(); //QVariant value converted to QString
            qInfo() << name << ": " << valStr << "\n";
            stream << name << ": " << valStr << "\n";

        }
    }
    file.close();
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Person *bart = new Person(&a,"Bart Simpson",QDate::currentDate(),Person::BloodType::O);

    writeToFile(bart);

    return a.exec();
}