/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
**     the names of its contributors may be used to endorse or promote
**     products derived from this software without specific prior written
**     permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtGui>
#include <QtNetwork>
#include "csvview.h"

//! [constructor]
CSVView::CSVView(const QString &mimeType, QWidget *parent)
    : QTableView(parent)
{
    this->mimeType = mimeType;
}
//! [constructor]

//! [update model begin]
void CSVView::updateModel()
{
    QNetworkReply *reply = static_cast<QNetworkReply *>(sender());

    if (reply->error() != QNetworkReply::NoError)
        return;

    bool hasHeader = false;
    QString charset = "latin1";
//! [update model begin]

    foreach (QString piece, mimeType.split(";")) {
        piece = piece.trimmed();
        if (piece.contains("=")) {
            int index = piece.indexOf("=");
            QString left = piece.left(index).trimmed();
            QString right = piece.mid(index + 1).trimmed();
            if (left == "header")
                hasHeader = (right == "present");
            else if (left == "charset")
                charset = right;
        }
    }

//! [read data begin]
    QTextStream stream(reply);
    stream.setCodec(QTextCodec::codecForName(charset.toLatin1()));

    QStandardItemModel *model = new QStandardItemModel(this);
//! [read data begin]
    QList<QStandardItem *> items;
    bool firstLine = hasHeader;
    bool wasQuote = false;
    bool wasCR = false;
    bool quoted = false;
    QString text;

    while (!stream.atEnd()) {

        QString ch = stream.read(1);

        if (wasQuote) {
            if (ch == "\"") {
                if (quoted) {
                    text += ch;         // quoted "" are inserted as "
                    wasQuote = false;   // no quotes are pending
                } else {
                    quoted = true;      // unquoted "" starts quoting
                    wasQuote = true;    // with a pending quote
                }
                continue;               // process the next character

            } else {
                quoted = !quoted;       // process the pending quote
                wasQuote = false;       // no quotes are pending
            }                           // process the current character

        } else if (wasCR) {
            wasCR = false;

            if (ch == "\n") {           // CR LF represents the end of a row
                if (!text.isEmpty())
                    items.append(new QStandardItem(QString(text)));

                addRow(firstLine, model, items);
                items.clear();
                text = "";
                firstLine = false;
                continue;               // process the next character
            } else
                text += "\r";           // CR on its own is inserted
        }                               // process the current character

        // wasQuote is never true here.
        // wasCR is never true here.

        if (ch == "\"")
            wasQuote = true;            // handle the pending quote later

        else if (ch == ",") {
            if (quoted)
                text += ch;
            else {
                items.append(new QStandardItem(QString(text)));
                text = "";
            }
        }

        else if (ch == "\r") {
            if (!quoted)
                wasCR = true;
            else
                text += ch;
        }

        else if (ch == "\n")
            text += ch;
        else
            text += ch;

    }

    if (items.count() > 0)
        addRow(firstLine, model, items);

//! [update model]
    reply->close();

    setModel(model);
    resizeColumnsToContents();
    horizontalHeader()->setStretchLastSection(true);
}
//! [update model]

void CSVView::addRow(bool firstLine, QStandardItemModel *model,
                     const QList<QStandardItem *> &items)
{
    if (firstLine) {
        for (int j = 0; j < items.count(); ++j)
            model->setHorizontalHeaderItem(j, items[j]);
    } else
        model->appendRow(items);
}
