#include "tvguidengosd.h"

cTVGuideOSD::cTVGuideOSD(skindesignerapi::cPluginStructure *plugStruct) : cSkindesignerOsdObject(plugStruct) {
    timeManager = NULL;
    epgGrid = NULL;
    channelJumper = NULL;
    detailView = NULL;
    recMenuView = NULL;
}

cTVGuideOSD::~cTVGuideOSD(void) {
    esyslog("tvguideng: closing");
    if (recMenuView && recMenuView->Active()) {
        recMenuView->Close();
    }
    if (timeManager)
        delete timeManager;
    if (epgGrid)
        delete epgGrid;
    if (channelJumper)
        delete channelJumper;
    if (detailView)
        delete detailView;
    if (recMenuView)
        delete recMenuView;
}

void cTVGuideOSD::Show(void) {
    if (!SkindesignerAvailable()) {
        esyslog("tvguideng: skindesigner not available but mandatorily needed - aborting");
        return;        
    }
    skindesignerapi::cOsdView *rootView = GetOsdView();
    if (!rootView) {
        esyslog("tvguideng: used skindesigner skin does not support tvguideng");
        return;
    }

    SwitchTimers.Load(AddDirectory(cPlugin::ConfigDirectory("epgsearch"), "epgsearchswitchtimers.conf"));
    recMenuView = new cRecMenuView();
    pRemoteTimers = cPluginManager::GetPlugin("remotetimers");
    if (pRemoteTimers) {
        isyslog("tvguideng: remotetimers-plugin is available");
    }
    if (config.useRemoteTimers && pRemoteTimers) {
        cString errorMsg;
        if (!pRemoteTimers->Service("RemoteTimers::RefreshTimers-v1.0", &errorMsg)) {
            esyslog("tvguideng: Remotetimers Error: %s", *errorMsg);
        }
    }

    timeManager = new cTimeManager();
    timeManager->Now();

    epgGrid = new cEpgGrid(rootView, timeManager);
    const cChannel *startChannel;
#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
    {
    LOCK_CHANNELS_READ;
    startChannel = Channels->GetByNumber(cDevice::CurrentChannel());
    }
#else
    startChannel = Channels.GetByNumber(cDevice::CurrentChannel());
#endif
    epgGrid->Init(startChannel);
    epgGrid->Activate();
    epgGrid->DrawHeader();
    epgGrid->DrawTime();
    epgGrid->DrawFooter();
    epgGrid->DrawChannelHeaders();
    epgGrid->DrawTimeline();
    epgGrid->DrawChannelgroups();
    epgGrid->DrawGrid();
    epgGrid->Flush();
}

eOSState cTVGuideOSD::ProcessKey(eKeys Key) {
    if (!epgGrid) {
        return osEnd;
    }

    eOSState state = osContinue;

    if (recMenuView->Active() && !detailView) {
        state = recMenuView->ProcessKey(Key);
        if (state == osEnd) {
            epgGrid->SetTimers();
            epgGrid->Activate();
            epgGrid->DrawGrid();
            epgGrid->Flush();
        } else if (state == osUser1) {
            DetailView(recMenuView->GetEvent());
        }
        state = osContinue;
        if (epgGrid->DrawTime())
            epgGrid->Flush();
    } else if (detailView) {
        //Detail View Key Handling
        switch (Key & ~k_Repeat) {
            case kBack:     
                CloseDetailedView();
                break;
            case kUp:
                detailView->Up();
                detailView->Flush();
                break;
            case kDown:
                detailView->Down();
                detailView->Flush();
                break;
            case kLeft:
                detailView->Left();
                detailView->Flush();
                break;
            case kRight:
                detailView->Right();
                detailView->Flush();
                break;
            case kOk:
                CloseDetailedView();
                break;
            case kBlue:
                state = ChannelSwitch(detailView->GetEvent());
                break;
            case kRed:
                CloseDetailedView();
                state = osContinue; 
                KeyRed();
                break;
            default:
                break;
        }
        if (detailView && state != osEnd && detailView->DrawTime()) {
            detailView->Flush();
        }
    } else {
        //EPG Grid is active
        switch (Key & ~k_Repeat) {
            case kBack:     
                state=osEnd; 
                break;
            case kUp:
                KeyUp();
                break;
            case kDown:
                KeyDown();
                break;
            case kLeft:
                KeyLeft();
                break;
            case kRight:
                KeyRight();
                break;
            case kOk:
                state = KeyOk(epgGrid->GetCurrentEvent());
                break;
            case k0 ... k9:
                NumericKey(Key - k0);
                break;
            case kRed:
                KeyRed();
                break;
            case kGreen:
                KeyGreen();
                break;
            case kYellow:
                KeyYellow();
                break;
            case kBlue:
                state = KeyBlue(epgGrid->GetCurrentEvent());
                break;
            case kNone:
                if (channelJumper) CheckTimeout();
                break;          
            default:        
                break;
        }
        if (state != osEnd && epgGrid->DrawTime())
            epgGrid->Flush();
    }
    return state;
}

