QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
{
    // individual tx do not affect any representation
    static const bool fMultiSig = true;

    QString strHTML;

    LOCK2(cs_main, wallet->cs_wallet);
    strHTML.reserve(4000);
    strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";

    int64_t nTime = wtx.GetTxTime();

    std::map<int, int64_t> mapDebit, mapCredit, mapChange, mapNet;
    // debits
    wallet->FillDebits(wtx, mapDebit, fMultiSig);
    // credits (mature)
    wallet->FillMatures(wtx, mapCredit, fMultiSig);

    // nets (mature - debits)
    FillNets(mapDebit, mapCredit, mapNet);

    strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx);
    int nRequests = wtx.GetRequestCount();
    if (nRequests != -1)
    {
        if (nRequests == 0)
            strHTML += tr(", has not been successfully broadcast yet");
        else if (nRequests > 0)
            strHTML += tr(", broadcast through %n node(s)", "", nRequests);
    }
    strHTML += "<br>";

    strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";

    //
    // From
    //
    if (wtx.IsCoinBase() || wtx.IsCoinStake())
    {
        strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>";
    }
    else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
    {
        // Online transaction
        strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>";
    }
    else
    {

        // Offline transaction
        if (ValueMapAllPositive(mapNet))
        {
            // Credit
            BOOST_FOREACH(const CTxOut& txout, wtx.vout)
            {
                if (wallet->IsMine(txout, fMultiSig) & ISMINE_ALL)
                {
                    CTxDestination address;
                    if (ExtractDestination(txout.scriptPubKey, address) &&
                        (IsMine(*wallet, address, fMultiSig) & ISMINE_ALL))
                    {
                        if (wallet->mapAddressBook.count(address))
                        {
                            strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
                            strHTML += "<b>" + tr("To") + ":</b> ";
                            CBitcoinAddress addr(address, txout.nColor);
                            strHTML += GUIUtil::HtmlEscape(addr.ToString());
                            // indicate distinction between own address and watch address
                            if (IsMine(*wallet, address, fMultiSig) & ISMINE_SPENDABLE)
                            {
                                if (!wallet->mapAddressBook[address].empty())
                                {
                                    strHTML += " (" + tr("own address") + ", " + tr("label") + ": " +
                                                   GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")";
                                }
                                else
                                {
                                    strHTML += " (" + tr("own address") + ")";
                                }
                            }
                            else
                            {
                                if (!wallet->mapAddressBook[address].empty())
                                {
                                    strHTML += " (" + tr("watch address") + ", " + tr("label") + ": " +
                                                   GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")";
                                }
                                else
                                {
                                    strHTML += " (" + tr("watch address") + ")";
                                }
                            }
                            strHTML += "<br>";
                        }
                    }
                    break;
                }
            }
        }
    }

    //
    // To
    //
    if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
    {
        // Online transaction
        std::string strAddress = wtx.mapValue["to"];
        strHTML += "<b>" + tr("To") + ":</b> ";
        CTxDestination dest = CBitcoinAddress(strAddress).Get();
        if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].empty())
            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest]) + " ";
        strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
    }

    //
    // Amount
    //
    // Coinbase was not mature
    if (wtx.IsCoinBase() && ValueMapAllZero(mapCredit))
    {
        //
        // Coinbase
        //
        strHTML += "<b>" + tr("Credit") + ":</b> ";
        if (wtx.IsInMainChain())
        {
            std::map<int, int64_t> mapUnmatured;
            wallet->FillCredits(wtx, mapUnmatured, fMultiSig);
            strHTML += ValueMapToHTML(mapUnmatured);
            strHTML += " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
        }
        else
        {
            strHTML += "(" + tr("not accepted") + ")";
        }
        strHTML += "<br>";
    }
    else if (ValueMapAllPositive(mapNet))
    {
        //
        // Credit
        //
        strHTML += "<b>" + tr("Credit") + ":</b> " + ValueMapToHTML(mapNet) + "<br>";
    }
    else
    {
        bool fAllFromMe = true;
        BOOST_FOREACH(const CTxIn& txin, wtx.vin)
        {
            fAllFromMe = fAllFromMe && (wallet->IsMine(txin, fMultiSig) & ISMINE_SPENDABLE);
            if (!fAllFromMe)
            {
                break;
            }
        }

        bool fAllToMe = true;
        BOOST_FOREACH(const CTxOut& txout, wtx.vout)
        {
            fAllToMe = fAllToMe && (wallet->IsMine(txout, fMultiSig) & ISMINE_SPENDABLE);
            if (!fAllToMe)
            {
                break;
            }
        }

        if (fAllFromMe)
        {
            //
            // Debit
            //
            BOOST_FOREACH(const CTxOut& txout, wtx.vout)
            {
                if (wallet->IsMine(txout, fMultiSig) & ISMINE_SPENDABLE)
                {
                    continue;
                }

                if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
                {
                    // Offline transaction
                    CTxDestination address;
                    if (ExtractDestination(txout.scriptPubKey, address))
                    {
                        strHTML += "<b>" + tr("To") + ":</b> ";
                        if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
                            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
                        strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address, txout.nColor).ToString());
                        strHTML += "<br>";
                    }
                }

                strHTML += "<b>" + tr("Debit") + ":</b> " +
                           BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue, txout.nColor) + "<br>";
            }

             std::map<int, int64_t> mapFee, mapDebit, mapValuesOut;

            if (fAllToMe)
            {
                // Payment to self
                std::map<int, int64_t> mapChange, mapValue;
                wallet->FillChange(wtx, mapChange);
                FillNets(mapChange, mapCredit, mapValue);
                FillNets(mapCredit, mapChange, mapDebit);
                strHTML += "<b>" + tr("Debit") + ":</b> " + ValueMapToHTML(mapDebit) + "<br>";
                strHTML += "<b>" + tr("Credit") + ":</b> " + ValueMapToHTML(mapValue) + "<br>";
            }

            wtx.FillValuesOut(mapValuesOut);
            wallet->FillDebits(wtx, mapDebit, fMultiSig);
            FillNets(mapValuesOut, mapDebit, mapFee);
            if (ValueMapAllPositive(mapFee))
            {
                strHTML += "<b>" + tr("Transaction fee") + ":</b> " + ValueMapToHTML(mapFee) + "<br>";
            }
        }
        else
        {
            //
            // Mixed debit transaction
            //
            BOOST_FOREACH(const CTxIn& txin, wtx.vin)
            {
                strHTML += TxInToHTML(txin, wallet);
            }
            BOOST_FOREACH(const CTxOut& txout, wtx.vout)
            {
                strHTML += TxOutToHTML(txout, wallet);
            }
        }
    }