#include <cstdio>

#include "backendsettings.h"
#include "frequencies.h"
#include "mythcontext.h"
#include "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 (int 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 GlobalComboBox *StorageScheduler()
{
    GlobalComboBox *gc = new GlobalComboBox("StorageScheduler");
    gc->setLabel(QObject::tr("Storage Group Disk Scheduler"));
    gc->addSelection(QObject::tr("Balanced Free Space"), "BalancedFreeSpace");
    gc->addSelection(QObject::tr("Balanced Disk I/O"), "BalancedDiskIO");
    gc->addSelection(QObject::tr("Combination"), "Combination");
    gc->setValue("BalancedFreeSpace");
    gc->setHelpText(QObject::tr("This setting controls how the Storage Group "
                    "scheduling code will balance new recordings across "
                    "directories.  'Balanced Free Space' is the recommended "
					"method for most users." ));
    return gc;
};

static GlobalCheckBox *DisableAutomaticBackup()
{
    GlobalCheckBox *gc = new GlobalCheckBox("DisableAutomaticBackup");
    gc->setLabel(QObject::tr("Disable Automatic Database Backup"));
    gc->setValue(false);
    gc->setHelpText(QObject::tr("This will prevent Myth from backing up the "
                                "database before upgrades.  If disabled, "
                                "you should have your own backup strategy "
                                "in place."));
    return gc;
};

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/info/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 master backend 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 HostLineEdit *SleepCommand()
{
    HostLineEdit *gc = new HostLineEdit("SleepCommand");
    gc->setLabel(QObject::tr("Sleep Command"));
    gc->setValue("");
    gc->setHelpText(QObject::tr("The command used to put this slave to sleep. "
                    "If set, the master backend will use this command to put "
                    "this slave to sleep when it is not needed for recording."));
    return gc;
};

static HostLineEdit *WakeUpCommand()
{
    HostLineEdit *gc = new HostLineEdit("WakeUpCommand");
    gc->setLabel(QObject::tr("Wake Command"));
    gc->setValue("");
    gc->setHelpText(QObject::tr("The command used to wake up this slave "
                    "from sleep.  This setting is not used on the master "
                    "backend."));
    return gc;
};

static GlobalLineEdit *BackendStopCommand()
{
    GlobalLineEdit *gc = new GlobalLineEdit("BackendStopCommand");
    gc->setLabel(QObject::tr("Backend Stop Command"));
    gc->setValue("killall mythbackend");
    gc->setHelpText(QObject::tr("The command used to stop the backend"
                    " when running on the master backend server\n"
                    "(e.g. sudo /etc/init.d/mythtv-backend stop)"));
    return gc;
};

static GlobalLineEdit *BackendStartCommand()
{
    GlobalLineEdit *gc = new GlobalLineEdit("BackendStartCommand");
    gc->setLabel(QObject::tr("Backend Start Command"));
    gc->setValue("mythbackend");
    gc->setHelpText(QObject::tr("The command used to start the backend"
                    " when running on the master backend server\n"
                    "(e.g. sudo /etc/init.d/mythtv-backend start)."));
    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 idling, "
                    "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;
}

#if 0
static GlobalCheckBox *UPNPShowRecordingUnderVideos()
{
    GlobalCheckBox *gc = new GlobalCheckBox("UPnP/RecordingsUnderVideos");
    gc->setLabel(QObject::tr("Include Recordings in Video List"));
    gc->setValue(false);
    gc->setHelpText(QObject::tr("If enabled, the master backend will include the "
                    " list of recorded shows in the list of videos "
                    " This is mainly to accommodate UPnP players which do not"
                    " allow more than 1 video section." ));
    return gc;
};
#endif

static HostSpinBox *UPNPRebuildDelay()
{
    HostSpinBox *gc = new HostSpinBox("UPnP/RebuildDelay", 0, 1440, 1);
    gc->setLabel(QObject::tr("Upnp Media Update Time"));
    gc->setHelpText(QObject::tr("The number of minutes between mythbackend checking "
			   " for new videos to serve via upnp. 0 = Off. "));
    gc->setValue(30);
    return gc;
};

static GlobalComboBox *UPNPWmpSource()
{
    GlobalComboBox *gc = new GlobalComboBox("UPnP/WMPSource");
    gc->setLabel(QObject::tr("Video content to show a WMP Client"));
    gc->addSelection(QObject::tr("Recordings"),"0");
    gc->addSelection(QObject::tr("Videos"),"1");
    gc->setValue("0");
    gc->setHelpText(QObject::tr("This forces us to show WMP clients "
                    " either the Recordings tree or the Video tree when "
                    " they request a list of videos "));
    return gc;
};


static GlobalCheckBox *LogEnabled()
{
    GlobalCheckBox *bc = new GlobalCheckBox("LogEnabled");
    bc->setLabel(QObject::tr("Log MythTV events to database"));
    bc->setValue(false);
    bc->setHelpText(QObject::tr("If enabled, MythTV modules will send event "
                    "details to the database, where they can be viewed with "
                    "MythLog or periodically emailed to the administrator."));
    return bc;
}

