#include <cstdio>

#include "backendsettings.h"
#include "frequencies.h"
#include "libmyth/mythcontext.h"
#include "libmyth/settings.h"
#include "channelsettings.h" // for ChannelTVFormat::GetFormats()
#include <unistd.h>


static HostLineEdit *LocalServerIP()
{
    HostLineEdit *gc = new HostLineEdit("BackendServerIP");
    gc->setLabel(QObject::tr("IP address"));
    gc->setValue("127.0.0.1");
    gc->setHelpText(QObject::tr("Enter the IP address of this machine.  "
                    "Use an externally accessible address (ie, not "
                    "127.0.0.1) if you are going to be running a frontend "
                    "on a different machine than this one."));
    return gc;
};

static HostLineEdit *LocalServerPort()
{
    HostLineEdit *gc = new HostLineEdit("BackendServerPort");
    gc->setLabel(QObject::tr("Port"));
    gc->setValue("6543");
    gc->setHelpText(QObject::tr("Unless you've got good reason to, don't "
                    "change this."));
    return gc;
};

static HostLineEdit *LocalStatusPort()
{
    HostLineEdit *gc = new HostLineEdit("BackendStatusPort");
    gc->setLabel(QObject::tr("Status Port"));
    gc->setValue("6544");
    gc->setHelpText(QObject::tr("Port which the server will listen to for "
                    "HTTP requests.  Currently, it shows a little status "
                    "information."));
    return gc;
};

static GlobalLineEdit *MasterServerIP()
{
    GlobalLineEdit *gc = new GlobalLineEdit("MasterServerIP");
    gc->setLabel(QObject::tr("IP address"));
    gc->setValue("127.0.0.1");
    gc->setHelpText(QObject::tr("The IP address of the master backend "
                    "server. All frontend and non-master backend machines "
                    "will connect to this server.  If you only have one "
                    "backend, this should be the same IP address as "
                    "above."));
    return gc;
};

static GlobalLineEdit *MasterServerPort()
{
    GlobalLineEdit *gc = new GlobalLineEdit("MasterServerPort");
    gc->setLabel(QObject::tr("Port"));
    gc->setValue("6543");
    gc->setHelpText(QObject::tr("Unless you've got good reason to, "
                    "don't change this."));
    return gc;
};

static HostLineEdit *LocalSecurityPin()
{
    HostLineEdit *gc = new HostLineEdit("SecurityPin");
    gc->setLabel(QObject::tr("Security Pin (Required)"));
    gc->setValue("");
    gc->setHelpText(QObject::tr("Pin code required for a frontend to connect "
                                "to the backend. Blank prevents all "
                                "connections, 0000 allows any client to "
                                "connect."));
    return gc;
};

static GlobalComboBox *TVFormat()
{
    GlobalComboBox *gc = new GlobalComboBox("TVFormat");
    gc->setLabel(QObject::tr("TV format"));

    QStringList list = ChannelTVFormat::GetFormats();
    for (uint i = 0; i < list.size(); i++)
        gc->addSelection(list[i]);

    gc->setHelpText(QObject::tr("The TV standard to use for viewing TV."));
    return gc;
};

static GlobalComboBox *VbiFormat()
{
    GlobalComboBox *gc = new GlobalComboBox("VbiFormat");
    gc->setLabel(QObject::tr("VBI format"));
    gc->addSelection("None");
    gc->addSelection("PAL Teletext");
    gc->addSelection("NTSC Closed Caption");
    gc->setHelpText(QObject::tr("VBI stands for Vertical Blanking Interrupt.  "
                    "VBI is used to carry Teletext and Closed Captioning "
                    "data."));
    return gc;
};

static GlobalComboBox *FreqTable()
{
    GlobalComboBox *gc = new GlobalComboBox("FreqTable");
    gc->setLabel(QObject::tr("Channel frequency table"));

    for (uint i = 0; chanlists[i].name; i++)
        gc->addSelection(chanlists[i].name);

    gc->setHelpText(QObject::tr("Select the appropriate frequency table for "
                    "your system.  If you have an antenna, use a \"-bcast\" "
                    "frequency."));
    return gc;
};

