#include "data.h"

#include <QTime>
#include <QRegularExpression>


typedef QByteArray (*fp_get_data_from)(QString);
typedef QString (Data::*fp_trns_fmt_to)(QByteArray);


static QByteArray get_from_ascii(QString in)
{
    return in.toLatin1();
}

static QByteArray get_from_base64(QString in)
{
    QString pure = in.replace(QRegularExpression("[^0-9a-zA-Z+/=]"), "");
    return QByteArray::fromBase64(pure.toLatin1());
}

static QByteArray get_from_hex(QString in)
{
    QString pure = in.replace(QRegularExpression("(0x)|[^0-9a-fA-F]"), "");
    return QByteArray::fromHex(pure.toLatin1());
}

static QString split_line(QString &line, int cpl)
{
    if (0 >= cpl) return QString(line);
    else {
        QString ret = "";
        for (int idx = 0; idx < line.length(); idx += cpl) {
            ret += line.mid(idx, cpl);
            ret += '\n';
        }
        ret.trimmed();
        return ret;
    }
}


Data::Data()
{}


Data::Data(int len)
{
    QByteArray rand;
    QTime cur = QTime::currentTime();
    qsrand(cur.second() * 1000 + cur.msec());
    while (len--) rand += qrand() % 256;
    this->data << rand;
}


void Data::set(QString &in, enum en_type type)
{
    this->data.clear();

    fp_get_data_from get_data = get_from_ascii;
    switch (type) {
        case t_ascii: get_data = get_from_ascii; break;
        case t_base64: get_data = get_from_base64; break;
        case t_hex: get_data = get_from_hex; break;
    }

    QStringList sl = in.split('\n');
    QStringList::const_iterator it = sl.begin();
    for (; it != sl.end(); it++) {
        this->data << get_data(*it);
    }
}


QString Data::get(int bpl, enum en_type type, enum en_format format)
{
    QString ret = "";

    QByteArrayList show;
    if (bpl < 0) show = this->data;
    else {
        show << this->data.join("");
    }

    int cpl = bpl;
    fp_trns_fmt_to trns_to = this->trns_to_ascii;
    switch (type) {
        case t_ascii: trns_to = this->trns_to_ascii; cpl = bpl; break;
        case t_base64: trns_to = this->trns_to_base64; cpl = bpl; break;
        case t_hex: {
            switch (format) {
                case continous: trns_to = this->trns_to_hex_cont; cpl = 2 * bpl; break;
                case separate: trns_to = this->trns_to_hex_sepa; cpl = 3 * bpl; break;
                case cprefix: trns_to = this->trns_to_hex_cpre; cpl = 6 * bpl; break;
            }
            break;
        }
    }

    QByteArrayList::const_iterator it = show.begin();
    for (; it < show.end(); it++) {
        QString line = (this->*trns_to)(*it);
        ret += split_line(line, cpl);
        ret += '\n';
    }

    return ret.trimmed();
}


QString Data::trns_to_ascii(QByteArray in)
{
    return QString(in);
}


QString Data::trns_to_base64(QByteArray in)
{
    return QString(in.toBase64());
}


QString Data::trns_to_hex_cont(QByteArray in)
{
    QString ret = in.toHex();
    if (this->cap) return ret.toUpper();
    return ret;
}


QString Data::trns_to_hex_sepa(QByteArray in)
{
    QString ret = "";
    QString raw = this->trns_to_hex_cont(in);
    for (int i = 0; i < raw.length(); i += 2) {
        ret += raw.mid(i, 2) + " ";
    }
    return ret.trimmed();
}


QString Data::trns_to_hex_cpre(QByteArray in)
{
    QString ret = "";
    QString raw = this->trns_to_hex_cont(in);
    for (int i = 0; i < raw.length(); i += 2) {
        ret += "0x" + raw.mid(i, 2) + ", ";
    }
    ret = ret.trimmed();
    return ret.left(ret.length() - 1);
}