#include "scountdlg.h"
#include "mainwindow.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QDateTime>
#include <QTimer>
#include <QFile>
#include <QApplication>
#include <QMessageBox>
#include <QFileDialog>

const int C_COMBO_MAX = 2;

SCountDlg::SCountDlg()
{
    setWidgets();
}

SCountDlg::~SCountDlg()
{
}

void SCountDlg::setWidgets()
{
    setWindowTitle("Count");
    QVBoxLayout *vlayout = new QVBoxLayout;
    {
        QHBoxLayout *hlayout = new QHBoxLayout;
        m_pCombo = new QComboBox[C_COMBO_MAX];
        for (int i = 0; i < C_COMBO_MAX ; i++)
            hlayout->addWidget(&m_pCombo[i]);

        QPushButton *ppbRun = new QPushButton("Run");
        connect(ppbRun, SIGNAL(released()),this, SLOT(run()));
        hlayout->addWidget(ppbRun);
        QPushButton *ppbGraph = new QPushButton("Graph");
        connect(ppbGraph, SIGNAL(released()),this, SLOT(graph()));
        hlayout->addWidget(ppbGraph);
        QPushButton *ppbSave = new QPushButton("Save");
        connect(ppbSave, SIGNAL(released()),this, SLOT(save()));
        hlayout->addWidget(ppbSave);

        vlayout->addLayout(hlayout);
    }
    m_pTable = new STable;
    m_pTable->SetHeaderList(QStringList() << "Item" << "Count");
    vlayout->addWidget(m_pTable);

    setLayout(vlayout);    

    for (int i = 0; i < C_COMBO_MAX ; i++)
    {
        m_pCombo[i].clear();
        foreach(QStringList strList,GetColumn().data())
            m_pCombo[i].addItem(strList.at(SColumn::E_NAME));
    }

    for (int i = 0; i < C_COMBO_MAX ; i++)
    {
        m_pCombo[i].addItem("[--------]");
        m_pCombo[i].setCurrentIndex(GetColumn().data().size());
    }    
}

void SCountDlg::choose_1()
{
    int nCatalog = D_NOT_SELECT;
    for (int i = 0; i < C_COMBO_MAX ; i++)
    {
        if (m_pCombo[i].currentIndex() != GetColumn().data().size())
        {
            nCatalog = m_pCombo[i].currentIndex();
            break;
        }
    }
    if (nCatalog == D_NOT_SELECT) return;
    m_pTable->SetHeaderList(QStringList() << GetColumn().data().at(nCatalog).at(SColumn::E_NAME) << "Count");
    QTableWidget *pCurrent = (QTableWidget *)GetMainWindow()->m_pDataDlg->GetCurrentWidget();
    GetMainWindow()->m_progress.setRange(0,pCurrent->rowCount());    
    if (GetColumn().isDateColumn(nCatalog))
    {
        QMap <QDate,int> mapCount;
        QDate dateStart(2055,12,31),dateEnd(1900,1,1);
        for (int nCount = 0 ; nCount < pCurrent->rowCount(); nCount++ )
        {
            //if(pCurrent->item(nCount,nCatalog)->text().trimmed().isEmpty()) continue;
            QDateTime date;
            QDate day = date.fromString(pCurrent->item(nCount,nCatalog)->text().trimmed(),"yyyy-MM-dd hh:mm:ss").date();
            if (day.year() < 1901) continue;
            if (day < dateStart) dateStart=day;
            if (day > dateEnd) dateEnd=day;
            if (mapCount.contains(day))
                mapCount[day]++;
            else
                mapCount.insert(day,1);
            GetMainWindow()->m_progress.setValue(nCount);
            GetMainWindow()->m_progress.repaint();
        }
        int nCount = 0;
        m_pTable->setRowCount(dateStart.daysTo(dateEnd));        
        for (QDate now = dateStart; now < dateEnd ; now=now.addDays(1) )
        {
            int nCol = 0;
            QString str = now.toString("yyyy-MM-dd").trimmed();
            m_pTable->setItem(nCount,nCol++,new QTableWidgetItem(str));
            if (mapCount.contains(now))
                m_pTable->setItem(nCount,nCol,new STableNumberItem(QString::number(mapCount[now])));
            else
                m_pTable->setItem(nCount,nCol,new STableNumberItem(QString::number(0)));
            nCount++;
        }
    }
    else
    {
        QMap <QString,int> mapCount;
        for (int nCount = 0 ; nCount < pCurrent->rowCount() ; nCount++ )
        {
            QString str = pCurrent->item(nCount,nCatalog)->text().trimmed();
            if(str.isEmpty()) continue;
            if (mapCount.contains(str))
                mapCount[str]++;
            else
                mapCount.insert(str,1);
            GetMainWindow()->m_progress.setValue(nCount);
            GetMainWindow()->m_progress.repaint();
        }
        m_pTable->setRowCount(mapCount.size());
        int nCount = 0;
        for (QMap<QString,int> ::iterator i = mapCount.begin(); i != mapCount.end(); ++i)
        {
            int nCol = 0;
            m_pTable->setItem(nCount,nCol++,new QTableWidgetItem(i.key()));
            m_pTable->setItem(nCount,nCol++,new STableNumberItem(QString::number(i.value())));
            nCount++;
        }
    }
}

