CTask *JukeReward(U8 *message)
{
        U8              *buf;
        CDoc    *doc;
        CTask   *res = Spawn(&ServerCmdLine, NULL, "Reward",, Fs);

        StrCopy(res->task_title, "Reward");
        res->title_src = TTS_LOCKED_CONST;

        doc = DocNew(, res);
        DocPrint(doc, "$WW+H,1$$RED$%s", message);

        buf = MStrPrint("DocEd(0x%X);", doc);
        TaskExe(res, NULL, buf, 1 << JOBf_EXIT_ON_COMPLETE | 1 << JOBf_FREE_ON_COMPLETE);
        Free(buf);
        TaskWait(res);

        res->border_src  = BDS_CONST;
        res->border_attr = LTGRAY << 4 + DriveTextAttrGet(':') & 15;
        res->text_attr   = LTGRAY << 4 + BLUE;
        res->win_inhibit = WIG_NO_FOCUS_TASK_DEFAULT;
        WinHorz(Fs->win_right + 2, TEXT_COLS - 2, res);
        WinVert(2, TEXT_ROWS - 2, res);

        WinFocus(Fs->parent_task);

        return res;
}

CTask *SingleSong(U8 *message, U8 *name)
{
        CTask *task = Spawn(&ServerCmdLine, NULL, name,, Fs);

        StrCopy(task->task_title, name);
        task->title_src = TTS_LOCKED_CONST;
        TaskExe(task, Fs, ";", 1 << JOBf_WAKE_MASTER | 1 << JOBf_FREE_ON_COMPLETE);
        WinHorz(task->win_left, task->win_left + 50, task);
        WinVert(2, 2 + 8, task);
        task->win_inhibit = WIG_NO_FOCUS_TASK_DEFAULT;
        TaskExe(task, NULL, message, 1 << JOBf_EXIT_ON_COMPLETE |1 << JOBf_FREE_ON_COMPLETE);
        DocPut(task)->max_entries = 100;

        return task;
}

#define JB_RUN_LEVEL_NULL               0
#define JB_RUN_LEVEL_ONE                1
#define JB_RUN_LEVEL_TWO                2

Bool JBPutKey(CDoc *doc, U8 *, I64 ch, I64 sc)
{//ch=ASCII; sc=scan_code
        CDocEntry       *doc_ce = doc->cur_entry, *doc_e;
        CDirEntry       *tmpde;
        I64                      i;
        U8                      *st;
        CDoc            *doc2;

        if (!(sc & (SCF_ALT | SCF_CTRL | SCF_SHIFT)) && doc_ce->type_u8 == DOCT_MENU_VAL && doc_ce->left_exp >= 0)
        {
                tmpde = doc_ce->left_exp;
                if (sc.u8[0] == SC_DELETE)
                {
                        Beep;
                        Silent;
                        Del(tmpde->full_name);
                        Silent(OFF);
                }
                else if ('0' <= ch <= '9')
                {
                        if (StrLen(doc_ce->tag) > 1)
                                doc_ce->tag[0] = ch;
                        doc2 = DocRead(tmpde->full_name);
                        DocGoToLine(doc2, 1);
                        doc_e = doc2->cur_entry;
                        if (doc_e != doc2 && doc_e->type_u8 == DOCT_TEXT && StrLen(doc_e->tag) >= 3)
                        {
                                doc_e->tag[2] = ch;
                                DocWrite(doc2);
                        }
                        DocDel(doc2);
                        return TRUE;
                }
                else if (ch == 'r')
                {
                        if (!DocTreeFFind(tmpde->full_name, "Reward1"))
                        {
                                doc2 = DocRead(tmpde->full_name);
                                DocGoToLine(doc2, 2);
                                DocPrint(doc2, 
                                                        "\n$TR,\"Reward1\"$\n"
                                                        "$ID,2$CallExtStr(\"JukeReward\",\"\"\n"
                                                        "$TR,\"Reward2\"$\n"
                                                        "$ID,2$\n"
                                                        "$ID,-2$\n"
                                                        ");\n$ID,-2$\n"
                                                        );
                                DocWrite(doc2);
                                DocDel(doc2);
                        }
                        if (DocTreeFFind(tmpde->full_name, "Reward1/Reward2"))
                        {
                                for (i = 0; i < 5; i++)
                                {
                                        st = MStrPrint("%s %s %s %s ", GodWordStr, GodWordStr, GodWordStr, GodWordStr);
                                        DocTreeFAppend(tmpde->full_name, "Reward1/Reward2", "\"%s\"\n", st);
                                        Free(st);
                                }
                                In(" ");
                        }
                        return TRUE;
                }
                else if (ch == CH_SPACE || ch == CH_ESC)
                        tmpde->user_data++; //JB_RUN_LEVEL++
                        //<SPACE> is followed by <ESC> --> JB_RUN_LEVEL_TWO
                        //Actual <ESC> just exits      --> JB_RUN_LEVEL_ONE
        }

        return FALSE;
}