static GlobalCheckBox *SaveTranscoding()
{
    GlobalCheckBox *gc = new GlobalCheckBox("SaveTranscoding");
    gc->setLabel(QObject::tr("Save original files after transcoding (globally)"));
    gc->setValue(false);
    gc->setHelpText(QObject::tr("When set and the transcoder is active, the "
                    "original files will be renamed to .old once the "
                    "transcoding is complete."));
    return gc;
};

static HostCheckBox *TruncateDeletes()
{
    HostCheckBox *hc = new HostCheckBox("TruncateDeletesSlowly");
    hc->setLabel(QObject::tr("Delete files slowly"));
    hc->setValue(false);
    hc->setHelpText(QObject::tr("Some filesystems use a lot of resources when "
                    "deleting large recording files.  This option makes Myth "
                    "delete the file slowly on this backend to lessen the "
                    "impact."));
    return hc;
};

static GlobalCheckBox *DeletesFollowLinks()
{
    GlobalCheckBox *gc = new GlobalCheckBox("DeletesFollowLinks");
    gc->setLabel(QObject::tr("Follow symbolic links when deleting files"));
    gc->setValue(false);
    gc->setHelpText(QObject::tr("This will cause Myth to follow symlinks "
                    "when recordings and related files are deleted, instead "
                    "of deleting the symlink and leaving the actual file."));
    return gc;
};

static GlobalSpinBox *HDRingbufferSize()
{
    GlobalSpinBox *bs = new GlobalSpinBox(
        "HDRingbufferSize", 25*188, 512*188, 25*188);
    bs->setLabel(QObject::tr("HD Ringbuffer size (KB)"));
    bs->setHelpText(QObject::tr("The HD device ringbuffer allows the "
                    "backend to weather moments of stress. "
                    "The larger the ringbuffer, the longer "
                    "the moments of stress can be. However, "
                    "setting the size too large can cause "
                    "swapping, which is detrimental."));
    bs->setValue(50*188);
    return bs;
}

static HostCheckBox *DisableFirewireReset()
{
    HostCheckBox *hc = new HostCheckBox("DisableFirewireReset");
    hc->setLabel(QObject::tr("Disable Firewire Reset"));
    hc->setHelpText(
        QObject::tr(
            "By default MythTV will reset the firewire bus when a "
            "firewire recorder stops responding to commands. But "
            "if this causes problems you can disable this here for "
            "Linux firewire recorders."));
    hc->setValue(false);
    return hc;
}

static HostLineEdit *MiscStatusScript()
{
    HostLineEdit *he = new HostLineEdit("MiscStatusScript");
    he->setLabel(QObject::tr("Miscellaneous Status Application"));
    he->setValue("");
    he->setHelpText(QObject::tr("External application or script that outputs "
                                "extra information for inclusion in the "
                                "backend status page.  See "
                                "contrib/misc_status_info/README"));
    return he;
}

static void init_time_offsets(GlobalComboBox *gc)
{
    gc->addSelection("None");
    gc->addSelection("Auto");
    gc->addSelection("+0030");
    gc->addSelection("+0100");
    gc->addSelection("+0130");
    gc->addSelection("+0200");
    gc->addSelection("+0230");
    gc->addSelection("+0300");
    gc->addSelection("+0330");
    gc->addSelection("+0400");
    gc->addSelection("+0430");
    gc->addSelection("+0500");
    gc->addSelection("+0530");
    gc->addSelection("+0600");
    gc->addSelection("+0630");
    gc->addSelection("+0700");
    gc->addSelection("+0730");
    gc->addSelection("+0800");
    gc->addSelection("+0830");
    gc->addSelection("+0900");
    gc->addSelection("+0930");
    gc->addSelection("+1000");
    gc->addSelection("+1030");
    gc->addSelection("+1100");
    gc->addSelection("+1130");
    gc->addSelection("+1200");
    gc->addSelection("-1100");
    gc->addSelection("-1030");
    gc->addSelection("-1000");
    gc->addSelection("-0930");
    gc->addSelection("-0900");
    gc->addSelection("-0830");
    gc->addSelection("-0800");
    gc->addSelection("-0730");
    gc->addSelection("-0700");
    gc->addSelection("-0630");
    gc->addSelection("-0600");
    gc->addSelection("-0530");
    gc->addSelection("-0500");
    gc->addSelection("-0430");
    gc->addSelection("-0400");
    gc->addSelection("-0330");
    gc->addSelection("-0300");
    gc->addSelection("-0230");
    gc->addSelection("-0200");
    gc->addSelection("-0130");
    gc->addSelection("-0100");
    gc->addSelection("-0030");
}