void cTVGuideOSD::KeyLeft(void) {
    if (config.displayMode == eHorizontal) {
        TimeBack();
    } else if (config.displayMode == eVertical) {
        ChannelsBack();
    }
}

void cTVGuideOSD::KeyRight(void) {
    if (config.displayMode == eHorizontal) {
        TimeForward();
    } else if (config.displayMode == eVertical) {
        ChannelsForward();
    }
}

void cTVGuideOSD::KeyUp(void) {
    if (config.displayMode == eHorizontal) {
        ChannelsBack();
    } else if (config.displayMode == eVertical) {
        TimeBack();
    }
}

void cTVGuideOSD::KeyDown(void) {
    if (config.displayMode == eHorizontal) {
        ChannelsForward();
    } else if (config.displayMode == eVertical) {
        TimeForward();
    }
}

void cTVGuideOSD::TimeForward(void) {
    bool scrolled = epgGrid->TimeForward();
    if (!scrolled) {
        epgGrid->UpdateActive();
    } else {
        epgGrid->DrawGrid();
    }
    epgGrid->DrawHeader();
    epgGrid->Flush();
}

void cTVGuideOSD::TimeBack(void) {
    bool scrolled = epgGrid->TimeBack();
    if (!scrolled) {
        epgGrid->UpdateActive();
    } else {
        epgGrid->DrawGrid();
    }
    epgGrid->DrawHeader();
    epgGrid->Flush();
}

void cTVGuideOSD::ChannelsForward(void) {
    bool scrolled = epgGrid->ChannelForward();
    if (!scrolled) {
        epgGrid->UpdateActive();
    } else {
        epgGrid->DrawChannelHeaders();
        epgGrid->DrawChannelgroups();
        epgGrid->DrawGrid();
    }
    if (config.channelJumpMode == eGroupJump)
        epgGrid->DrawFooter();
    epgGrid->DrawHeader();
    epgGrid->Flush();
}

void cTVGuideOSD::ChannelsBack(void) {
    bool scrolled = epgGrid->ChannelBack();
    if (!scrolled) {
        epgGrid->UpdateActive();
    } else {
        epgGrid->DrawChannelHeaders();
        epgGrid->DrawChannelgroups();
        epgGrid->DrawGrid();
    }
    if (config.channelJumpMode == eGroupJump)
        epgGrid->DrawFooter();
    epgGrid->DrawHeader();
    epgGrid->Flush();
}

void cTVGuideOSD::NumericKey(int key) {
    if (config.numKeyMode == eTimeJump) {
        if (key == 2) {
            CreateInstantTimer();
        } else if (key == 5) {
            DisplaySearchRecordings();
        } else if (key == 8) {
            DisplaySearchEPG();
        } else {
            NumericKeyTimeJump(key);
        }
    } else if (config.numKeyMode == eChannelJump) {
        NumericKeyChannelJump(key);
    }
}

void cTVGuideOSD::NumericKeyTimeJump(int key) {
    switch (key) {
        case 1: {
            bool tooFarInPast = timeManager->DelMinutes(config.bigStepHours*60);
            if (tooFarInPast)
                return;
            }
            break;
        case 3: {
            timeManager->AddMinutes(config.bigStepHours*60);
        }
            break;
        case 4: {
            bool tooFarInPast = timeManager->DelMinutes(config.hugeStepHours*60);
            if (tooFarInPast)
                return;
            }
            break;
        case 6: {
            timeManager->AddMinutes(config.hugeStepHours*60);
            }
            break;
        case 7: {
            cTimeManager primeChecker;
            primeChecker.Now();
            time_t prevPrime = primeChecker.GetPrevPrimetime(timeManager->GetStart());
            if (primeChecker.TooFarInPast(prevPrime))
                return;
            timeManager->SetTime(prevPrime);
        }
            break;
        case 9: {
            cTimeManager primeChecker;
            time_t nextPrime = primeChecker.GetNextPrimetime(timeManager->GetStart());
            timeManager->SetTime(nextPrime);
        }
            break;
        default:
            return;
    }
    epgGrid->RebuildEpgGrid();
    epgGrid->DrawGrid();
    epgGrid->DrawHeader();
    epgGrid->DrawTimeline();
    epgGrid->Flush();
}