void SCountDlg::choose_2()
{
    QTableWidget *pCurrent = (QTableWidget *)GetMainWindow()->m_pDataDlg->GetCurrentWidget();
    int anCatalog[C_COMBO_MAX];

    for (int i = 0; i < C_COMBO_MAX ; i++)
        anCatalog[i] = m_pCombo[i].currentIndex();

    QMap <QString,QMap<QString,int> > mapCount;
    QSet <QString> setList;
    QDate dateStart(2055,12,31),dateEnd(1900,1,1);
    GetMainWindow()->m_progress.setRange(0,pCurrent->rowCount());
    for (int nCount = 0 ; nCount < pCurrent->rowCount(); nCount++ )
    {
        QString astr[C_COMBO_MAX];
        bool bFlag=true;
        for (int i = 0; i < C_COMBO_MAX ; i++)
        {
            if (GetColumn().isDateColumn(anCatalog[i]))
            {
                QDateTime date;
                QDate day = date.fromString(pCurrent->item(nCount,anCatalog[i])->text().trimmed(),"yyyy-MM-dd hh:mm:ss").date();
                astr[i] = day.toString("yyyy-MM-dd").trimmed();
                if(astr[i].isEmpty()) continue;
                if (day.year() == 0) continue;
                if (day < dateStart) dateStart=day;
                if (day > dateEnd) dateEnd=day;
            }
            else
                astr[i] = pCurrent->item(nCount,anCatalog[i])->text().trimmed();
            if (astr[i].isEmpty()) bFlag = false;
        }
        if (bFlag == false) continue;
        if (mapCount.contains(astr[0]) == false)
        {
            QMap <QString,int> mapSec;
            mapCount.insert(astr[0],mapSec);
        }
        if (mapCount[astr[0]].contains(astr[1]) == false)
            mapCount[astr[0]].insert(astr[1],0);
        if (setList.contains(astr[1]) == false)
            setList.insert(astr[1]);
        mapCount[astr[0]][astr[1]]++;
        GetMainWindow()->m_progress.setValue(nCount);
        GetMainWindow()->m_progress.repaint();
    }
    m_pTable->clear();
    QStringList strList;
    strList.push_back(m_pCombo[0].currentText());
    for (QSet<QString>::iterator i = setList.begin(); i != setList.end(); ++i)
         strList.push_back(*i);
    m_pTable->SetHeaderList(strList);
    int nCount = 0;
    m_dTotal = 0.0;
    if (GetColumn().isDateColumn(anCatalog[0]))
    {
        //qDebug() << dateStart.daysTo(dateEnd);
        m_pTable->setRowCount(dateStart.daysTo(dateEnd));
        for (QDate now = dateStart; now < dateEnd ; now=now.addDays(1) )
        {
            int nCol = 0;
            QString str = now.toString("yyyy-MM-dd").trimmed();
            m_pTable->setItem(nCount,nCol++,new QTableWidgetItem(str));
            if (mapCount.contains(str))
            {
                for (QSet<QString>::iterator j = setList.begin(); j != setList.end(); ++j)
                {
                    if (mapCount[str].contains(*j))
                        m_pTable->setItem(nCount,nCol++,new STableNumberItem(QString::number(mapCount[str].value(*j))));
                    else
                        m_pTable->setItem(nCount,nCol++,new STableNumberItem(QString::number(0)));
                }
            }
            else
            {
                for (;nCol < strList.size();nCol++)
                    m_pTable->setItem(nCount,nCol,new STableNumberItem(QString::number(0)));
            }
            nCount++;
        }
    }
    else
    {
        m_pTable->setRowCount(mapCount.size());
        for (QMap<QString,QMap<QString,int> >::iterator i = mapCount.begin(); i != mapCount.end(); ++i)
        {
            int nCol = 0;
            m_pTable->setItem(nCount,nCol++,new QTableWidgetItem(i.key()));
            for (QSet<QString>::iterator j = setList.begin(); j != setList.end(); ++j)
            {
                if (i->contains(*j))
                    m_pTable->setItem(nCount,nCol++,new STableNumberItem(QString::number(i->value(*j))));
                else
                    m_pTable->setItem(nCount,nCol++,new STableNumberItem(QString::number(0)));
            }
            nCount++;
        }
    }

    m_strGraph = "<html>\r\n<meta charset=\"utf8\">\r\n<style>\r\nbody {\r\n  font: 10px sans-serif;\r\n}\r\n\r\n.axis path,\r\n.axis line {\r\n  fill: none;"
                 "\r\n  stroke: #000;\r\n  shape-rendering: crispEdges;\r\n}\r\n\r\n.x.axis path {\r\n  display: none;\r\n}\r\n\r\n.line {\r\n  fill: none;\r\n  stroke: steelblue;"
                 "\r\n  stroke-width: 1.5px;\r\n}\r\n\r\n</style>\r\n<body>\r\n<script src=\"http://d3js.org/d3.v3.min.js\"></script>\r\n<script>\r\n"
                 "\r\nvar margin = {top: 20, right: 80, bottom: 30, left: 50},\r\n    width = 960 - margin.left - margin.right,\r\n    height = 500 - margin.top - margin.bottom;"
                 "\r\n\r\nvar parseDate = d3.time.format(\"%Y-%m-%d\").parse;\r\n\r\nvar x = d3.time.scale()\r\n    .range([0, width]);\r\n\r\nvar y = d3.scale.linear()\r\n    .range([height, 0]);"
                 "\r\n\r\nvar color = d3.scale.category10();\r\n\r\nvar xAxis = d3.svg.axis()\r\n    .scale(x)\r\n    .orient(\"bottom\");\r\n\r\nvar yAxis = d3.svg.axis()\r\n    .scale(y)"
                 "\r\n    .orient(\"left\");"
                 "\r\n"
                 "\r\nvar line = d3.svg.line()"
                 "\r\n    .interpolate(\"basis\")"
                 "\r\n    .x(function(d) { return x(d.date); })"
                 "\r\n    .y(function(d) { return y(d.temperature); });"
                 "\r\n"
                 "\r\nvar svg = d3.select(\"body\").append(\"svg\")"
                 "\r\n    .attr(\"width\", width + margin.left + margin.right)"
                 "\r\n    .attr(\"height\", height + margin.top + margin.bottom)"
                 "\r\n  .append(\"g\")"
                 "\r\n    .attr(\"transform\", \"translate(\" + margin.left + \",\" + margin.top + \")\");"
                 "\r\n"
                 "\r\nd3.tsv(\"file:///[!F*i!l*e!]\", function(error, data) {"
                 "\r\n  if (error) throw error;"
                 "\r\n"
                 "\r\n  color.domain(d3.keys(data[0]).filter(function(key) { return key !== \"date\"; }));"
                 "\r\n"
                 "\r\n  data.forEach(function(d) {"
                 "\r\n    d.date = parseDate(d.date);"
                 "\r\n  });"
                 "\r\n"
                 "\r\n  var cities = color.domain().map(function(name) {"
                 "\r\n    return {"
                 "\r\n      name: name,"
                 "\r\n      values: data.map(function(d) {"
                 "\r\n        return {date: d.date, temperature: +d[name]};"
                 "\r\n      })"
                 "\r\n    };"
                 "\r\n  });"
                 "\r\n"
                 "\r\n  x.domain(d3.extent(data, function(d) { return d.date; }));"
                 "\r\n"
                 "\r\n  y.domain(["
                 "\r\n    d3.min(cities, function(c) { return d3.min(c.values, function(v) { return v.temperature; }); }),"
                 "\r\n    d3.max(cities, function(c) { return d3.max(c.values, function(v) { return v.temperature; }); })"
                 "\r\n  ]);"
                 "\r\n"
                 "\r\n  svg.append(\"g\")"
                 "\r\n      .attr(\"class\", \"x axis\")"
                 "\r\n      .attr(\"transform\", \"translate(0,\" + height + \")\")"
                 "\r\n      .call(xAxis);"
                 "\r\n"
                 "\r\n  svg.append(\"g\")"
                 "\r\n      .attr(\"class\", \"y axis\")"
                 "\r\n      .call(yAxis)"
                 "\r\n    .append(\"text\")"
                 "\r\n      .attr(\"transform\", \"rotate(-90)\")"
                 "\r\n      .attr(\"y\", 6)"
                 "\r\n      .attr(\"dy\", \".71em\")"
                 "\r\n      .style(\"text-anchor\", \"end\")"
                 "\r\n      .text(\"Count\");"
                 "\r\n"
                 "\r\n  var city = svg.selectAll(\".city\")"
                 "\r\n      .data(cities)"
                 "\r\n    .enter().append(\"g\")"
                 "\r\n      .attr(\"class\", \"city\");"
                 "\r\n"
                 "\r\n  city.append(\"path\")"
                 "\r\n      .attr(\"class\", \"line\")"
                 "\r\n      .attr(\"d\", function(d) { return line(d.values); })"
                 "\r\n      .style(\"stroke\", function(d) { return color(d.name); });"
                 "\r\n"
                 "\r\n  city.append(\"text\")"
                 "\r\n      .datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })"
                 "\r\n      .attr(\"transform\", function(d) { return \"translate(\" + x(d.value.date) + \",\" + y(d.value.temperature) + \")\"; })"
                 "\r\n      .attr(\"x\", 3)"
                 "\r\n      .attr(\"dy\", \".35em\")"
                 "\r\n      .text(function(d) { return d.name; });"
                 "\r\n});"
                 "\r\n"
                 "\r\n</script>"
                 "\r\n";
    QRegExp re("\\s{2,}");
    m_strGraph = m_strGraph.replace(re,"");
    m_strGraph = m_strGraph.replace("[!F*i!l*e!]",QApplication::applicationDirPath()+"/graph.tsv");
}