static GlobalComboBox *TimeOffset()
{
    GlobalComboBox *gc = new GlobalComboBox("TimeOffset");
    gc->setLabel(QObject::tr("Your Local Timezone (for XMLTV)"));
    init_time_offsets(gc);
    QString helptext = QObject::tr(
        "Used if the XMLTV data comes from a different timezone than your "
        "own. This adjust the times in the XMLTV EPG data to compensate. "
        "'Auto' converts the XMLTV time to local time using your "
        "computer's timezone.  "
        "'None' ignores the XMLTV timezone, interpreting times as local.");
    gc->setHelpText(helptext);
    return gc;
};

#if 0
static GlobalComboBox *EITTimeOffset()
{
    GlobalComboBox *gc = new GlobalComboBox("EITTimeOffset");
    gc->setLabel(QObject::tr("Time offset for EIT listings"));
    init_time_offsets(gc);
    gc->setValue(1);
    QString helptext = QObject::tr(
        "Adjust the relative timezone of the EIT EPG data.  "
        "'Auto' converts the EIT time to local time using your "
        "computer's timezone.  "
        "'None' ignores the EIT timezone, interpreting times as local.");
    gc->setHelpText(helptext);
    return gc;
};
#endif

static GlobalSpinBox *EITTransportTimeout()
{
    GlobalSpinBox *gc = new GlobalSpinBox("EITTransportTimeout", 1, 15, 1);
    gc->setLabel(QObject::tr("EIT Transport Timeout (mins)"));
    gc->setValue(5);
    QString helpText = QObject::tr(
        "Maximum time to spend waiting for listings data on one DTV channel "
        "before checking for new listings data on the next channel.");
    gc->setHelpText(helpText);
    return gc;
}

static GlobalCheckBox *MasterBackendOverride()
{
    GlobalCheckBox *gc = new GlobalCheckBox("MasterBackendOverride");
    gc->setLabel(QObject::tr("Master Backend Override"));
    gc->setValue(true);
    gc->setHelpText(QObject::tr("If enabled, the master backend will stream and"
                    " delete files if it finds them in the video directory. "
                    "Useful if you are using a central storage location, like "
                    "a NFS share, and your slave backend isn't running."));
    return gc;
};

static GlobalCheckBox *EITIgnoresSource()
{
    GlobalCheckBox *gc = new GlobalCheckBox("EITIgnoresSource");
    gc->setLabel(QObject::tr("Cross Source EIT"));
    gc->setValue(false);
    QString help = QObject::tr(
        "If enabled, listings data collected on one Video Source will be "
        "applied to the first matching DVB channel on any Video Source. "
        "This is sometimes useful for DVB-S, but may insert bogus "
        "data into any ATSC listings stored in the same database.");
    gc->setHelpText(help);
    return gc;
};

static GlobalSpinBox *EITCrawIdleStart()
{
    GlobalSpinBox *gc = new GlobalSpinBox("EITCrawIdleStart", 30, 7200, 30);
    gc->setLabel(QObject::tr("Backend Idle Before EIT Crawl (seconds)"));
    gc->setValue(60);
    QString help = QObject::tr(
        "The minimum number of seconds after a recorder becomes idle "
        "to wait before MythTV begins collecting EIT listings data.");
    gc->setHelpText(help);
    return gc;
}

