/*
 * Copyright (c) 2010 Mark Liversedge (liversedge@gmail.com)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "LTMChartParser.h"
#include "LTMSettings.h"
#include "LTMTool.h"
#include "Athlete.h"

#include <QDate>
#include <QDebug>

bool LTMChartParser::startDocument()
{
    buffer.clear();
    return true;
}

// to see the format of the charts.xml file, look at the serialize()
// function at the bottom of this source file.
bool LTMChartParser::endElement( const QString&, const QString&, const QString &qName )
{
    //
    // Single Attribute elements
    //
    if(qName == "chart") {
        QString string = buffer.mid(1,buffer.length()-2);

        QByteArray base64(string.toLatin1());
        QByteArray unmarshall = QByteArray::fromBase64(base64);
        QDataStream s(&unmarshall, QIODevice::ReadOnly);
        LTMSettings x;
        s >> x;
        settings << x;
    } 
    return true;
}

bool LTMChartParser::startElement( const QString&, const QString&, const QString &, const QXmlAttributes &)
{
    buffer.clear();
    return true;
}

bool LTMChartParser::characters( const QString& str )
{
    buffer += str;
    return true;
}

QList<LTMSettings>
LTMChartParser::getSettings()
{
    return settings;
}

bool LTMChartParser::endDocument()
{
    return true;
}

// static helper to protect special xml characters
// ideally we would use XMLwriter to do this but
// the file format is trivial and this implementation
// is easier to follow and modify... for now.
static QString xmlprotect(QString string)
{
    QTextEdit trademark("&#8482;"); // process html encoding of(TM)
    QString tm = trademark.toPlainText();

    QString s = string;
    s.replace( tm, "&#8482;" );
    s.replace( "&", "&amp;" );
    s.replace( ">", "&gt;" );
    s.replace( "<", "&lt;" );
    s.replace( "\"", "&quot;" );
    s.replace( "\'", "&apos;" );
    return s;
}

//
// Write out the charts.xml file
//
// Most of the heavy lifting is done by the LTMSettings
// << and >> operators. We just put them into the character
// data for a chart.
//
void
LTMChartParser::serialize(QString filename, QList<LTMSettings> charts)
{
    // open file - truncate contents
    QFile file(filename);
    if (!file.open(QFile::WriteOnly)) {
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Critical);
        msgBox.setText(QObject::tr("Problem Saving Charts Configuration"));
        msgBox.setInformativeText(QObject::tr("File: %1 cannot be opened for 'Writing'. Please check file properties.").arg(filename));
        msgBox.exec();
        return;
    };
    file.resize(0);
    QTextStream out(&file);
    out.setCodec("UTF-8");

    // begin document
    out << QString("<charts version=\"%1\">\n").arg(LTM_VERSION_NUMBER);

    // write out to file
    foreach (LTMSettings chart, charts) {

        out <<"\t<chart name=\"" << xmlprotect(chart.name) <<"\">\"";
        // chart name
        QByteArray marshall;
        QDataStream s(&marshall, QIODevice::WriteOnly);
        s << chart;
        out<<marshall.toBase64();
        out<<"\"</chart>\n";
    }

    // end document
    out << "</charts>\n";

    // close file
    file.close();
}

ChartTreeView::ChartTreeView(Context *context) : context(context)
{
    setDragDropMode(QAbstractItemView::InternalMove);
    setDragDropOverwriteMode(true);
#ifdef Q_OS_MAC
    setAttribute(Qt::WA_MacShowFocusRect, 0);
#endif

}

void
ChartTreeView::dropEvent(QDropEvent* event)
{
    QTreeWidgetItem* target = (QTreeWidgetItem *)itemAt(event->pos());
    int idxTo = indexFromItem(target).row();

    // when dragging to past the last one, we get -1, so lets
    // set the target row to the very last one
    if (idxTo < 0) idxTo = invisibleRootItem()->childCount()-1;

    int offsetFrom = 0;
    int offsetTo = 0;

    QList<int> idxToList;

    foreach (QTreeWidgetItem *p, selectedItems()) {
        int idxFrom = indexFromItem(p).row();

        context->athlete->presets.move(idxFrom+offsetFrom, idxTo+offsetTo);

        idxToList << idxTo+(idxFrom>idxTo?offsetTo:offsetFrom);

        if (idxFrom<idxTo)
            offsetFrom--;
        else
            offsetTo++;
    }

    // the default implementation takes care of the actual move inside the tree
    //QTreeWidget::dropEvent(event);

    // reset
    context->notifyPresetsChanged();

    clearSelection();
    // xxx dgr removed because
    // select it!
    /*foreach (int idx, idxToList) {
        invisibleRootItem()->child(idx)->setSelected(true);
    }*/
}

QStringList 
ChartTreeView::mimeTypes() const
{
    QStringList returning;
    returning << "application/x-gc-charts";

    return returning;
}

QMimeData *
ChartTreeView::mimeData (const QList<QTreeWidgetItem *> items) const
{
    QMimeData *returning = new QMimeData;

    // we need to pack into a byte array
    QByteArray rawData;
    QDataStream stream(&rawData, QIODevice::WriteOnly);
    stream.setVersion(QDataStream::Qt_4_6);

    // pack data 
    stream << (quint64)(context); // where did this come from?
    stream << items.count();
    foreach (QTreeWidgetItem *p, items) {

        // get the season this is for
        int index = p->treeWidget()->invisibleRootItem()->indexOfChild(p);

        // season[index] ...
        stream << context->athlete->presets[index]; // name
    }

    // and return as mime data
    returning->setData("application/x-gc-charts", rawData);
    return returning;
}
