#include "OrderObject.h"
#include "PreDefined.h"
#include "../Util/IniDataManger.h"
#include <QFileInfo>
#include <QDateTime>
#include <QDebug>

/*QString OrderObject::toString() const
{
    QJsonObject json = toJson();

    QJsonArray ComdsArray;
    foreach ( ComdObject *v, proList) {
        QJsonObject o = v->toJson();
        ComdsArray.append(o);
    }
    json["products"] = ComdsArray;

    QJsonDocument doc;
    doc.setObject(json);

    return QString::fromUtf8(doc.toJson());
}*/

void OrderObject::fromJson(const QJsonObject &json)
{
    this->fetchDataFromJson(json);
    QJsonArray proArray = json["products"].toArray();
    QStringList mates = IniDataManger::Instance().GetStoreMates();
    QList<ComdObject *> list;
    QList<ComdObject *> mList;

    pvm.clear();
    foreach (QJsonValue pro, proArray) {
        ComdObject *proObject = new ComdObject(this);
        proObject->fetchDataFromJson(pro.toObject());
        //TODO
//        if (mates.contains(proObject->name)) {
//            mList.append(proObject);
//        }
        if (mates.contains(proObject->pid)) {
            mList.append(proObject);
        }
        else {
            pvm[proObject].reserve(1);
        }
        list.append(proObject);
    }

    //! Offline properties
    QString order_file = OBJREF(IniDataManger).GetBillFile();
    order_file += "." + channel + "." + QDateTime::fromTime_t(create_time).toString("yyyyMMddhhmmss") + "." + order_index;
    QFileInfo bill_fm(order_file);

    QString vivi_file = OBJREF(IniDataManger).GetViviBillFile();
    vivi_file += bill_fm.fileName();

    bill_file = bill_fm.exists() ? order_file : vivi_file;

    QFileInfo bill_vivi(vivi_file);
    billed = bill_fm.exists() || bill_vivi.exists();

    if (!billed) bill_file = "";

    setMateList(mList);
    this->getProList(list);

    return;
}


//void OrderObject::fromString(const QString &str)
//{
//    QJsonParseError error;
//    QJsonDocument doc = QJsonDocument::fromJson( str.toUtf8(),&error);
//    if( error.error == QJsonParseError::NoError){
//        QJsonObject json = doc.object();
//        fromJson( json);
//    }
//}

void OrderObject::getProList(QList<ComdObject *> &list)
{
    qDeleteAll(proList);
    proList.clear();
    proList = list;
}

void OrderObject::setMateList(QList<ComdObject *> &list)
{
    if (!mateList.isEmpty()) {
        mateList.clear();
    }
    mateList = list;
    if (!mateList.isEmpty()) {
        setHasMate(true);
        setMateAssigned(billed);
    }
}

QStringList OrderObject::getdis_desc() const
{
    return dis_desc;
}

void OrderObject::setdis_desc(const QStringList &v)
{
    dis_desc = v;
}

int OrderObject::getpackage_fee() const
{
    return package_fee;
}

void OrderObject::setpackage_fee(const int &v)
{
    package_fee = v;
}

int OrderObject::getStatus() const
{
    return status;
}
void OrderObject::setStatus(const int &v)
{
    status = v;
}

QString OrderObject::getChannel() const
{
    return channel;
}

void OrderObject::setChannel(const QString &v)
{
    channel = v;
}

QString OrderObject::getChannelName() const
{
    return channelName;
}

void OrderObject::setChannelName(const QString &v)
{
    channelName = v;
}

QString OrderObject::getPhone() const
{
    return phone;
}
void OrderObject::setPhone(const QString& v)
{
    phone = v;
}

QString OrderObject::getAddress() const
{
    return address;
}
void OrderObject::setAddress(const QString& v)
{
    address = v;
}

QString OrderObject::getCustomer() const
{
    return customer;
}
void OrderObject::setCustomer(const QString& v)
{
    customer = v;
}

QString OrderObject::getDeliveryParty() const
{
    return delivery_party;
}
void OrderObject::setDeliveryParty(const QString& v)
{
    delivery_party = v;
}

QString OrderObject::getOrderId() const
{
    return order_id;
}

void OrderObject::setOrderId(const QString &v)
{
    order_id = v;
}

QString OrderObject::getPosOrderId() const
{
    return posorder_id;
}

void OrderObject::setPosOrderId(const QString &v)
{
    posorder_id = v;
}

int OrderObject::getPaidFee() const
{
    return paid_fee;
}

void OrderObject::setPaidFee(const int &v)
{
    paid_fee = v;
}