static GlobalSpinBox *WOLbackendReconnectWaitTime()
{
    GlobalSpinBox *gc = new GlobalSpinBox("WOLbackendReconnectWaitTime", 0, 1200, 5);
    gc->setLabel(QObject::tr("Delay between wake attempts (secs)"));
    gc->setValue(0);
    gc->setHelpText(QObject::tr("Length of time the frontend waits between "
                    "tries to wake up the master backend. This should be the "
                    "time your masterbackend needs to startup. Set 0 to "
                    "disable."));
    return gc;
};

static GlobalSpinBox *WOLbackendConnectRetry()
{
    GlobalSpinBox *gc = new GlobalSpinBox("WOLbackendConnectRetry", 1, 60, 1);
    gc->setLabel(QObject::tr("Wake Attempts"));
    gc->setHelpText(QObject::tr("Number of times the frontend will try to wake "
                    "up the master backend."));
    gc->setValue(5);
    return gc;
};

static GlobalLineEdit *WOLbackendCommand()
{
    GlobalLineEdit *gc = new GlobalLineEdit("WOLbackendCommand");
    gc->setLabel(QObject::tr("Wake Command"));
    gc->setValue("");
    gc->setHelpText(QObject::tr("The command used to wake up your master "
                    "backend server\n(eg. sudo /etc/init.d/mythtv-backend restart)."));
    return gc;
};

static GlobalLineEdit *WOLslaveBackendsCommand()
{
    GlobalLineEdit *gc = new GlobalLineEdit("WOLslaveBackendsCommand");
    gc->setLabel(QObject::tr("Wake command"));
    gc->setValue("");
    gc->setHelpText(QObject::tr("The command used to wakeup your slave "
                    "backends. Leave empty to disable."));
    return gc;
};

static GlobalSpinBox *idleTimeoutSecs()
{
    GlobalSpinBox *gc = new GlobalSpinBox("idleTimeoutSecs", 0, 1200, 5);
    gc->setLabel(QObject::tr("Idle shutdown timeout (secs)"));
    gc->setValue(0);
    gc->setHelpText(QObject::tr("The amount of time the master backend idles "
                    "before it shuts down all backends. Set to 0 to disable "
                    "auto shutdown."));
    return gc;
};
    
static GlobalSpinBox *idleWaitForRecordingTime()
{
    GlobalSpinBox *gc = new GlobalSpinBox("idleWaitForRecordingTime", 0, 120, 1);
    gc->setLabel(QObject::tr("Max. wait for recording (min)"));
    gc->setValue(15);
    gc->setHelpText(QObject::tr("The amount of time the master backend waits "
                    "for a recording.  If it's idle but a recording starts "
                    "within this time period, the backends won't shut down."));
    return gc;
};

static GlobalSpinBox *StartupSecsBeforeRecording()
{
    GlobalSpinBox *gc = new GlobalSpinBox("StartupSecsBeforeRecording", 0, 1200, 5);
    gc->setLabel(QObject::tr("Startup before rec. (secs)"));
    gc->setValue(120);
    gc->setHelpText(QObject::tr("The amount of time the master backend will be "
                    "woken up before a recording starts."));
    return gc;
};

static GlobalLineEdit *WakeupTimeFormat()
{
    GlobalLineEdit *gc = new GlobalLineEdit("WakeupTimeFormat");
    gc->setLabel(QObject::tr("Wakeup time format"));
    gc->setValue("hh:mm yyyy-MM-dd");
    gc->setHelpText(QObject::tr("The format of the time string passed to the "
                    "\'setWakeuptime Command\' as $time. See "
                    "QT::QDateTime.toString() for details. Set to 'time_t' for "
                    "seconds since epoch."));
    return gc;
};

