/*
 *
 * Copyright (C) 2002 George Staikos <staikos@kde.org>
 * Copyright (C) 2002 Rich Moore <rich@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., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <stdlib.h>
#include <unistd.h>

#include <qapplication.h>
#include <qtimer.h>

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

#include "channel.h"
#include "channelstore.h"
#include "channelscannerregion.h"

#include "channelscanner.h"
#include "channelscanner.moc"
#include "qvsrcplugin.h"

ChannelScanner::ChannelScanner( QObject *parent, const char *name )
    : QObject( parent, name ),
      dev(0), freq(0), min(0), max(0), start(0), adj(0),
      percentDone(0), lastProgress(0), onePercent(0),
      chanStore(0), chan(0), region(0)
{
    connect( this, SIGNAL( foundChannel() ), SLOT( addChannel() ) );
}

ChannelScanner::~ChannelScanner()
{
    delete region;
}

void ChannelScanner::setDevice( QVSourcePlugin *device )
{
    dev = device;
    freq = min = 90000;   // FIXME
    max = 800000;

    if ( max == 0x7fff )
	max = max / 4;
}

void ChannelScanner::setStore( ChannelStore *store )
{
    chanStore = store;
}

void ChannelScanner::scan()
{
    kdDebug() << "ChannelScanner::scan() starting" << endl;

    if ( !first() ) {
	kdWarning() << "ChannelScanner::scan() Cannot start, first() returned error" << endl;
	return;
    }

    emit started();
    QTimer::singleShot( 0, this, SLOT(scanChunk()) );
}

void ChannelScanner::addChannel()
{
    kdDebug() << "ChannelScanner::addChannel()" << endl;
    if ( !chanStore )
	return;

    chanStore->addChannel( (freq+start)/2 + 1 );
}

void ChannelScanner::scanChunk()
{
    unsigned long count = 0;
    bool hasNext;
    do {
	if ( scanCurrent() ) {
	    kdDebug() << "ChannelScanner::scan() foundChannel freq=" << freq << endl;
	    emit foundChannel();
	}

	hasNext = next();
	count++;
    } while( hasNext && (count < oneChunk) );

    if ( hasNext ) {
	QTimer::singleShot( 0, this, SLOT(scanChunk()) );
    }
    else {
	last();
	emit done();
	emit done( (chan ? true : false) );
	kdDebug() << "ChannelScanner::scanChunk() all done" << endl;
    }
}

bool ChannelScanner::scanCurrent()
{
    dev->setFrequency( freq );
    usleep( 20 );

    if ( dev->signal() > 60000 ) {
	if ( start == 0 )
	    start = freq;
    }
    else if ( start != 0 ) {
	if ( adj < 5 )
	    adj++;
	else {
	    adj = 0;
	    start = 0;
	    return true;
	}
    }

    return false;
}

bool ChannelScanner::first()
{
    if ( !dev )
	return false;

    freq = min;
    start = 0;
    adj = 0;
  
    onePercent = (max-min)/100;
    oneChunk = (max-min)/1000;
    percentDone = 0; // freq value we last sent a progress signal for
    lastProgress = min;

    emit started();
    emit progress( percentDone );
    chan = 0;

    if ( region )
	return regionFirst();

    return true;
}

bool ChannelScanner::next()
{
    if ( region ) {
	if ( !regionNext() )
	    return false; // Finished
    }
    else {
	freq++;
    }

    if ( freq > max ) {
	freq = min;
	return false; // Finished
    }

    if ( (freq-lastProgress) >= onePercent ) {
	percentDone++;
	lastProgress = freq;
	kdDebug() << "ChannelScanner::scan() " << percentDone << "% progress made, freq=" << freq << endl;

	emit progress( percentDone );
    }

    return true;
}

bool ChannelScanner::last()
{
    emit done();
    return true;
}

bool ChannelScanner::loadRegionFile( const QString &filename )
{
    if ( filename.isNull() ) {
	kdWarning() << "ChannelScanner::loadRegionFile() Clearing region defs" << endl;
	if ( region )
	    delete region;
	region = 0;
	return true;
    }

    ChannelScannerRegion *reg = new ChannelScannerRegion();
    if ( !reg->load( filename ) ) {
	delete reg;
	return false;
    }
    delete region;
    region = reg;

    kdDebug() << "ChannelScanner::loadRegionFile() Loaded region, " << reg->name() << endl;
    return true;
}

bool ChannelScanner::regionFirst()
{
    if ( !region->first() )
	return false;

    freq = region->frequency() - 10;

    kdDebug() << "ChannelScanner::regionFirst() freq=" << freq << endl;
    return true;
}

bool ChannelScanner::regionNext()
{
    // If we're still in the range for the current tuning just inc freq
    unsigned long delta = labs(freq - region->frequency());
    if ( delta < 15 ) {
	freq++;
	return true;
    }

    bool hasNext = region->next();
    if ( !hasNext ) {
	kdDebug() << "ChannelScanner::regionNext() No more channels" << endl;
	return false;
    }

    freq = region->frequency() - 10;
    kdDebug() << "ChannelScanner::regionNext() min=" << min << " max=" << max << endl;
    kdDebug() << "ChannelScanner::regionNext() Next channel, freq=" << freq << endl;

    return true;
}