int OrderObject::getShopFee() const
{
    return shop_fee;
}

void OrderObject::setShopFee(const int &v)
{
    shop_fee = v;
}

int OrderObject::getRestFee() const
{
    return rest_fee ;
}

void OrderObject::setRestFee(const int &v)
{
    rest_fee = v;
}

int OrderObject::getUserFee() const
{
    return user_fee ;
}

void OrderObject::setUserFee(const int &v)
{
    user_fee = v;
}

QString OrderObject::getCoupon() const
{
    return coupon;
}

void OrderObject::setCoupon(const QString &v)
{
    coupon = v;
}

QString OrderObject::getRemark() const
{
    return remark;
}

void OrderObject::setRemark(const QString &v)
{
    remark = v;
}

int OrderObject::getCreateTime() const
{
    return create_time;
}

void OrderObject::setCreateTime(const int &v)
{
    create_time = v;
}

int OrderObject::getExpireTime() const
{
    return expire_time;
}

void OrderObject::setExpireTime(const int &v)
{
    expire_time = v;
}

QString OrderObject::getTimestamp() const
{
    return timestamp;
}

void OrderObject::setTimestamp(const QString &v)
{
    timestamp = v;
}

QString OrderObject::getPayType() const
{
    return pay_type;
}

void OrderObject::setPayType(const QString &v)
{
    pay_type = v;
}

QString OrderObject::getprintcfg() const
{
    return printcfg;
}

void OrderObject::setprintcfg(const QString &v)
{
    printcfg = v;
}

int OrderObject::getTotalFee() const
{
    return total_fee;
}

void OrderObject::setTotalFee(const int &v)
{
    total_fee = v;
}
int OrderObject::getDiscountFee() const
{
    return discount_fee;
}

void OrderObject::setDiscountFee(const int &v)
{
    discount_fee = v;
}

int OrderObject::getDisShopFee() const
{
    return dis_shop_fee;
}

void OrderObject::setDisShopFee(const int &v)
{
    dis_shop_fee = v;
}

int OrderObject::getSendFee() const
{
    return send_fee;
}

void OrderObject::setSendFee(const int &v)
{
    send_fee = v;
}

int OrderObject::getServiceFee() const
{
    return service_fee;
}

void OrderObject::setServiceFee(const int v)
{
    service_fee = v;
}

int OrderObject::getProductFee() const
{
    return product_fee;
}

void OrderObject::setProductFee(const int v)
{
    product_fee = v;
}

int OrderObject::getTotalAmount() const
{
    return total_amount;
}

void OrderObject::setTotalAmount(const int &v)
{
    total_amount = v;
}

int OrderObject::getOrderIndex() const
{
    return order_index;
}

void OrderObject::setOrderIndex(const int v)
{
    order_index = v;
}

int OrderObject::getDeliveryStatus() const
{
    return delivery_status;
}

void OrderObject::setDeliveryStatus(const int v)
{
    delivery_status = v;
}

QString OrderObject::getFmId() const
{
    return fm_id;
}

void OrderObject::setFmId(const QString &v)
{
    fm_id = v;
}

QString OrderObject::getStatusDesc() const
{
    return status_desc;
}

void OrderObject::setStatusDesc(const QString &v)
{
    status_desc = v;
}

int OrderObject::getDeliveryType() const
{
    return delivery_type;
}

void OrderObject::setDeliveryType(const int v)
{
    delivery_type = v;
}

quint32 OrderObject::getDeliveryTime() const
{
    return delivery_time;
}

void OrderObject::setDeliveryTime(quint32 v)
{
    delivery_time = v;
}

bool OrderObject::getHasMate() const
{
    return has_mate;
}

void OrderObject::setHasMate(bool v)
{
    has_mate = v;
}

bool OrderObject::getMateAssigned() const
{
    return mate_assigned;
}

void OrderObject::setMateAssigned(bool v)
{
    mate_assigned = v;
}

bool OrderObject::getBilled() const
{
    return billed;
}

void OrderObject::setBilled(bool v)
{
    billed = v;
}

QString OrderObject::getBillFile() const
{
    return bill_file;
}

void OrderObject::setBillFile(const QString &v)
{
    bill_file = v;
}

