/*
 * Copyright 2010  Jonas Emanuel Müller <zanoi@zanoi.net>
 *
 * 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, see <http://www.gnu.org/licenses/>.
 */

#include "episodemodel.h"
#include <QSqlRecord>
#include <QModelIndex>
#include <QSqlQuery>
#include <QRegExp>

#ifdef KDE
#include <KUrl>
#include <klocalizedstring.h>
#endif

namespace Videocatcher {

struct EpisodeModel::EpisodeModelPrivate
{
    EpisodeModelPrivate()
    {
    }
    
    ~EpisodeModelPrivate()
    {
    }

    QString m_tableName;
};

EpisodeModel::EpisodeModel(QObject* parent) : QSqlRelationalTableModel(parent), d(new EpisodeModelPrivate)
{
    d->m_tableName = "episodes";
    QSqlQuery query(QString("CREATE TABLE IF NOT EXISTS %1 (\
        id INTEGER PRIMARY KEY AUTOINCREMENT,\
        status  INT,\
        video_size  DOUBLE,\
        title   TEXT,\
        description  TEXT,\
        channel_id INTEGER,\
        date_published DOUBLE,\
        video_url   TEXT,\
        video_path  TEXT,\
        FOREIGN KEY (channel_id) REFERENCES channels\
        )").arg(d->m_tableName));
  
    setTable(d->m_tableName);
    
    setSort(Episode_Date_Published, Qt::DescendingOrder);
    setHeaderData(Episode_Title, Qt::Horizontal, i18nc("Refers to the titles of the episodes", "Title"));
    setHeaderData(Episode_Video_Size, Qt::Horizontal, i18n("Size"));
    setHeaderData(Episode_Description, Qt::Horizontal, i18n("Description"));
    setHeaderData(Episode_Status, Qt::Horizontal, i18n("Status"));
    setHeaderData(Episode_Date_Published, Qt::Horizontal, i18n("Released"));
    setEditStrategy(QSqlTableModel::OnManualSubmit);
 
    select();
}

EpisodeModel::~EpisodeModel()
{
    delete d;
}

QModelIndex EpisodeModel::addEpisode(const QString &title, const QString &description, const int channelId, const double datePublished, const QString &videoUrl, const double videoSize)
{
    QModelIndex modelIndex;

    int row = rowCount();
    bool success = insertRow(row);
    if(!success) {
        return QModelIndex();
    }

    modelIndex = index(row, Episode_Title);
    qDebug() << "adding episode: " << title;
    setData(modelIndex, title);

    modelIndex = index(row, Episode_Channel_Id);
    setData(modelIndex, channelId);

    modelIndex = index(row, Episode_Description);
    setData(modelIndex, description);

    modelIndex = index(row, Episode_Date_Published);
    setData(modelIndex, datePublished);
    
    modelIndex = index(row, Episode_Video_Size);
    setData(modelIndex, videoSize);

    //need to have a valid enclosure in order add it to model
    if(videoUrl.length() != 0 && KUrl(videoUrl).isValid()) {
        modelIndex = index(row, Episode_Video_Url);
        setData(modelIndex, videoUrl);

        modelIndex = index(row, Episode_Status);
        setData(modelIndex, Episode_Status_Not_Downloaded);
    } else {
        kWarning() << "could not find a valid enclosure URL. Setting episode to unavailable";
        modelIndex = index(row, Episode_Status);
        setData(modelIndex, Episode_Status_Unavailable);
    }

    return index(row, Episode_Id);
}

QModelIndex EpisodeModel::findById(const int id) const
{
    return match(index(0, Episode_Id), Qt::DisplayRole, id, 1, Qt::MatchExactly).first();
}

QModelIndex EpisodeModel::findByTitle(const QString &title) const
{
    return match(index(0, Episode_Title), Qt::DisplayRole, title, 1, Qt::MatchExactly).first();
}

QModelIndex EpisodeModel::findByUrl(const QString &url) const
{
    return match(index(0, Episode_Video_Url), Qt::DisplayRole, url,  1, Qt::MatchExactly).first();
}

QModelIndexList EpisodeModel::findAllByTitle(const QString &title) const
{
    return match(index(0, Episode_Title), Qt::DisplayRole, title, -1, Qt::MatchExactly);
}

QModelIndexList EpisodeModel::findAllByUrl(const QString &url) const
{
    return match(index(0, Episode_Video_Url), Qt::DisplayRole, url,  -1, Qt::MatchExactly);
}

QModelIndexList EpisodeModel::findAllbyChannelId(const int channelId) const
{
    return match(index(0, Episode_Channel_Id), Qt::DisplayRole, channelId,  -1, Qt::MatchExactly);
}

QModelIndexList EpisodeModel::findDownloadedEpisodes(const int channelId) const
{
    QModelIndexList episodes = findAllbyChannelId(channelId);
    QModelIndexList finalEpisodeList;
    foreach(const QModelIndex &episode, episodes)
    {
        QString path  = videoPath(episode);
        if(!path.isEmpty())
        {
            finalEpisodeList << episode;
        }
    }
    return finalEpisodeList;
}

QModelIndexList EpisodeModel::findDownloadingEpisodes() const
{
    QModelIndex modelIndex;
    QModelIndexList finalEpisodeList;
    
    for(int i=0; i<rowCount(); i++) {
      modelIndex = index(i, Episode_Status);
        if(data(modelIndex).toInt() >= 0) {
          finalEpisodeList << modelIndex;
        }
    }
    return finalEpisodeList;
}

QModelIndexList EpisodeModel::findByVideoPath(const QRegExp &regExp) const
{
    return match(index(0, Episode_Video_Path), Qt::DisplayRole, regExp,  -1, Qt::MatchRegExp);
}


int EpisodeModel::id(const QModelIndex &row) const
{
    QModelIndex modelIndex = index(row.row(), Episode_Id);
    return data(modelIndex).toInt();
}

int EpisodeModel::status(const QModelIndex &row) const
{
    QModelIndex modelIndex = index(row.row(), Episode_Status);
    return data(modelIndex).toInt();
}

QString EpisodeModel::title(const QModelIndex &row) const
{
    QModelIndex modelIndex = index(row.row(), Episode_Title);
    return data(modelIndex).toString();
}

int EpisodeModel::channelId(const QModelIndex &row) const
{
    QModelIndex modelIndex = index(row.row(), Episode_Channel_Id);
    return data(modelIndex).toInt();
}

QString EpisodeModel::description(const QModelIndex &row) const
{
    QModelIndex modelIndex = index(row.row(), Episode_Description);
    return data(modelIndex).toString();
}

double EpisodeModel::videoSize(const QModelIndex &row) const
{
    QModelIndex modelIndex = index(row.row(), Episode_Video_Size);
    return data(modelIndex).toDouble();
}

QString EpisodeModel::videoUrl(const QModelIndex &row) const
{
    QModelIndex modelIndex = index(row.row(), Episode_Video_Url);
    return data(modelIndex).toString();
}

QString EpisodeModel::videoPath(const QModelIndex &row) const
{
    QModelIndex modelIndex = index(row.row(), Episode_Video_Path);
    return data(modelIndex).toString();
}

double EpisodeModel::datePublished(const QModelIndex &row) const
{
    QModelIndex modelIndex = index(row.row(), Episode_Date_Published);
    return data(modelIndex).toDouble();
}

bool EpisodeModel::setStatus(const QModelIndex &row, const int data)
{
    QModelIndex modelIndex = index(row.row(), Episode_Status);
    return setData(modelIndex, data);
}

bool EpisodeModel::setTitle(const QModelIndex &row, const QString &data)
{
    QModelIndex modelIndex = index(row.row(), Episode_Title);
    return setData(modelIndex, data);
}

bool EpisodeModel::setDescription(const QModelIndex &row, const QString &data)
{
    QModelIndex modelIndex = index(row.row(), Episode_Description);
    return setData(modelIndex, data);
}

bool EpisodeModel::setChannelId(const QModelIndex &row, const int data)
{
    QModelIndex modelIndex = index(row.row(), Episode_Channel_Id);
    return setData(modelIndex, data);
}

bool EpisodeModel::setVideoSize(const QModelIndex &row, const double data)
{
    QModelIndex modelIndex = index(row.row(), Episode_Video_Size);
    return setData(modelIndex, data);
}

bool EpisodeModel::setVideoUrl(const QModelIndex &row, const QString &data)
{
    QModelIndex modelIndex = index(row.row(), Episode_Video_Url);
    return setData(modelIndex, data);
}

bool EpisodeModel::setVideoPath(const QModelIndex &row, const QString &data)
{
    QModelIndex modelIndex = index(row.row(), Episode_Video_Path);
    return setData(modelIndex, data);
}

bool EpisodeModel::setDatePublished(const QModelIndex &row, const double data)
{
    QModelIndex modelIndex = index(row.row(), Episode_Date_Published);
    return setData(modelIndex, data);
}

bool EpisodeModel::removeEpisode(const QModelIndex &index)
{
    return removeRow(index.row());
}

bool EpisodeModel::removeEpisodes(const QModelIndexList &indexList)
{
    bool success;
    bool overallSuccess = true;
    foreach(const QModelIndex &index, indexList)
    {
        success = removeEpisode(index);
        if(!success)overallSuccess = false; 
    }
    return overallSuccess;
}

QModelIndex EpisodeModel::findNewest(const int channelId)
{
    QSqlQuery query;

    //FIXME: ugly hack, please look away
    query.exec(QString("SELECT * FROM episodes WHERE date_published = (SELECT MAX(date_published) FROM episodes where channel_id = '%1')").arg(channelId));
    if(query.first()) {
        double date = query.record().value(Episode_Date_Published).toDouble();
        QModelIndexList result = match(index(0, Episode_Date_Published), Qt::DisplayRole, date, 1, Qt::MatchExactly);
        if(result.empty()) {
            qWarning() << "findNewest could not find an episode...something is wrong. channelId: " << channelId;
        }
        return (result.empty() ? QModelIndex() : result.first());
    } else {
        qDebug() << "could not find a newest date...either list is empty or something is very wrong";
        return QModelIndex();
    }
}

} //namespace Videocatcher