void cTVGuideOSD::NumericKeyChannelJump(int key) {
    if (!channelJumper) {
        channelJumper = epgGrid->GetChannelJumper();
    }
    channelJumper->Set(key);
    channelJumper->Draw();
    epgGrid->Flush();
}

void cTVGuideOSD::CheckTimeout(void) {
    if (!channelJumper)
        return;
    if (!channelJumper->TimeOut())
        return;
    int newChannelNum = channelJumper->GetChannel(); 
    delete channelJumper;
    channelJumper = NULL;
#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
    const cChannels* channels;
    {
    LOCK_CHANNELS_READ;
    channels = Channels;
    }
#else
    cChannels* channels = &Channels;
#endif
    const cChannel *newChannel = channels->GetByNumber(newChannelNum);
    if (!newChannel) {
        return;
    }
    epgGrid->Clear();
    epgGrid->Init(newChannel);
    epgGrid->DrawHeader();
    epgGrid->DrawTime();
    epgGrid->DrawFooter();
    epgGrid->DrawChannelHeaders();
    epgGrid->DrawTimeline();
    epgGrid->DrawChannelgroups();
    epgGrid->DrawGrid();
    epgGrid->Flush();
}

void cTVGuideOSD::KeyGreen(void) {
    const cChannel *prevStart = NULL;
    if (config.channelJumpMode == eNumJump) {
        prevStart = epgGrid->GetPrevChannelNumJump();
    } else if (config.channelJumpMode == eGroupJump) {
        if (epgGrid->IsFirstGroup()) {
            return;
        }
        prevStart = epgGrid->GetPrevChannelGroupJump();
    }
    epgGrid->Clear();
    epgGrid->Init(prevStart);
    epgGrid->DrawHeader();
    epgGrid->DrawTime();
    epgGrid->DrawFooter();
    epgGrid->DrawChannelHeaders();
    epgGrid->DrawChannelgroups();
    if (config.channelJumpMode == eGroupJump)
        epgGrid->DrawFooter();
    epgGrid->DrawTimeline();
    epgGrid->DrawGrid();
    epgGrid->Flush();
}

void cTVGuideOSD::KeyYellow(void) {
    const cChannel *nextStart = NULL;
    if (config.channelJumpMode == eNumJump) {
        nextStart = epgGrid->GetNextChannelNumJump();
    } else if (config.channelJumpMode == eGroupJump) {
        if (epgGrid->IsLastGroup()) {
            return;
        }
        if (config.hideLastChannelGroup && epgGrid->IsSecondLastGroup()) {
            return;
        }
        nextStart = epgGrid->GetNextChannelGroupJump();        
    }
    epgGrid->Clear();
    epgGrid->Init(nextStart);
    epgGrid->DrawHeader();
    epgGrid->DrawTime();
    epgGrid->DrawFooter();
    epgGrid->DrawChannelHeaders();
    epgGrid->DrawChannelgroups();
        if (config.channelJumpMode == eGroupJump)
            epgGrid->DrawFooter();
    epgGrid->DrawTimeline();
    epgGrid->DrawGrid();
    epgGrid->Flush();
}

eOSState cTVGuideOSD::KeyBlue(const cEvent *e) {
    if (config.blueKeyMode == eBlueKeySwitch) {
        return ChannelSwitch(e);
    } else if (config.blueKeyMode == eBlueKeyEPG) {
        DetailView(e);
    } else if (config.blueKeyMode == eBlueKeyFavorites) {
        Favorites();
    }
    return osContinue;
}

eOSState cTVGuideOSD::KeyOk(const cEvent *e) {
    if (config.blueKeyMode == eBlueKeySwitch) {
        DetailView(e);
    } else if (config.blueKeyMode == eBlueKeyEPG) {
        return ChannelSwitch(e);
    } else if (config.blueKeyMode == eBlueKeyFavorites) {
        DetailView(e);
    }
    return osContinue;
}