static HostSpinBox *LogMaxCount()
{
    HostSpinBox *gs = new HostSpinBox("LogMaxCount", 0, 500, 10);
    gs->setLabel(QObject::tr("Maximum Number of Entries per Module"));
    gs->setValue(100);
    gs->setHelpText(QObject::tr("If there are more than this number of entries "
                    "for a module, the oldest log entries will be deleted to "
                    "reduce the count to this number.  Set to 0 to disable."));
    return gs;
}

static HostCheckBox *LogCleanEnabled()
{
    HostCheckBox *gc = new HostCheckBox("LogCleanEnabled");
    gc->setLabel(QObject::tr("Automatic Log Cleaning Enabled"));
    gc->setValue(false);
    gc->setHelpText(QObject::tr("This enables the periodic cleanup of the "
                    "events stored in the Myth database (see \"Log MythTV "
                    "events to database\")."));
    return gc;
}

static HostSpinBox *LogCleanPeriod()
{
    HostSpinBox *gs = new HostSpinBox("LogCleanPeriod", 0, 60, 1);
    gs->setLabel(QObject::tr("Log Cleanup Frequency (Days)"));
    gs->setValue(14);
    gs->setHelpText(QObject::tr("The number of days between log cleanup runs."));
    return gs;
}

static HostSpinBox *LogCleanDays()
{
    HostSpinBox *gs = new HostSpinBox("LogCleanDays", 0, 60, 1);
    gs->setLabel(QObject::tr("Number of days to keep acknowledged log "
                 "entries"));
    gs->setValue(14);
    gs->setHelpText(QObject::tr("The number of days before a log entry that "
                    "has been acknowledged will be deleted by the log cleanup "
                    "process."));
    return gs;
}

static HostSpinBox *LogCleanMax()
{
    HostSpinBox *gs = new HostSpinBox("LogCleanMax", 0, 60, 1);
    gs->setLabel(QObject::tr("Number of days to keep unacknowledged log "
                 "entries"));
    gs->setValue(30);
    gs->setHelpText(QObject::tr("The number of days before a log entry that "
                    "has NOT been acknowledged will be deleted by the log "
                    "cleanup process."));
    return gs;
}

static HostComboBox *LogPrintLevel()
{
    HostComboBox *gc = new HostComboBox("LogPrintLevel");
    gc->setLabel(QObject::tr("Log Print Threshold"));
    gc->addSelection(QObject::tr("All Messages"), "8");
    gc->addSelection(QObject::tr("Debug and Higher"), "7");
    gc->addSelection(QObject::tr("Info and Higher"), "6");
    gc->addSelection(QObject::tr("Notice and Higher"), "5");
    gc->addSelection(QObject::tr("Warning and Higher"), "4");
    gc->addSelection(QObject::tr("Error and Higher"), "3");
    gc->addSelection(QObject::tr("Critical and Higher"), "2");
    gc->addSelection(QObject::tr("Alert and Higher"), "1");
    gc->addSelection(QObject::tr("Emergency Only"), "0");
    gc->addSelection(QObject::tr("Disable Printed Output"), "-1");
    gc->setHelpText(QObject::tr("This controls what messages will be printed "
                    "out as well as being logged to the database."));
    return gc;
}

static GlobalCheckBox *MythFillEnabled()
{
    GlobalCheckBox *bc = new GlobalCheckBox("MythFillEnabled");
    bc->setLabel(QObject::tr("Automatically run mythfilldatabase"));
    bc->setValue(true);
    bc->setHelpText(QObject::tr("This enables the automatic execution of "
                    "mythfilldatabase."));
    return bc;
}

static GlobalSpinBox *MythFillPeriod()
{
    GlobalSpinBox *bs = new GlobalSpinBox("MythFillPeriod", 1, 30, 1);
    bs->setLabel(QObject::tr("mythfilldatabase Run Frequency (Days)"));
    bs->setValue(1);
    bs->setHelpText(QObject::tr("The number of days between mythfilldatabase "
                    "runs."));
    return bs;
}

static GlobalSpinBox *MythFillMinHour()
{
    GlobalSpinBox *bs = new GlobalSpinBox("MythFillMinHour", 0, 23, 1);
    bs->setLabel(QObject::tr("mythfilldatabase Execution Start"));
    bs->setValue(2);
    bs->setHelpText(QObject::tr("This setting and the following one define a "
                    "time period when the mythfilldatabase process is "
                    "allowed to run.  For example, setting Start to 11 and "
                    "End to 13 would mean that the process would only "
                    "run between 11:00 AM and 1:59 PM."));
    return bs;
}

static GlobalSpinBox *MythFillMaxHour()
{
    GlobalSpinBox *bs = new GlobalSpinBox("MythFillMaxHour", 0, 23, 1);
    bs->setLabel(QObject::tr("mythfilldatabase Execution End"));
    bs->setValue(5);
    bs->setHelpText(QObject::tr("This setting and the preceding one define a "
                    "time period when the mythfilldatabase process is "
                    "allowed to run.  For example, setting Start to 11 and "
                    "End to 13 would mean that the process would only "
                    "run between 11:00 AM and 1:59 PM."));
    return bs;
}

