/*
 *
 * Copyright (C) 2002 George Staikos <staikos@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */


#include <qstring.h>
#include <qfile.h>

#include <assert.h>

#include <klocale.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kstandarddirs.h>

#include "kdetv.h"
#include "channel.h"
#include "channelio.h"

#include "channelstore.h"
#include "channeladaptor.h"
#include "channelstore.moc"
#include "sourcemanager.h"

#include "cfgdata.h"

ChannelStore::ChannelStore( Kdetv *ktv, QObject *parent, const char *name )
    :QObject( parent),
      _silentModifications(false),
      _ktv(ktv),
      _defaultFileName(KGlobal::dirs()->saveLocation("kdetv") + "channels.xml")
{
    setObjectName(name);
    new ChannelAdaptor(this);
    QDBusConnection::sessionBus().registerObject("/Kdetv/ChannelStore", this);

    _channels.setAutoDelete(true);
    _metaInfo = new KdetvChannelPlugin::ChannelFileMetaInfo();
}

ChannelStore::~ChannelStore()
{
}

void ChannelStore::clear()
{
    _channels.clear();
    emit loaded();
}

const QMap<QString, QString>& ChannelStore::fileFormatsRead() const
{
    return ChannelIO::fileFormatsRead(_ktv);
}

const QMap<QString, QString>& ChannelStore::fileFormatsWrite() const
{
    return ChannelIO::fileFormatsWrite(_ktv);
}

bool ChannelStore::load( const QString &file, const QString& fmt )
{
    if (file.isEmpty()) return false;

    ChannelStore tmp(_ktv, this, "tempStore");

    _silentModifications = true;
    bool rc = ChannelIO::load( _ktv, &tmp, &tmp.getMetaInfo(), file, fmt );
    _silentModifications = false;
    if (rc) {
        _channels.clear();
        addChannels(tmp);
        fixupControlLists();
        emit loaded();
    }

    return rc;
}

bool ChannelStore::load( QIODevice* dev, const QString& fmt )
{
    ChannelStore tmp(_ktv, this, "tempStore");

    _silentModifications = true;
    bool rc = ChannelIO::load( _ktv, &tmp, &tmp.getMetaInfo(), dev, fmt );
    _silentModifications = false;
    if (rc) {
        _channels.clear();
        addChannels(tmp);
        fixupControlLists();
        emit loaded();
    }

    return rc;
}

bool ChannelStore::save( const QString &file, const QString& fmt )
{
    if (file.isEmpty()) return false;
    if (fmt.isEmpty()) return false;

    _silentModifications = true;
    bool rc = ChannelIO::save( _ktv, this, _metaInfo, file, fmt );
    _silentModifications = false;
    if (rc)
        emit saved();
    return rc;
}

bool ChannelStore::save( QIODevice* dev, const QString& fmt )
{
    if (fmt.isEmpty()) return false;

    _silentModifications = true;
    bool rc = ChannelIO::save( _ktv, this, _metaInfo, dev, fmt );
    _silentModifications = false;
    if (rc)
        emit saved();
    return rc;
}

void ChannelStore::addChannel( Channel *channel )
{
    assert(channel);

    channel->setNumber( _channels.last() ? _channels.last()->number()+1 : _ktv->config()->channelNumberingStart );

    if ( channel->name().isNull() || channel->name().isEmpty() )
	channel->setName( i18n("Channel %1",channel->number()) );

    _channels.inSort( channel );
    if (!_silentModifications)
        emit channelAdded(channel);
}

void ChannelStore::addChannels( const ChannelStore& nstore)
{
    _silentModifications = true;
    Channel* ch;
    for (Q3PtrListIterator<Channel> it(nstore._channels); (ch = it.current()) != 0; ++it) {
        Channel* channel = new Channel(this);
        *channel = ch;
        addChannel(channel);
    }

    *_metaInfo = nstore.getMetaInfo();

    _silentModifications = false;
    emit loaded();
}

Channel *ChannelStore::channelNumber(int n)
{
    Channel *c = 0;
    for (c = _channels.first(); c; c = _channels.next()) {
        if (c->number() == n)
            break;
    }
    return c;
}

void ChannelStore::renumber( int start )
{
    for ( Channel *c = _channels.first(); c; c = _channels.next() ) {
        c->setNumber(start++);
    }
    emit loaded();
}

void ChannelStore::renumber()
{
    renumber(_ktv->config()->channelNumberingStart);
}

Channel *ChannelStore::channelAfter( Channel *channel )
{
    int rc = _channels.findRef(channel);
    if (rc == -1 || rc >= (int)_channels.count()-1)
        return _channels.at(0);

    return _channels.at(rc+1);
}

Channel *ChannelStore::channelBefore( Channel *channel )
{
    int rc = _channels.findRef(channel);
    if (rc == -1)
        return _channels.at(0);

    if (rc == 0)
        return _channels.at(_channels.count()-1);

    return _channels.at(rc-1);
}

int ChannelStore::removeChannelNumber( int n )
{
    for (Channel *c = _channels.first(); c; c = _channels.next()) {
        if (c->number() == n) {
            return removeChannel(c);
        }
    }

    return -1;
}

int ChannelStore::removeChannel( int idx )
{
    Channel *tmp = _channels.at(idx);
    int rc = _channels.remove(idx) ? 0 : -1;

    if (rc == 0 && !_silentModifications)
        emit channelRemoved(tmp);

    return rc;
}

int ChannelStore::removeChannel( Channel *channel )
{
    Channel *tmp = channel;
    int rc = _channels.remove(channel) ? 0 : -1;

    if (rc == 0 && !_silentModifications)
        emit channelRemoved(tmp);

    return rc;
}

void ChannelStore::fixupControlLists()
{
    if( (_metaInfo->_globalControls.count() == 1) &&
        (_metaInfo->_globalControls.contains("unknown"))) {
        _metaInfo->_globalControls[_ktv->sourceManager()->device()] = _metaInfo->_globalControls["unknown"];
        _metaInfo->_globalControls.remove("unknown");
    }

    for(unsigned int i=0; i<count(); i++) {
        QMap<QString, Channel::PropertyList> list = channelAt(i)->allControls();
        if( (list.count() == 1) &&
            (list.contains("unknown"))) {
            list[_ktv->sourceManager()->device()] = list["unknown"];
            list.remove("unknown");
        }
    }
}