eOSState cTVGuideOSD::ChannelSwitch(const cEvent *e) {
    bool running = false;
    if (e) {
        time_t now = time(0);
        if (((e->StartTime() - 5*60) <= now) && (e->EndTime() >= now))
            running = true;
    }
    if (running || !config.intelligentSwitch) {
        const cChannel *currentChannel = epgGrid->GetCurrentChannel();
        if (!currentChannel) {
            return osContinue;
        }
        cDevice::PrimaryDevice()->SwitchChannel(currentChannel, true);
        if (config.closeOnSwitch) {
            return osEnd;
        }
    } else {
        CreateSwitchTimer(e);
        epgGrid->SetTimers();
        epgGrid->DrawGrid();
        epgGrid->Flush();
    }
    return osContinue;    
}

void cTVGuideOSD::CreateSwitchTimer(const cEvent *e) {
    if (!e)
        return;
    if (SwitchTimers.EventInSwitchList(e))
        return;
    cSwitchTimer st;
    cRecManager recManager;
    recManager.SetEPGSearchPlugin();
    recManager.CreateSwitchTimer(e, st);
}

void cTVGuideOSD::DetailView(const cEvent *e) {
    if (!e)
        return;
    epgGrid->Deactivate(true);
    if (recMenuView->Active())
        recMenuView->Hide(true);
    skindesignerapi::cOsdView *dV = GetOsdView((int)eViews::detailView);
    detailView = new cDetailView(dV, e);
    detailView->Activate();
    detailView->Draw();
    detailView->DrawTime();
    detailView->Flush();
}

void cTVGuideOSD::CloseDetailedView(void) {
    delete detailView;
    detailView = NULL;
    epgGrid->Activate();
    epgGrid->Flush();
    if (recMenuView->Active()) {
        recMenuView->Activate(true);
        recMenuView->Flush();        
    }
}

void cTVGuideOSD::KeyRed(void) {
    const cEvent *e = epgGrid->GetCurrentEvent();
    if (!e)
        return;
    epgGrid->Deactivate(false);
    skindesignerapi::cOsdView *recView = GetOsdView((int)eViews::recMenu);
    skindesignerapi::cOsdView *recViewBuffer = GetOsdView((int)eViews::recMenu2);
    skindesignerapi::cOsdView *recViewBuffer2 = GetOsdView((int)eViews::recMenu3);
    recMenuView->Init(recView, recViewBuffer, recViewBuffer2);
    recMenuView->Activate();
    recMenuView->DisplayRecMenu(e);
    recMenuView->Flush();
}

void cTVGuideOSD::Favorites(void) {
    epgGrid->Deactivate(false);
    skindesignerapi::cOsdView *recView = GetOsdView((int)eViews::recMenu);
    skindesignerapi::cOsdView *recViewBuffer = GetOsdView((int)eViews::recMenu2);
    skindesignerapi::cOsdView *recViewBuffer2 = GetOsdView((int)eViews::recMenu3);
    recMenuView->Init(recView, recViewBuffer, recViewBuffer2);
    recMenuView->Activate();
    recMenuView->DisplayFavorites();
    recMenuView->Flush();
}

void cTVGuideOSD::CreateInstantTimer(void) {
    const cEvent *e = epgGrid->GetCurrentEvent();
    if (!e)
        return;
    cRecManager recManager;
    recManager.SetEPGSearchPlugin();
    if (!e->HasTimer())
        recManager.createTimer(e, "");
    else
        recManager.DeleteTimer(e);
    epgGrid->SetTimers();
    epgGrid->DrawGrid();
    epgGrid->Flush();
}

void cTVGuideOSD::DisplaySearchRecordings(void) {
    const cEvent *e = epgGrid->GetCurrentEvent();
    if (!e)
        return;
    epgGrid->Deactivate(false);
    skindesignerapi::cOsdView *recView = GetOsdView((int)eViews::recMenu);
    skindesignerapi::cOsdView *recViewBuffer = GetOsdView((int)eViews::recMenu2);
    skindesignerapi::cOsdView *recViewBuffer2 = GetOsdView((int)eViews::recMenu3);
    recMenuView->Init(recView, recViewBuffer, recViewBuffer2);
    recMenuView->Activate();
    recMenuView->DisplayRecSearch(e);
    recMenuView->Flush();
}

