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 ", DivineWordStr, DivineWordStr, DivineWordStr, DivineWordStr);
					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 $LK,"SettingsPush",A="MN: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;
}