QList<ComdObject *> OrderObject::_ReadObjectMates(const QString &mates_str)
{
    QList<ComdObject*> mate_list, primitive_mates, dup_list;
    QStringList store_mates = OBJREF(IniDataManger).GetStoreMates();

    QStringList tmp_mates = mates_str.split(",");

    foreach(QString tm, tmp_mates) {
        QString m = tm.section("|", 0, 0);
        int mn = tm.section("|", 2, 2).toInt();
        if (store_mates.contains(m)) {
            ComdObject* primitive_po = 0;
            foreach(ComdObject *po, mateList) {
                //TODO
//                if (po->name == m) {
//                    primitive_po = po;
//                    break;
//                }
                if (po->pid == m) {
                    primitive_po = po;
                    break;
                }
            }
            ComdObject *dup_mate = new ComdObject();
            dup_mate->fetchDataFromJson(primitive_po->toJson());
            dup_mate->productAmount = mn;
            mate_list << dup_mate;
        }
    }

    primitive_mates = mateList;
    foreach(ComdObject *mate, primitive_mates) {
        foreach(ComdObject *mo, mate_list) {
            if (mate->name == mo->name) {
                mate->productAmount = mo->productAmount;
                mate_list.removeOne(mo);
                mate_list << mate;
                break;
            }
        }
    }

    foreach(ComdObject *mo, mate_list) {
        if (!mateList.contains(mo)) {
            mateList << mo;
        }
    }

    assignedMateList += mate_list;

    return mate_list;
}

ComdObject *OrderObject::MatchObjectsFromBill(const QJsonArray &products)
{
    foreach (ComdObject* lmo, loneMateList) {
        mateList.removeOne(lmo);
        delete lmo;
    }
    loneMateList.clear();

    QList<ComdObject*> primitive_list = pvm.keys();
    QList<ComdObject*> dup_list;
    foreach(QJsonValue pro, products) {
        QJsonObject v = pro.toObject();
        QString pid = v["pid"].toString();
        int product_num = v["consume_num"].toInt();
        QString mates_str = v["condiments"].toString();

        ComdObject* primitive_po = 0;
        foreach(ComdObject *po, primitive_list) {
            if (po->pid == pid) {
                primitive_po = po;
                break;
            }
        }

        //! No product of pid #pid found
        if (primitive_po) {
            ComdObject *dup_obj = new ComdObject();
            dup_obj->fetchDataFromJson(primitive_po->toJson());
            dup_obj->productAmount = product_num;
            pvm[dup_obj] = _ReadObjectMates(mates_str);
            dup_list << dup_obj;
        }
        else {
            bool lone_mate_found = false;
            foreach(ComdObject *lmo, loneMateList) {
                if (lmo->pid == pid) {
                    ++lmo->productAmount;
                    lone_mate_found = true;
                }
            }

            if (!lone_mate_found) {
                foreach(ComdObject *mo, mateList) {
                    if (mo->pid == pid) {
                        primitive_po = mo;
                        break;
                    }
                }
                if (primitive_po) {
                    ComdObject *dup_obj = new ComdObject();
                    dup_obj->fetchDataFromJson(primitive_po->toJson());
                    dup_obj->productAmount = 1;
                    loneMateList << dup_obj;
                    mateList << dup_obj;
                }
            }
        }
    }

    foreach(ComdObject *po, primitive_list) {
        foreach(ComdObject *dpo, dup_list) {
            if (po->pid == dpo->pid) {
                po->productAmount = dpo->productAmount;
                pvm[po] = pvm[dpo];
                dup_list.removeOne(dpo);
                pvm.remove(dpo);
                break;
            }
        }
    }
}

void OrderObject::CheckIfMatesAssigned()
{
    mate_assigned = true;
    foreach (ComdObject *obj,  mateList) {
        if (!assignedMateList.contains(obj)) {
            mate_assigned = false;
            if (!loneMateList.contains(obj)) {
                loneMateList << obj;
            }
        }
        else {
            if (loneMateList.contains(obj)) {
                loneMateList.removeOne(obj);
            }
        }
    }

    if (has_mate && !mate_assigned) {
        QList<ComdObject *> tmp_list = loneMateList;
        foreach(ComdObject* lmo, tmp_list) {
            QList<ComdObject *> product_list = pvm.keys();
            int same_cnt = 0;
            foreach(ComdObject *po, product_list) {
                //! Check if meets lmo->name
                foreach(ComdObject *mo, pvm[po]) {
                    if (mo->name == lmo->name) {
                        ++same_cnt;
                        break;
                        //! Next product
                    }
                }
            }

            if (same_cnt < product_list.size() && loneMateList.contains(lmo)) {
                loneMateList.removeOne(lmo);
            }
            else if (same_cnt == product_list.size()) {
                mate_assigned = true;
            }
        }

        if (tmp_list.size() != loneMateList.size()) {
            mate_assigned = false;
        }
    }
}