static GlobalLineEdit *SetWakeuptimeCommand()
{
    GlobalLineEdit *gc = new GlobalLineEdit("SetWakeuptimeCommand");
    gc->setLabel(QObject::tr("Command to set Wakeup Time"));
    gc->setValue("");
    gc->setHelpText(QObject::tr("The command used to set the wakeup time (passed as "
                    "$time) for the Master Backend"));
    return gc;
};

static GlobalLineEdit *ServerHaltCommand()
{
    GlobalLineEdit *gc = new GlobalLineEdit("ServerHaltCommand");
    gc->setLabel(QObject::tr("Server halt command"));
    gc->setValue("sudo /sbin/halt -p");
    gc->setHelpText(QObject::tr("The command used to halt the backends."));
    return gc;
};

static GlobalLineEdit *preSDWUCheckCommand()
{
    GlobalLineEdit *gc = new GlobalLineEdit("preSDWUCheckCommand");
    gc->setLabel(QObject::tr("Pre Shutdown check-command"));
    gc->setValue("");
    gc->setHelpText(QObject::tr("A command executed before the backend would "
                    "shutdown. The return value determines if "
                    "the backend can shutdown. 0 - yes, "
                    "1 - restart idleing, "
                    "2 - reset the backend to wait for a frontend."));
    return gc;
};

static GlobalCheckBox *blockSDWUwithoutClient()
{
    GlobalCheckBox *gc = new GlobalCheckBox("blockSDWUwithoutClient");
    gc->setLabel(QObject::tr("Block shutdown before client connected"));
    gc->setValue(true);
    gc->setHelpText(QObject::tr("If set, the automatic shutdown routine will "
                    "be disabled until a client connects."));
    return gc;
};

static GlobalLineEdit *startupCommand()
{
    GlobalLineEdit *gc = new GlobalLineEdit("startupCommand");
    gc->setLabel(QObject::tr("Startup command"));
    gc->setValue("");
    gc->setHelpText(QObject::tr("This command is executed right after starting "
                    "the BE. As a parameter \'$status\' is replaced by either "
                    "\'auto\' if the machine was started automatically or "
                    "\'user\' if a user switched it on."));
    return gc;
};

static HostSpinBox *JobQueueMaxSimultaneousJobs()
{
    HostSpinBox *gc = new HostSpinBox("JobQueueMaxSimultaneousJobs", 1, 10, 1);
    gc->setLabel(QObject::tr("Maximum simultaneous jobs on this backend"));
    gc->setHelpText(QObject::tr("The Job Queue will be limited to running "
                    "this many simultaneous jobs on this backend."));
    gc->setValue(1);
    return gc;
};

static HostSpinBox *JobQueueCheckFrequency()
{
    HostSpinBox *gc = new HostSpinBox("JobQueueCheckFrequency", 5, 300, 5);
    gc->setLabel(QObject::tr("Job Queue Check frequency (in seconds)"));
    gc->setHelpText(QObject::tr("When looking for new jobs to process, the "
                    "Job Queue will wait this long between checks."));
    gc->setValue(60);
    return gc;
};

static HostComboBox *JobQueueCPU()
{
    HostComboBox *gc = new HostComboBox("JobQueueCPU");
    gc->setLabel(QObject::tr("CPU Usage"));
    gc->addSelection(QObject::tr("Low"), "0");
    gc->addSelection(QObject::tr("Medium"), "1");
    gc->addSelection(QObject::tr("High"), "2");
    gc->setHelpText(QObject::tr("This setting controls approximately how "
                    "much CPU jobs in the queue may consume. "
                    "On 'High', all available CPU time may be used "
                    "which could cause problems on slower systems." ));
    return gc;
};

static HostTimeBox *JobQueueWindowStart()
{
    HostTimeBox *gc = new HostTimeBox("JobQueueWindowStart", "00:00");
    gc->setLabel(QObject::tr("Job Queue Start Time"));
    gc->setHelpText(QObject::tr("This setting controls the start of the "
                    "Job Queue time window which determines when new jobs will "
                    "be started."));
    return gc;
};