void cTVGuideOSD::DisplaySearchEPG(void) {
    const cEvent *e = epgGrid->GetCurrentEvent();
    if (!e)
        return;
    epgGrid->Deactivate(false);
    skindesignerapi::cOsdView *recView = GetOsdView((int)eViews::recMenu);
    skindesignerapi::cOsdView *recViewBuffer = GetOsdView((int)eViews::recMenu2);
    skindesignerapi::cOsdView *recViewBuffer2 = GetOsdView((int)eViews::recMenu3);
    recMenuView->Init(recView, recViewBuffer, recViewBuffer2);
    recMenuView->Activate();
    recMenuView->DisplaySearchEPG(e);
    recMenuView->Flush();
}

void cTVGuideOSD::DefineTokens(eViewElementsRoot ve, skindesignerapi::cTokenContainer *tk) {
    switch (ve) {
        case eViewElementsRoot::backgroundHor:
        case eViewElementsRoot::backgroundVer:
            break;
        case eViewElementsRoot::headerHor:
        case eViewElementsRoot::headerVer:
            tk->DefineIntToken("{isdummy}", (int)eHeaderIT::isdummy);
            tk->DefineIntToken("{daynumeric}", (int)eHeaderIT::daynumeric);
            tk->DefineIntToken("{month}", (int)eHeaderIT::month);
            tk->DefineIntToken("{year}", (int)eHeaderIT::year);
            tk->DefineIntToken("{running}", (int)eHeaderIT::running);
            tk->DefineIntToken("{elapsed}", (int)eHeaderIT::elapsed);
            tk->DefineIntToken("{duration}", (int)eHeaderIT::duration);
            tk->DefineIntToken("{durationhours}", (int)eHeaderIT::durationhours);
            tk->DefineIntToken("{channelnumber}", (int)eHeaderIT::channelnumber);
            tk->DefineIntToken("{channellogoexists}", (int)eHeaderIT::isdummy);
            tk->DefineIntToken("{hasposter}", (int)eHeaderIT::hasposter);
            tk->DefineIntToken("{posterwidth}", (int)eHeaderIT::posterwidth);
            tk->DefineIntToken("{posterheight}", (int)eHeaderIT::posterheight);
            tk->DefineStringToken("{title}", (int)eHeaderST::title);
            tk->DefineStringToken("{shorttext}", (int)eHeaderST::shorttext);
            tk->DefineStringToken("{description}", (int)eHeaderST::description);
            tk->DefineStringToken("{start}", (int)eHeaderST::start);
            tk->DefineStringToken("{stop}", (int)eHeaderST::stop);
            tk->DefineStringToken("{day}", (int)eHeaderST::day);
            tk->DefineStringToken("{date}", (int)eHeaderST::date);
            tk->DefineStringToken("{durationminutes}", (int)eHeaderST::durationminutes);
            tk->DefineStringToken("{channelname}", (int)eHeaderST::channelname);
            tk->DefineStringToken("{channelid}", (int)eHeaderST::channelid);
            tk->DefineStringToken("{posterpath}", (int)eHeaderST::posterpath);
            break;
        case eViewElementsRoot::footerHor:
        case eViewElementsRoot::footerVer:
            tk->DefineIntToken("{red1}", (int)eFooterIT::red1);
            tk->DefineIntToken("{red2}", (int)eFooterIT::red2);
            tk->DefineIntToken("{red3}", (int)eFooterIT::red3);
            tk->DefineIntToken("{red4}", (int)eFooterIT::red4);
            tk->DefineIntToken("{green1}", (int)eFooterIT::green1);
            tk->DefineIntToken("{green2}", (int)eFooterIT::green2);
            tk->DefineIntToken("{green3}", (int)eFooterIT::green3);
            tk->DefineIntToken("{green4}", (int)eFooterIT::green4);
            tk->DefineIntToken("{yellow1}", (int)eFooterIT::yellow1);
            tk->DefineIntToken("{yellow2}", (int)eFooterIT::yellow2);
            tk->DefineIntToken("{yellow3}", (int)eFooterIT::yellow3);
            tk->DefineIntToken("{yellow4}", (int)eFooterIT::yellow4);
            tk->DefineIntToken("{blue1}", (int)eFooterIT::blue1);
            tk->DefineIntToken("{blue2}", (int)eFooterIT::blue2);
            tk->DefineIntToken("{blue3}", (int)eFooterIT::blue3);
            tk->DefineIntToken("{blue4}", (int)eFooterIT::blue4);
            tk->DefineStringToken("{red}", (int)eFooterST::red);
            tk->DefineStringToken("{green}", (int)eFooterST::green);
            tk->DefineStringToken("{yellow}", (int)eFooterST::yellow);
            tk->DefineStringToken("{blue}", (int)eFooterST::blue);
            break;
        case eViewElementsRoot::timeHor:
        case eViewElementsRoot::timeVer:
            tk->DefineIntToken("{sec}", (int)eTimeIT::sec);
            tk->DefineIntToken("{min}", (int)eTimeIT::min);
            tk->DefineIntToken("{hour}", (int)eTimeIT::hour);
            tk->DefineIntToken("{hmins}", (int)eTimeIT::hmins);
            tk->DefineIntToken("{year}", (int)eTimeIT::year);
            tk->DefineIntToken("{day}", (int)eTimeIT::day);
            tk->DefineStringToken("{time}", (int)eTimeST::time);
            tk->DefineStringToken("{monthname}", (int)eTimeST::monthname);
            tk->DefineStringToken("{monthnameshort}", (int)eTimeST::monthnameshort);
            tk->DefineStringToken("{month}", (int)eTimeST::month);
            tk->DefineStringToken("{dayleadingzero}", (int)eTimeST::dayleadingzero);
            tk->DefineStringToken("{dayname}", (int)eTimeST::dayname);
            tk->DefineStringToken("{daynameshort}", (int)eTimeST::daynameshort);
            break;
        case eViewElementsRoot::dateTimelineHor:
        case eViewElementsRoot::dateTimelineVer:
            tk->DefineStringToken("{weekday}", (int)eDateTimeST::weekday);
            tk->DefineStringToken("{date}", (int)eDateTimeST::date);
            break;
        case eViewElementsRoot::timeIndicatorHor:
        case eViewElementsRoot::timeIndicatorVer:
            tk->DefineIntToken("{percenttotal}", (int)eTimeIndicatorIT::percenttotal);
            break;
        case eViewElementsRoot::channelJump:
            tk->DefineStringToken("{channel}", (int)eChannelJumpST::channel);
            break;
        default:
            break;
    }
}

