/* -*- Mode: c++ -*-
 * vim: set expandtab tabstop=4 shiftwidth=4:
 *
 * Original Project
 *      MythTV      http://www.mythtv.org
 *
 * Copyright (c) 2004, 2005 John Pullan <john@pullan.org>
 * Copyright (c) 2005 - 2007 Daniel Kristjansson
 *
 * Description:
 *     Collection of classes to provide channel scanning functionallity
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
 *
 */

// System headers
#include <unistd.h>

// Std C++
#include <algorithm>
using namespace std;

// MythTV headers
#include "mythcontext.h"
#include "scanwizard.h"
#include "channelscanner_gui.h"
#include "channelscanner_gui_scan_pane.h"
#include "channelimporter.h"
#include "loglist.h"
#include "channelscan_sm.h"

#include "channelbase.h"
#include "dtvsignalmonitor.h"
#include "dvbsignalmonitor.h"
#include "mpegstreamdata.h"

#define LOC QString("ChScanGUI: ")
#define LOC_ERR QString("ChScanGUI, Error: ")

QString ChannelScannerGUI::kTitle = QString::null;

// kTitle must be initialized after the Qt translation system is initialized...
static void init_statics(void)
{
    static QMutex lock;
    static bool do_init = true;
    QMutexLocker locker(&lock);
    if (do_init)
    {
        ChannelScannerGUI::kTitle = ChannelScannerGUI::tr("Scanning");
        do_init = false;
    }
}

ChannelScannerGUI::ChannelScannerGUI(void)
    : StackedConfigurationGroup(false, true, false, false),
      scanStage(NULL), doneStage(new LogList())
{
    init_statics();

    setLabel(kTitle);

    addChild(doneStage);
}

ChannelScannerGUI::~ChannelScannerGUI()
{
    Teardown();
    if (scanMonitor)
    {
        post_event(scanMonitor, ScannerEvent::ScanShutdown,
                   MythDialog::Rejected);
    }
}

void ChannelScannerGUI::HandleEvent(const ScannerEvent *scanEvent)
{
    switch (scanEvent->eventType())
    {
        case ScannerEvent::ScanComplete:
        {
            if (scanStage)
                scanStage->SetScanProgress(1.0);
            raise(doneStage);

            // HACK: make channel insertion work after [21644]
            post_event(scanMonitor, ScannerEvent::ScanShutdown,
                       kDialogCodeAccepted);
        }
        break;

        case ScannerEvent::ScanShutdown:
        {
            if (scanEvent->ConfigurableValue())
            {
                setLabel(scanEvent->ConfigurableValue()->getLabel());
                raise(scanEvent->ConfigurableValue());
            }

            ScanDTVTransportList transports;
            if (sigmonScanner)
            {
                sigmonScanner->StopScanner();
                transports = sigmonScanner->GetChannelList();
            }

            Teardown();

            int ret = scanEvent->intValue();
            if (!transports.empty() || (MythDialog::Rejected != ret))
                Process(transports);
        }
        break;

        case ScannerEvent::AppendTextToLog:
        {
            if (scanStage)
                scanStage->AppendLine(scanEvent->strValue());
            doneStage->AppendLine(scanEvent->strValue());
            messageList += scanEvent->strValue();
        }
        break;

        default:
            break;
    }

    if (!scanStage)
        return;

    switch (scanEvent->eventType())
    {
        case ScannerEvent::SetStatusText:
            scanStage->SetStatusText(scanEvent->strValue());
            break;
        case ScannerEvent::SetStatusTitleText:
            scanStage->SetStatusTitleText(scanEvent->strValue());
            break;
        case ScannerEvent::SetPercentComplete:
            scanStage->SetScanProgress(scanEvent->intValue() * 0.01);
            break;
        case ScannerEvent::SetStatusRotorPosition:
            scanStage->SetStatusRotorPosition(scanEvent->intValue());
            break;
        case ScannerEvent::SetStatusSignalLock:
            scanStage->SetStatusLock(scanEvent->intValue());
            break;
        case ScannerEvent::SetStatusSignalToNoise:
            scanStage->SetStatusSignalToNoise(scanEvent->intValue());
            break;
        case ScannerEvent::SetStatusSignalStrength:
            scanStage->SetStatusSignalStrength(scanEvent->intValue());
            break;
        default:
            break;
    }
}

void ChannelScannerGUI::Process(const ScanDTVTransportList &_transports)
{
    ChannelImporter ci(true, true, true, true, true,
                       freeToAirOnly, serviceRequirements);
    ci.Process(_transports);
}
       
void ChannelScannerGUI::InformUser(const QString &error)
{
    MythPopupBox::showOkPopup(gContext->GetMainWindow(),
                              tr("ScanWizard"), error);
}

void ChannelScannerGUI::quitScanning(void)
{
    if (scanMonitor)
    {
        post_event(scanMonitor, ScannerEvent::ScanShutdown,
                   MythDialog::Rejected, doneStage);
    }
}

void ChannelScannerGUI::MonitorProgress(bool lock, bool strength,
                                        bool snr,  bool rotor)
{
    scanStage = new ChannelScannerGUIScanPane(
        lock, strength, snr, rotor, this,SLOT(quitScanning(void)));
    for (uint i = 0; i < (uint) messageList.size(); i++)
        scanStage->AppendLine(messageList[i]);

    addChild(scanStage);
    raise(scanStage);
}