static GlobalCheckBox *MythFillGrabberSuggestsTime()
{
    GlobalCheckBox *bc = new GlobalCheckBox("MythFillGrabberSuggestsTime");
    bc->setLabel(QObject::tr("Run mythfilldatabase at time suggested by the "
                             "grabber."));
    bc->setValue(true);
    bc->setHelpText(QObject::tr("This setting allows a DataDirect guide data "
                    "provider to specify the next download time in order to "
                    "distribute load on their servers. If this setting is "
                    "enabled, mythfilldatabase Execution Start/End times are "
                    "ignored."));
    return bc;
}

static GlobalLineEdit *MythFillDatabasePath()
{
    GlobalLineEdit *be = new GlobalLineEdit("MythFillDatabasePath");
    be->setLabel(QObject::tr("mythfilldatabase Program"));
    be->setValue("mythfilldatabase");
    be->setHelpText(QObject::tr(
                        "Use 'mythfilldatabase' or the name of a custom "
                        "script that will populate the program guide info "
                        "for all your video sources."));
    return be;
}

static GlobalLineEdit *MythFillDatabaseArgs()
{
    GlobalLineEdit *be = new GlobalLineEdit("MythFillDatabaseArgs");
    be->setLabel(QObject::tr("mythfilldatabase Arguments"));
    be->setValue("");
    be->setHelpText(QObject::tr("Any arguments you want passed to the "
                    "mythfilldatabase program."));
    return be;
}

static GlobalLineEdit *MythFillDatabaseLog()
{
    GlobalLineEdit *be = new GlobalLineEdit("MythFillDatabaseLog");
    be->setLabel(QObject::tr("mythfilldatabase Log Path"));
    be->setValue("");
    be->setHelpText(QObject::tr("File or directory to use for logging "
                    "output from the mythfilldatabase program.  Leave blank "
                    "to disable logging."));
    return be;
}

class MythLogSettings : public TriggeredConfigurationGroup
{
  public:
    MythLogSettings() : TriggeredConfigurationGroup(false, true, false, false)
    {
         setLabel(QObject::tr("Myth Database Logging"));
//         setUseLabel(false);

         Setting* logEnabled = LogEnabled();
         addChild(logEnabled);
         setTrigger(logEnabled);
         addChild(LogMaxCount());

         ConfigurationGroup* settings = new VerticalConfigurationGroup(false);
         settings->addChild(LogPrintLevel());
         settings->addChild(LogCleanEnabled());
         settings->addChild(LogCleanPeriod());
         settings->addChild(LogCleanDays());
         settings->addChild(LogCleanMax());
         addTarget("1", settings);

         // show nothing if logEnabled is off
         addTarget("0", new VerticalConfigurationGroup(true));
     };
};

class MythFillSettings : public TriggeredConfigurationGroup
{
  public:
     MythFillSettings() :
         TriggeredConfigurationGroup(false, true, false, false)
     {
         setLabel(QObject::tr("Mythfilldatabase"));
         setUseLabel(false);

         Setting* fillEnabled = MythFillEnabled();
         addChild(fillEnabled);
         setTrigger(fillEnabled);

         ConfigurationGroup* settings = new VerticalConfigurationGroup(false);
         settings->addChild(MythFillDatabasePath());
         settings->addChild(MythFillDatabaseArgs());
         settings->addChild(MythFillDatabaseLog());
         settings->addChild(MythFillPeriod());
         settings->addChild(MythFillMinHour());
         settings->addChild(MythFillMaxHour());
         settings->addChild(MythFillGrabberSuggestsTime());
         addTarget("1", settings);

         // show nothing if fillEnabled is off
         addTarget("0", new VerticalConfigurationGroup(true));
     };
};

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") + " (" +
                          gContext->GetHostName() + ")");
    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"));
    HorizontalConfigurationGroup* master =
              new HorizontalConfigurationGroup(false, false, true, true);
    master->addChild(MasterServerIP());
    master->addChild(MasterServerPort());
    masterServer->addChild(master);
    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());
    fm->addChild(StorageScheduler());
    group2->addChild(fm);
    group2->addChild(MiscStatusScript());
    group2->addChild(DisableAutomaticBackup());
    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(SleepCommand());
    slaveBackend->addChild(WakeUpCommand());
    group4->addChild(slaveBackend);
    addChild(group4);

    VerticalConfigurationGroup* backendControl = new VerticalConfigurationGroup();
    backendControl->setLabel(QObject::tr("Backend Control"));
    backendControl->addChild(BackendStopCommand());
    backendControl->addChild(BackendStartCommand());
    addChild(backendControl);
    
    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);

    VerticalConfigurationGroup* group8 = new VerticalConfigurationGroup(false);
    group8->setLabel(QObject::tr("UPNP Server Settings"));
    //group8->addChild(UPNPShowRecordingUnderVideos());
    group8->addChild(UPNPWmpSource());
    group8->addChild(UPNPRebuildDelay());
    addChild(group8);

    MythLogSettings *mythlog = new MythLogSettings();
    addChild(mythlog);

    MythFillSettings *mythfill = new MythFillSettings();
    addChild(mythfill);
    
}