void SCountDlg::run()
{
    int nNone=0;
    for (int i = 0; i < C_COMBO_MAX ; i++)
    {
        if (m_pCombo[i].currentIndex() == GetColumn().data().size())
            nNone++;
    }
    switch(nNone)
    {
        case 0:choose_2();break;
        case 1:choose_1();break;
    }
}

void SCountDlg::graph()
{
    QFile file(QApplication::applicationDirPath()+"/graph.tsv");
    if (!file.open(QIODevice::WriteOnly)) return;
    QTextStream out(&file);
    out << QString("date\t").toUtf8();
    for (int i = 1; i < m_pTable->columnCount();i++)
        out << m_pTable->horizontalHeaderItem(i)->text().toUtf8() << QString("\t").toUtf8();
    out << QString("\n").toUtf8();
    GetMainWindow()->m_progress.setRange(0,m_pTable->rowCount());
    for (int i = 0 ; i < m_pTable->rowCount() ; i++ )
    {
        for (int j = 0; j < m_pTable->columnCount();j++)
        {
            out << m_pTable->item(i,j)->text().trimmed().toUtf8() << QString("\t").toUtf8();
        }
        out << QString("\n").toUtf8();
        GetMainWindow()->m_progress.setValue(i);
        GetMainWindow()->m_progress.repaint();
    }        
    file.close();

    GetMainWindow()->m_graph.setHtml(m_strGraph.toUtf8(),QUrl("file:///"));
    GetMainWindow()->m_graph.settings()->setObjectCacheCapacities(0,0,0);
    GetMainWindow()->m_graph.repaint();
    GetMainWindow()->m_graph.show();    
}

void SCountDlg::save()
{
    QFile file(QFileDialog::getSaveFileName(this,tr("Save Csv"), "", tr("Csv Files (*.csv)")));
    if (!file.open(QIODevice::WriteOnly)) return;
    QTextStream out(&file);
    for (int i = 0; i < m_pTable->columnCount();i++)
        out << m_pTable->horizontalHeaderItem(i)->text().toUtf8() << QString(",").toUtf8();
    out << QString("\r\n").toUtf8();
    GetMainWindow()->m_progress.setRange(0,m_pTable->rowCount());
    for (int i = 0 ; i < m_pTable->rowCount() ; i++ )
    {
        for (int j = 0; j < m_pTable->columnCount();j++)
        {
            out << m_pTable->item(i,j)->text().trimmed().toUtf8() << QString(",").toUtf8();
        }
        out << QString("\r\n").toUtf8();
        GetMainWindow()->m_progress.setValue(i);
        GetMainWindow()->m_progress.repaint();
    }
    file.close();
}
