wxString mmReportChartStocks::getHTMLText()
{
    mmHTMLBuilder hb;
    hb.init();
    hb.addHeader(2, _("Stocks Performance Charts"));

    wxTimeSpan dtDiff = dtRange_->end_date() - dtRange_->start_date();
    if (dtRange_->is_with_date() && dtDiff.GetDays() <= 366)
        hb.DisplayDateHeading(dtRange_->start_date(), dtRange_->end_date(), true);
    hb.addHorizontalLine();

    int count = 0, heldAt = -1;
    bool pointDot = false, showGridLines = false;
    wxTimeSpan dist;
    wxDate dateDt, precDateDt = wxInvalidDateTime;
    for (const auto& stock : Model_Stock::instance().all(Model_Stock::COL_HELDAT))
    {
        int dataCount = 0, freq = 1;
        Model_StockHistory::Data_Set histData = Model_StockHistory::instance().find(Model_StockHistory::SYMBOL(stock.SYMBOL),
            Model_StockHistory::DATE(dtRange_->start_date(), GREATER_OR_EQUAL),
            Model_StockHistory::DATE(dtRange_->end_date(), LESS_OR_EQUAL));
        std::stable_sort(histData.begin(), histData.end(), SorterByDATE());
        if (histData.size() <= 30)
            showGridLines = pointDot = true;
        else if (histData.size() <= 366)
            showGridLines = true;
        else
            freq = histData.size() / 366;
        std::vector<ValueTrio> aData;
        for (const auto& hist : histData)
        {
            if (dataCount % freq == 0)
            {
                ValueTrio val;
                dateDt = Model_StockHistory::DATE(hist);
                if (histData.size() <= 30)
                    val.label = mmGetDateForDisplay(dateDt);
                else if (precDateDt.IsValid() && dateDt.GetMonth() != precDateDt.GetMonth())
                    val.label = dateDt.GetMonthName(dateDt.GetMonth());
                else
                    val.label = "";
                val.amount = hist.VALUE;
                aData.push_back(val);
                precDateDt = dateDt;
            }
            dataCount++;
        }
        if (!aData.empty())
        {
            Model_Account::Data* account = Model_Account::instance().get(stock.HELDAT);
            hb.addHeader(1, wxString::Format("%s - (%s)", stock.STOCKNAME, account->ACCOUNTNAME));
            hb.addLineChart(aData, stock.STOCKNAME, count, 1000, 400, pointDot, showGridLines, true);
        }

        heldAt = stock.HELDAT;
        count++;
    }

    return hb.getHTMLText();
}
void mmStockDialog::showStockHistory()
{
    priceListBox_->DeleteAllItems();
    if (m_stock->SYMBOL.IsEmpty())
        return;

    Model_Account::Data* account = Model_Account::instance().get(m_stock->HELDAT);
    Model_StockHistory::Data_Set histData = Model_StockHistory::instance().find(Model_StockHistory::SYMBOL(m_stock->SYMBOL));
    std::stable_sort(histData.begin(), histData.end(), SorterByDATE());
    std::reverse(histData.begin(), histData.end());
    if (histData.size()>300)
        histData.resize(300);
    if (!histData.empty())
    {
        int idx=0;
        for (const auto &d : histData)
        {
            wxListItem item;
            item.SetId(idx);
            item.SetData(d.HISTID);
            priceListBox_->InsertItem( item );
            const wxDate dtdt = Model_StockHistory::DATE(d);
            const wxString dispAmount = Model_Account::toString(d.VALUE, account, 4);
            priceListBox_->SetItem(idx, 0, mmGetDateForDisplay(dtdt));
            priceListBox_->SetItem(idx, 1, dispAmount);
            if (idx == 0)
            {
                priceDate_->SetValue(dtdt);
                currentPrice_->SetValue(dispAmount);
            }
            const wxString& priceAmount = Model_Account::toString(d.VALUE - m_stock->PURCHASEPRICE, account, 4);
            priceListBox_->SetItem(idx, 2, priceAmount);
            idx++;
        }
        priceListBox_->RefreshItems(0, --idx);
    }
}
wxString mmReportChartStocks::getHTMLText()
{
    mmHTMLBuilder hb;
    hb.init();
    hb.addDivContainer();
    hb.addHeader(2, getReportTitle());
    hb.addDateNow();

    wxTimeSpan dtDiff = m_date_range->end_date() - m_date_range->start_date();
    if (m_date_range->is_with_date() && dtDiff.GetDays() <= 366)
        hb.DisplayDateHeading(m_date_range->start_date(), m_date_range->end_date(), true);
    hb.addHorizontalLine();

    bool pointDot = false, showGridLines = false;
    wxTimeSpan dist;
    wxDate precDateDt = wxInvalidDateTime;
    for (const auto& stock : Model_Stock::instance().all(Model_Stock::COL_HELDAT))
    {
        int dataCount = 0, freq = 1;
        Model_StockHistory::Data_Set histData = Model_StockHistory::instance().find(Model_StockHistory::SYMBOL(stock.SYMBOL),
            Model_StockHistory::DATE(m_date_range->start_date(), GREATER_OR_EQUAL),
            Model_StockHistory::DATE(m_date_range->end_date(), LESS_OR_EQUAL));
        std::stable_sort(histData.begin(), histData.end(), SorterByDATE());
        if (histData.size() <= 30)
            showGridLines = pointDot = true;
        else if (histData.size() <= 366)
            showGridLines = true;
        else
            freq = histData.size() / 366;
        std::vector<LineGraphData> aData;
        for (const auto& hist : histData)
        {
            if (dataCount % freq == 0)
            {
                LineGraphData val;
                val.xPos = mmGetDateForDisplay(hist.DATE);
                const wxDate dateDt = Model_StockHistory::DATE(hist);
                if (histData.size() <= 30)
                    val.label = val.xPos;
                else if (precDateDt.IsValid() && dateDt.GetMonth() != precDateDt.GetMonth())
                    val.label = wxGetTranslation(dateDt.GetEnglishMonthName(dateDt.GetMonth()));
                else
                    val.label = "";
                val.amount = hist.VALUE;
                aData.push_back(val);
                precDateDt = dateDt;
            }
            dataCount++;
        }
        if (!aData.empty())
        {
            hb.addDivRow();
            Model_Account::Data* account = Model_Account::instance().get(stock.HELDAT);
            hb.addHeader(1, wxString::Format("%s - (%s)", stock.STOCKNAME, account->ACCOUNTNAME));
            hb.addDivCol17_67();
            hb.addLineChart(aData, stock.STOCKNAME, 0, 1000, 400, pointDot, showGridLines);
            hb.endDiv();
            hb.endDiv();
        }
    }

    hb.endDiv();
    hb.end();

    return hb.getHTMLText();
}