void cTVGuideOSD::DefineTokens(eViewGridsRoot vg, skindesignerapi::cTokenContainer *tk) {
    switch (vg) {
        case eViewGridsRoot::channelsHor:
        case eViewGridsRoot::channelsVer:
            tk->DefineIntToken("{number}", (int)eChannelGridIT::number);
            tk->DefineIntToken("{channellogoexists}", (int)eChannelGridIT::channellogoexists);
            tk->DefineStringToken("{name}", (int)eChannelGridST::name);
            tk->DefineStringToken("{channelid}", (int)eChannelGridST::channelid);
            break;
        case eViewGridsRoot::schedulesHor:
        case eViewGridsRoot::schedulesVer:
            tk->DefineIntToken("{color}", (int)eSchedulesGridIT::color);
            tk->DefineIntToken("{dummy}", (int)eSchedulesGridIT::dummy);
            tk->DefineIntToken("{timer}", (int)eSchedulesGridIT::timer);
            tk->DefineIntToken("{switchtimer}", (int)eSchedulesGridIT::switchtimer);
            tk->DefineStringToken("{title}", (int)eSchedulesGridST::title);
            tk->DefineStringToken("{shorttext}", (int)eSchedulesGridST::shorttext);
            tk->DefineStringToken("{start}", (int)eSchedulesGridST::start);
            tk->DefineStringToken("{stop}", (int)eSchedulesGridST::stop);
            break;
        case eViewGridsRoot::channelGroupsHor:
        case eViewGridsRoot::channelGroupsVer:
            tk->DefineIntToken("{color}", (int)eChannelgroupsGridIT::color);
            tk->DefineStringToken("{group}", (int)eChannelgroupsGridST::group);
            break;
        case eViewGridsRoot::timelineHor:
        case eViewGridsRoot::timelineVer:
            tk->DefineStringToken("{timestring}", (int)eTimelineGridST::timestring);
            tk->DefineIntToken("{fullhour}", (int)eTimelineGridIT::fullhour);
            break;
        default:
            break;
    }
}