static HostTimeBox *JobQueueWindowEnd()
{
    HostTimeBox *gc = new HostTimeBox("JobQueueWindowEnd", "23:59");
    gc->setLabel(QObject::tr("Job Queue End Time"));
    gc->setHelpText(QObject::tr("This setting controls the end of the "
                    "Job Queue time window which determines when new jobs will "
                    "be started."));
    return gc;
};

static GlobalCheckBox *JobsRunOnRecordHost()
{
    GlobalCheckBox *gc = new GlobalCheckBox("JobsRunOnRecordHost");
    gc->setLabel(QObject::tr("Run Jobs only on original recording backend"));
    gc->setValue(false);
    gc->setHelpText(QObject::tr("If set, jobs in the queue will be required "
                                "to run on the backend that made the "
                                "original recording."));
    return gc;
};

static GlobalCheckBox *AutoTranscodeBeforeAutoCommflag()
{
    GlobalCheckBox *gc = new GlobalCheckBox("AutoTranscodeBeforeAutoCommflag");
    gc->setLabel(QObject::tr("Run Transcode Jobs before Auto-Commercial Flagging"));
    gc->setValue(false);
    gc->setHelpText(QObject::tr("If set, if both auto-transcode and "
                                "auto commercial flagging are turned ON for a "
                                "recording, transcoding will run first, "
                                "otherwise, commercial flagging runs first."));
    return gc;
};

static GlobalCheckBox *AutoCommflagWhileRecording()
{
    GlobalCheckBox *gc = new GlobalCheckBox("AutoCommflagWhileRecording");
    gc->setLabel(QObject::tr("Start Auto-Commercial Flagging jobs when the "
                             "recording starts"));
    gc->setValue(false);
    gc->setHelpText(QObject::tr("If set and Auto Commercial Flagging is ON for "
                                "a recording, the flagging job will be started "
                                "as soon as the recording starts.  NOT "
                                "recommended on underpowered systems."));
    return gc;
};

static GlobalLineEdit *UserJob(uint job_num)
{
    GlobalLineEdit *gc = new GlobalLineEdit(QString("UserJob%1").arg(job_num));
    gc->setLabel(QObject::tr("User Job #%1 Command").arg(job_num));
    gc->setValue("");
    gc->setHelpText(QObject::tr("The command to run whenever this User Job "
                    "number is scheduled."));
    return gc;
};

static GlobalLineEdit *UserJobDesc(uint job_num)
{
    GlobalLineEdit *gc = new GlobalLineEdit(QString("UserJobDesc%1")
                                            .arg(job_num));
    gc->setLabel(QObject::tr("User Job #%1 Description").arg(job_num));
    gc->setValue(QObject::tr("User Job #%1").arg(job_num));
    gc->setHelpText(QObject::tr("The Description for this User Job."));  
    return gc;
};

static HostCheckBox *JobAllowCommFlag()
{
    HostCheckBox *gc = new HostCheckBox("JobAllowCommFlag");
    gc->setLabel(QObject::tr("Allow Commercial Detection jobs"));
    gc->setValue(true);
    gc->setHelpText(QObject::tr("Allow jobs of this type to run on this "
                                "backend."));
    return gc;
};

static HostCheckBox *JobAllowTranscode()
{
    HostCheckBox *gc = new HostCheckBox("JobAllowTranscode");
    gc->setLabel(QObject::tr("Allow Transcoding jobs"));
    gc->setValue(true);
    gc->setHelpText(QObject::tr("Allow jobs of this type to run on this "
                                "backend."));
    return gc;
};

static GlobalLineEdit *JobQueueTranscodeCommand()
{
    GlobalLineEdit *gc = new GlobalLineEdit("JobQueueTranscodeCommand");
    gc->setLabel(QObject::tr("Transcoder command"));
    gc->setValue("mythtranscode");
    gc->setHelpText(QObject::tr("The program used to transcode recordings. "
                    "The default is 'mythtranscode' if this setting is empty."));
    return gc;
};