public U0 JukeBox(U8 *dirname="~/Psalmody", U8 **_filename=NULL)
{//_filename is for using this as a song-chooser program.
        I64                      i = 0, rating;
        U8                      *st, *st2;
        CDirEntry       *tmpde, *tmpde1;
        CDoc            *doc = DocNew, *s;
        CDocEntry       *doc_e;
        CTask           *task = NULL;

        if (_filename)
                *_filename = NULL;
        SettingsPush; //See SettingsPush
        AutoComplete;
        try
        {
                dirname = StrNew(dirname);
                st = MStrPrint("%s/*.CC", dirname);
                tmpde = tmpde1 = FilesFind(st);
                Free(st);
                Free(dirname);
                doc->user_put_key = &JBPutKey;
                DocPrint(doc, 
                                        "Key: $GREEN$Graphics $BLUE$Words $RED$No Nothing "
                                        "$BLACK$Incomplete $CYAN$Special$FG$\n\n"
                                        "$GREEN$<DEL>$FG$\tto delete a song.\n"
                                        "'$GREEN$0$FG$'-'$GREEN$9$FG$'\tto rate a song.\n"
                                        "'$GREEN$r$FG$'\tto get your reward from God.\n");
                while (tmpde)
                {
                        if (!(i++ % 5))
                                DocPrint(doc, "\n");
                        if (FileOcc("Play(", tmpde->full_name, ""))
                        {
                                st = StrNew(tmpde->name);
                                FileExtRemove(st);
                                s = DocRead(tmpde->full_name);
                                doc_e = s->head.next;
                                while (doc_e != s && doc_e->type_u8 != DOCT_TEXT)
                                        doc_e = doc_e->next;
                                rating = '0';
                                if (doc_e != s && doc_e->type_u8 == DOCT_TEXT)
                                {
                                        if ('0' <= doc_e->tag[2] <= '9')
                                                rating = doc_e->tag[2];
                                        if (StrMatch("incomplete", doc_e->tag))
                                                DocPrint(doc, "$BLACK$");
                                        else if (StrMatch("has graphics", doc_e->tag))
                                                DocPrint(doc, "$GREEN$");
                                        else if (StrMatch("has words", doc_e->tag))
                                                DocPrint(doc, "$BLUE$");
                                        else if (StrMatch("special", doc_e->tag))
                                                DocPrint(doc, "$CYAN$");
                                        else if (StrMatch("no nothing", doc_e->tag))
                                        {
                                                DocPrint(doc, "$RED$");
                                                if (FileOcc("\\0", tmpde->full_name, ""))
                                                {
                                                        s->cur_entry = doc_e->next;
                                                        s->cur_col = 0;
                                                        DocEntryDel(s, doc_e);
                                                        DocPrint(s, "//0 has words\n");
                                                        DocWrite(s);
                                                }
                                        }
                                        DocPrint(doc, "$MU-UL,\"%c%-8ts\",LE=%d$ ", rating, st, tmpde);
                                        tmpde->user_data = JB_RUN_LEVEL_NULL;
                                }
                                DocDel(s);
                                Free(st);
                        }
                        tmpde = tmpde->next;
                }
                DocPrint(doc, "\n$CYAN$$MU-UL,\"DONE\",LE=%d$\n", DOCM_CANCEL);
                while (TRUE)
                {
                        if (_filename)
                                tmpde = PopUpMenu(doc, DOF_INTERCEPT_TASK_END);
                        else
                                tmpde = PopUpMenu(doc);
                        if (task)
                                Kill(task);
                        if (tmpde <= 0)
                                break;
                        st2 = StrNew(tmpde->name);
                        if (_filename)
                        {
                                Free(*_filename);
                                *_filename = StrNew(tmpde->full_name);
                        }
                        if (tmpde->user_data == JB_RUN_LEVEL_ONE)
                                break; //<ESC>
                        tmpde->user_data = JB_RUN_LEVEL_NULL; //Reset from <SPACE>
                        FileExtRemove(st2);
                        st = MStrPrint("ExeFile(\"%s\");", tmpde->full_name);
                        MusicSettingsReset;
                        task = SingleSong(st, st2);
                        Free(st2);
                        Free(st);
                }
                DocDel(doc);
                DirTreeDel(tmpde1);
        }
        catch
                PutExcept;
        SettingsPop;
}