/*******************************************************************************
 **
 ** smolbote: yet another qute browser
 ** Copyright (C) 2017  Xian Nox
 **
 ** 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 3 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, see <http://www.gnu.org/licenses/>.
 **
 ******************************************************************************/

#include "xbel.h"
#include <QFile>

#include <QTreeWidgetItem>

Xbel::Xbel(QTreeWidget *widget)
{
    treeWidget = widget;

    QStyle *style = treeWidget->style();
    folderIcon.addPixmap(style->standardPixmap(QStyle::SP_DirOpenIcon), QIcon::Normal, QIcon::On);
    folderIcon.addPixmap(style->standardPixmap(QStyle::SP_DirClosedIcon), QIcon::Normal, QIcon::Off);
    bookmarkIcon.addPixmap(style->standardPixmap(QStyle::SP_FileIcon));
}

bool Xbel::read(const QString &xbel)
{
    // no file specified
    if(xbel.isEmpty()) {
        return false;
    }

    QFile file(xbel);
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        // file cannot be opened
        qDebug("Cannot open xbel: %s", qUtf8Printable(xbel));
        return false;
    }

    xmlReader.setDevice(&file);

    if(xmlReader.readNextStartElement()) {
        if(xmlReader.name() == "xbel" && xmlReader.attributes().value("version") == "1.0") {
            qDebug("valid xbel");
            readChildElements(0);
        } else {
            qDebug("invalid xbel");
            return false;
        }

    }
    return true;
}

bool Xbel::write(const QString &xbel)
{
    // no file specified
    if(xbel.isEmpty()) {
        return false;
    }

    QFile file(xbel);
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        // file cannot be opened
        qDebug("Cannot open xbel: %s", qUtf8Printable(xbel));
        return false;
    }

    xmlWriter.setAutoFormatting(true);
    xmlWriter.setDevice(&file);

    xmlWriter.writeStartDocument();
    xmlWriter.writeDTD("<!DOCTYPE xbel>");
    xmlWriter.writeStartElement("xbel");
    xmlWriter.writeAttribute("version", "1.0");

    for(int i=0; i<treeWidget->topLevelItemCount(); i++) {
        writeItem(treeWidget->topLevelItem(i));
    }

    xmlWriter.writeEndDocument();
    return true;
}

void Xbel::readChildElements(QTreeWidgetItem *parentItem)
{
    while(xmlReader.readNextStartElement()) {
        if(xmlReader.name() == "title") {
            readTitle(parentItem);
        } else if(xmlReader.name() == "folder") {
            readChildElements(addFolder(parentItem));
        } else if(xmlReader.name() == "bookmark") {
            QTreeWidgetItem *item = addBookmark(parentItem);
            item->setText(1, xmlReader.attributes().value("href").toString());
            readChildElements(item);
        } else if(xmlReader.name() == "separator") {
            addSeparator(parentItem);
            xmlReader.skipCurrentElement();
        } else {
            xmlReader.skipCurrentElement();
        }
    }
}

void Xbel::readTitle(QTreeWidgetItem *item)
{
    item->setText(0, xmlReader.readElementText());
}

QTreeWidgetItem *Xbel::addFolder(QTreeWidgetItem *parentItem)
{
    QTreeWidgetItem *folderItem = createChildItem(parentFolder(parentItem), "folder");
    //folderItem->setExpanded(xmlReader.attributes().value("folded") != "no");
    treeWidget->setItemExpanded(folderItem, xmlReader.attributes().value("folded") != "yes");
    folderItem->setFlags(folderItem->flags() | Qt::ItemIsEditable);
    folderItem->setIcon(0, folderIcon);

    return folderItem;
}

QTreeWidgetItem *Xbel::addBookmark(QTreeWidgetItem *parentItem)
{
    QTreeWidgetItem *bookmarkItem = createChildItem(parentFolder(parentItem), "bookmark");
    bookmarkItem->setFlags((bookmarkItem->flags() | Qt::ItemIsEditable) & ~Qt::ItemIsDropEnabled);
    bookmarkItem->setIcon(0, bookmarkIcon);
    bookmarkItem->setText(0, "Unknown Title");
    bookmarkItem->setText(1, "Unknown Address");

    return bookmarkItem;
}

void Xbel::addSeparator(QTreeWidgetItem *parentItem)
{
    QTreeWidgetItem *separatorItem = createChildItem(parentFolder(parentItem), "separator");
    separatorItem->setFlags(separatorItem->flags() & ~Qt::ItemIsDropEnabled);
    separatorItem->setText(0, "-----");
}

QTreeWidgetItem *Xbel::parentFolder(QTreeWidgetItem *item)
{
    QTreeWidgetItem *parentItem = item;

    if(parentItem) {
        while(parentItem->data(0, Qt::UserRole) != "folder") {
            parentItem = parentItem->parent();
            if(parentItem == 0) {
                break;
            }
        }
    }

    return parentItem;
}

QTreeWidgetItem *Xbel::createChildItem(QTreeWidgetItem *item, const QString &type)
{
    QTreeWidgetItem *childItem;
    if(item) {
        childItem = new QTreeWidgetItem(item);
    } else {
        childItem = new QTreeWidgetItem(treeWidget);
    }
    childItem->setData(0, Qt::UserRole, type);
    return childItem;
}

void Xbel::writeItem(QTreeWidgetItem *item)
{
    QString tagName = item->data(0, Qt::UserRole).toString();
    if (tagName == "folder") {
        xmlWriter.writeStartElement(tagName);
        xmlWriter.writeAttribute("folded", treeWidget->isItemExpanded(item) ? "no" : "yes");
        xmlWriter.writeTextElement("title", item->text(0));
        for (int i = 0; i < item->childCount(); ++i) {
            writeItem(item->child(i));
        }
        xmlWriter.writeEndElement();
    } else if (tagName == "bookmark") {
        xmlWriter.writeStartElement(tagName);
        if (!item->text(1).isEmpty()) {
            xmlWriter.writeAttribute("href", item->text(1));
        }
        xmlWriter.writeTextElement("title", item->text(0));
        xmlWriter.writeEndElement();
    } else if (tagName == "separator") {
        xmlWriter.writeEmptyElement(tagName);
    }
}