/*
 * See the README file for copyright information and how to reach the author.
 *
 */

#include "common.h"

class cRMMenuChannelItem:
    public cRMChannel
{
    public:
        cOsdItem* item;

        cRMMenuChannelItem(cChannel* _channel):
                cRMChannel(_channel)
        {
            item=NULL;
        };

        cRMMenuChannelItem(cRMChannel* _channel):
                cRMChannel(_channel)
        {
            item=NULL;
        };
};

cRMChannelMenu::cRMChannelMenu():
        cOsdMenu(tr("Channels"), 33)
{
    keepAlive=false;
    scanActive=false;
    updateMenu=false;
    displayVdrChannels=true;

    tuningChannel=NULL;
    cRMDevice* device=PvrUsb2->FirstDevice();
    if(device) {
        for(cChannel* channel=Channels.First(); 
               channel; channel=Channels.Next(channel))
        {
            if(device->ProvidesCa(channel)) {
                if(strcmp(channel->Name(), tr("PVR USB2 Tuning"))==0) {
                    tuningChannel=new cRMChannel(channel);
                } else {
                    channelList.Add(new cRMMenuChannelItem(channel)); 
                }
            }
        }
    }
    if(!tuningChannel) {
        tuningChannel=new cRMChannel(10001);
        tuningChannel->SetName(tr("PVR USB2 Tuning"));
        tuningChannel->Write2VdrChannel();
    }
    Channels.SwitchTo(tuningChannel->VdrChannelNumber());

    DisplayMenu();
    SelectFirstLine();
    Tune2CurrentChannel();
}

cRMChannelMenu::~cRMChannelMenu()
{
    StopChannelScan();
    if(tuningChannel) {
        tuningChannel->DeleteVdrChannel();
        delete tuningChannel;
        tuningChannel=NULL;
        Channels.SwitchTo(Channels.GetNextNormal(-1));
    }
}

bool cRMChannelMenu::StopChannelScan()
{
    if(PvrUsb2) {
        cRMDevice* device=PvrUsb2->FirstDevice();
        if(device) {
            return device->StopChannelScan();
        }
    }
    return false;
}

bool cRMChannelMenu::StartChannelScan()
{
    if(PvrUsb2) {
        cRMDevice* device=PvrUsb2->FirstDevice();
        if(device) {
            return device->StartChannelScan(this);
        }
    }
    return false;
}

cRMMenuChannelItem* cRMChannelMenu::GetChannel(cOsdItem* _item)
{
    for(cRMMenuChannelItem* channel=channelList.First(); channel;
            channel=channelList.Next(channel))
    {
        if(!channel->item) {
            cPvrUsb2Plugin::LogError("No OSD Item for: %s (%d)",
                    channel->Name(), channel->Frequency());
        }
        if(channel->item==_item) {
            return channel;
        }
    }
    return NULL;
}

void cRMChannelMenu::SelectFirstLine()
{
    if(Get(3)) {
        SetCurrent(Get(3));
    } else {
        SetCurrent(Last());
    }
}

void cRMChannelMenu::SetHelpKeys()
{
    const char* red=tr("Scan");
    if(scanActive) {
        red=tr("Stop");
    }
    const char* yellow=NULL;
    if(!scanActive) {
        yellow=tr("Remove");
    }
    const char* blue=NULL;
    if(!scanActive) {
        blue=tr("Tune");
    }

    cRMChannel* channel=GetChannel(Get(Current()));
    const char* green=NULL;
    if(channel && channel->IsModified()) {
        green=tr("Update");
        if(!channel->HaveVdrChannel()) {
            green=tr("Add");
        }
        SetHelp(NULL, green, NULL, NULL);
    }
    SetHelp(red, green, yellow, blue);
}

void cRMChannelMenu::DisplayMenu() {
    int current=Current();
    if(Get(current)==Last()) {
        current=-1;
    }
    Clear();

    SetHelpKeys();

    cRMDevice* device=PvrUsb2->FirstDevice();
    int frequency=device->CurrentValue(eSetupFrequency);
    int minFrequency=device->MinValue(eSetupFrequency);
    int maxFrequency=device->MaxValue(eSetupFrequency);

    char tmp[100];
    snprintf(tmp, sizeof(tmp), "%s: %'.2f MHz", tr("Frequency"),
            1.0*frequency/1000);
    Add(cRMMenuItems::Label(tmp));

    snprintf(tmp, sizeof(tmp), "%s",
            cRMSetupTools::Index2StringValue(eBigSliderItem,
                    cRMSetupTools::Value2Index(eBigSliderItem,
                            frequency, minFrequency, maxFrequency)));
    Add(cRMMenuItems::Label(tmp));
    Add(cRMMenuItems::Label(""));
    mutex.Lock();
    for(cRMMenuChannelItem* channel=channelList.First(); channel;
            channel=channelList.Next(channel))
    {
        cOsdItem* item=cRMMenuItems::ChannelItem(channel);
        channel->item=item;
        Add(item);
    }
    mutex.Unlock();

    if(current<0) {
        SetCurrent(Last());
    } else if(current<2) {
        SelectFirstLine();
    } else {
        SetCurrent(Get(current));
    }

    Display();
}