static GlobalLineEdit *JobQueueCommFlagCommand()
{
    GlobalLineEdit *gc = new GlobalLineEdit("JobQueueCommFlagCommand");
    gc->setLabel(QObject::tr("Commercial Flagger command"));
    gc->setValue("mythcommflag");
    gc->setHelpText(QObject::tr("The program used to detect commercials in a "
                    "recording.  The default is 'mythcommflag' "
                    "if this setting is empty."));
    return gc;
};

static HostCheckBox *JobAllowUserJob(uint job_num)
{
    QString dbStr = QString("JobAllowUserJob%1").arg(job_num);
    QString desc  = gContext->GetSetting(QString("UserJobDesc%1").arg(job_num));
    QString label = QObject::tr("Allow %1 jobs").arg(desc);

    HostCheckBox *bc = new HostCheckBox(dbStr);
    bc->setLabel(label);
    bc->setValue(false);
    // FIXME:
    // It would be nice to disable inactive jobs,
    // but enabling them currently requires a restart of mythtv-setup
    // after entering the job command string. Will improve this logic later:
    // if (QString(gContext->GetSetting(QString("UserJob%1").arg(job_num)))
    //            .length() == 0)
    //     bc->setEnabled(false);
    bc->setHelpText(QObject::tr("Allow jobs of this type to run on this "
                    "backend."));
    return bc;
}