bool cRMChannelMenu::HaveNewChannels()
{
    for(cRMMenuChannelItem* channel=channelList.First(); channel;
            channel=channelList.Next(channel))
    {
        if(channel->HaveVdrChannel()) {
            return true;
        }
    }
    return false;
}

void cRMChannelMenu::Tune2CurrentChannel()
{
    if(!scanActive) {
        cRMMenuChannelItem* channel=GetChannel(Get(Current()));
        if(channel) {
            cRMDevice* device=PvrUsb2->FirstDevice();
            device->Tune(channel->Frequency()+channel->Offset());
            updateMenu=true;
        }
    }
}

void cRMChannelMenu::ReNumber()
{
    for(cRMMenuChannelItem* channel=channelList.First(); channel;
            channel=channelList.Next(channel))
    {
        channel->UpdateVdrChannel();
    }
}

eOSState cRMChannelMenu::ProcessKey(eKeys _key)
{
    eOSState state=cOsdMenu::ProcessKey(_key);

    switch(state) {
        // key already handled but we have to deal with it anyway
        case osContinue:
            if(HasSubMenu()) {
                return state;
            }
            switch(_key) {
                case kUp|k_Repeat:
                case kUp:
                case kDown|k_Repeat:
                case kDown:
                    Tune2CurrentChannel();
                    break;
                default:
                    return state;
            }
            break;
        // unhandled key
        case osUnknown:
            switch(_key) {
                case kNone:
                    if(keepAlive) {
                        cRemote::Put(kKeepAlive);
                    }
                    if(updateMenu || scanActive) {
                        updateMenu=false;
                        DisplayMenu();
                    }
                    SetStatus(NULL);
                    break;
                case kBack:
                    StopChannelScan();
                    return osBack;
                case kOk:
                case kBlue:
                    if(!scanActive) {
                        updateMenu=false;
                        return AddSubMenu(new
                                cRMTuneMenu(this, GetChannel(Get(Current()))));
                    }
                    break;
                case kGreen: {
                    cRMChannel* channel=GetChannel(Get(Current()));
                    if(!channel->IsModified()) {
                        break;
                    }
                    channel->Write2VdrChannel();
                    DisplayMenu();
                    if(channel->HaveVdrChannel()) {
                        SetStatus(tr("Channel updated"));
                    }
                    SetHelpKeys();
                    break;
                }
                case kYellow:
                    if(!scanActive) {
                        if(Interface->Confirm(tr("Delete channel?"))) {
                            cRMChannel* channel=GetChannel(Get(Current()));
                            channel->DeleteVdrChannel();
                            channelList.Del(channel); 
                            ReNumber();
                            DisplayMenu();
                        }
                    }
                    break;
                case kRed:
                    if(scanActive) {
                        StopChannelScan();
                        if(!HaveNewChannels()) {
                            displayVdrChannels=true;
                        }
                    } else {
                        channelList.Clear();
                        StartChannelScan();
                        scanActive=true;
                        displayVdrChannels=false;
                        keepAlive=true;
                    }
                    DisplayMenu();
                    break;
                default:
                    break;
            }
            break;
        case osBack:
            StopChannelScan();
            return state;
        default:
            return state;
    }
    return osContinue;
}

void cRMChannelMenu::NewChannel(cRMChannelList* _list)
{
    mutex.Lock();
    channelList.Clear();

    for(cRMChannel* channel=_list->First(); channel;
            channel=_list->Next(channel))
    {
        channelList.Add(new cRMMenuChannelItem(channel));
    }
    mutex.Unlock();
    updateMenu=true;
}

void cRMChannelMenu::ScanFinished()
{
    updateMenu=true;
    scanActive=false;
    keepAlive=false;
    Tune2CurrentChannel();
}