BackendSettings::BackendSettings() {
    VerticalConfigurationGroup* server = new VerticalConfigurationGroup(false);
    server->setLabel(QObject::tr("Host Address Backend Setup"));
    VerticalConfigurationGroup* localServer = new VerticalConfigurationGroup();
    localServer->setLabel(QObject::tr("Local Backend" + QString(" (") + gContext->GetHostName() + QString(")")));
    HorizontalConfigurationGroup* localIP =
              new HorizontalConfigurationGroup(false, false, true, true);
    localIP->addChild(LocalServerIP());
    localServer->addChild(localIP);
    HorizontalConfigurationGroup* localPorts =
              new HorizontalConfigurationGroup(false, false, true, true);
    localPorts->addChild(LocalServerPort());
    localPorts->addChild(LocalStatusPort());
    localServer->addChild(localPorts);
    HorizontalConfigurationGroup* localPin =
              new HorizontalConfigurationGroup(false, false, true, true);
    localPin->addChild(LocalSecurityPin());
    localServer->addChild(localPin);
    VerticalConfigurationGroup* masterServer = new VerticalConfigurationGroup();
    masterServer->setLabel(QObject::tr("Master Backend"));
    masterServer->addChild(MasterServerIP());
    masterServer->addChild(MasterServerPort());
    server->addChild(localServer);
    server->addChild(masterServer);
    addChild(server);

    VerticalConfigurationGroup* locale = new VerticalConfigurationGroup(false);
    locale->setLabel(QObject::tr("Locale Settings"));
    locale->addChild(TVFormat());
    locale->addChild(VbiFormat());
    locale->addChild(FreqTable());
    locale->addChild(TimeOffset());
    addChild(locale);
    
    VerticalConfigurationGroup* group2 = new VerticalConfigurationGroup(false);
    group2->setLabel(QObject::tr("Miscellaneous Settings"));
    VerticalConfigurationGroup* fm = new VerticalConfigurationGroup();
    fm->setLabel(QObject::tr("File Management Settings"));
    fm->addChild(MasterBackendOverride());
    HorizontalConfigurationGroup *fmh1 =
        new HorizontalConfigurationGroup(false, false, true, true);
    fmh1->addChild(DeletesFollowLinks());
    fmh1->addChild(TruncateDeletes());
    fm->addChild(fmh1);
    fm->addChild(HDRingbufferSize());
    group2->addChild(fm);
    group2->addChild(MiscStatusScript());
    group2->addChild(DisableFirewireReset());
    addChild(group2);

    VerticalConfigurationGroup* group2a1 = new VerticalConfigurationGroup(false);
    group2a1->setLabel(QObject::tr("EIT Scanner Options"));                
    //group2a1->addChild(EITTimeOffset());
    group2a1->addChild(EITTransportTimeout());
    group2a1->addChild(EITIgnoresSource());
    group2a1->addChild(EITCrawIdleStart());
    addChild(group2a1);

    VerticalConfigurationGroup* group3 = new VerticalConfigurationGroup(false);
    group3->setLabel(QObject::tr("Shutdown/Wakeup Options"));
    group3->addChild(startupCommand());
    group3->addChild(blockSDWUwithoutClient());
    group3->addChild(idleTimeoutSecs());
    group3->addChild(idleWaitForRecordingTime());
    group3->addChild(StartupSecsBeforeRecording());
    group3->addChild(WakeupTimeFormat());
    group3->addChild(SetWakeuptimeCommand());
    group3->addChild(ServerHaltCommand());
    group3->addChild(preSDWUCheckCommand());
    addChild(group3);    

    VerticalConfigurationGroup* group4 = new VerticalConfigurationGroup(false);
    group4->setLabel(QObject::tr("Backend Wakeup settings"));

    VerticalConfigurationGroup* backend = new VerticalConfigurationGroup();
    backend->setLabel(QObject::tr("Master Backend"));
    backend->addChild(WOLbackendReconnectWaitTime());
    backend->addChild(WOLbackendConnectRetry());
    backend->addChild(WOLbackendCommand());
    group4->addChild(backend);
    
    VerticalConfigurationGroup* slaveBackend = new VerticalConfigurationGroup();
    slaveBackend->setLabel(QObject::tr("Slave Backends"));
    slaveBackend->addChild(WOLslaveBackendsCommand());
    group4->addChild(slaveBackend);
    addChild(group4);

    VerticalConfigurationGroup* group5 = new VerticalConfigurationGroup(false);
    group5->setLabel(QObject::tr("Job Queue (Backend-Specific)"));
    group5->addChild(JobQueueMaxSimultaneousJobs());
    group5->addChild(JobQueueCheckFrequency());

    HorizontalConfigurationGroup* group5a =
              new HorizontalConfigurationGroup(false, false);
    VerticalConfigurationGroup* group5a1 =
              new VerticalConfigurationGroup(false, false);
    group5a1->addChild(JobQueueWindowStart());
    group5a1->addChild(JobQueueWindowEnd());
    group5a1->addChild(JobQueueCPU());
    group5a1->addChild(JobAllowCommFlag());
    group5a1->addChild(JobAllowTranscode());
    group5a->addChild(group5a1);

    VerticalConfigurationGroup* group5a2 =
            new VerticalConfigurationGroup(false, false);
    group5a2->addChild(JobAllowUserJob(1));
    group5a2->addChild(JobAllowUserJob(2));
    group5a2->addChild(JobAllowUserJob(3));
    group5a2->addChild(JobAllowUserJob(4));
    group5a->addChild(group5a2);
    group5->addChild(group5a);
    addChild(group5);    

    VerticalConfigurationGroup* group6 = new VerticalConfigurationGroup(false);
    group6->setLabel(QObject::tr("Job Queue (Global)"));
    group6->addChild(JobsRunOnRecordHost());
    group6->addChild(AutoCommflagWhileRecording());
    group6->addChild(JobQueueCommFlagCommand());
    group6->addChild(JobQueueTranscodeCommand());
    group6->addChild(AutoTranscodeBeforeAutoCommflag());
    group6->addChild(SaveTranscoding());
    addChild(group6);    

    VerticalConfigurationGroup* group7 = new VerticalConfigurationGroup(false);
    group7->setLabel(QObject::tr("Job Queue (Job Commands)"));
    group7->addChild(UserJobDesc(1));
    group7->addChild(UserJob(1));
    group7->addChild(UserJobDesc(2));
    group7->addChild(UserJob(2));
    group7->addChild(UserJobDesc(3));
    group7->addChild(UserJob(3));
    group7->addChild(UserJobDesc(4));
    group7->addChild(UserJob(4));
    addChild(group7);    
}
