#help_index "DolDoc/Misc"

U8 captured_macro_name[STR_LEN];
StrCopy(captured_macro_name, "Test");

I64 sys_macro_repeat_n = 1;

U0 SysMacroStripKey(CJob *macro_head, I64 arg1, I64 arg2)
{
        CJob *tmpc,*tmpc1;

        tmpc = macro_head->next;
        while (tmpc != macro_head)
        {
                tmpc1 = tmpc->next;
                if (tmpc->job_code == JOBT_MESSAGE &&
                        (tmpc->message_code == MESSAGE_KEY_DOWN ||
                         tmpc->message_code == MESSAGE_KEY_UP ||
                         tmpc->message_code == MESSAGE_KEY_DOWN_UP) &&
                        arg1 && tmpc->aux1 == arg1 || !arg1 && tmpc->aux2 == arg2)
                {
                        QueueRemove(tmpc);
                        JobDel(tmpc);
                }
                tmpc = tmpc1;
        }
}

#define MT_NULL         0
#define MT_MESSAGE      1
#define MT_CHAR         2

class CMacroTmp
{
        CMacroTmp       *next, *last;
        I64                      type;
        U8                       buf[STR_LEN];
};

CMacroTmp *Cmd2MT(CJob *tmpc)
{
        U8                       buf[8];
        CMacroTmp       *tmpmt = CAlloc(sizeof(CMacroTmp));

        if (Bt(char_bmp_macro, tmpc->aux1) && tmpc->message_code == MESSAGE_KEY_DOWN)
        {
                tmpmt->type = MT_CHAR;
                buf[0] = tmpc->aux1;
                buf[1] = 0;
                StrPrint(tmpmt->buf, "%Q", buf);
        }
        else
        {
                tmpmt->type = MT_MESSAGE;
                StrPrint(tmpmt->buf, "Message(0x%X,0x%X,0x%X);", tmpc->message_code, tmpc->aux1, tmpc->aux2);
        }

        return tmpmt;
}

U8 *SysMacro2Str(CJob *macro_head)
{
        CJob            *tmpc;
        I64                      count = 1; //terminating zero
        U8                      *ptr, *m;
        CMacroTmp       *tmpmt, *tmpmt1,head;

        LBtr(&sys_semas[SEMA_RECORD_MACRO], 0);

        QueueInit(&head);
        head.type = MT_NULL;
        tmpc = macro_head->next;
        while (tmpc != macro_head)
        {
                tmpmt = Cmd2MT(tmpc);
                QueueInsert(tmpmt, head.last);
                count += StrLen(tmpmt->buf);
                if (tmpmt->type == MT_CHAR)
                {
                        if (tmpmt->last->type != MT_CHAR)
                                count += StrLen("\"");
                        if (tmpmt->next->type != MT_CHAR)
                                count += StrLen("\";");
                }
                tmpc = tmpc->next;
        }

        m = MAlloc(count);
        ptr = m;

        tmpmt = head.next;
        while (tmpmt != &head)
        {
                tmpmt1 = tmpmt->next;
                if (tmpmt->type == MT_MESSAGE)
                {
                        StrCopy(ptr, tmpmt->buf);
                        ptr += StrLen(tmpmt->buf);
                }
                else
                {
                        if (tmpmt->last->type != MT_CHAR)
                        {
                                StrCopy(ptr, "\"");
                                ptr += StrLen("\"");
                        }
                        StrCopy(ptr, tmpmt->buf);
                        ptr += StrLen(tmpmt->buf);
                        if (tmpmt->next->type != MT_CHAR)
                        {
                                StrCopy(ptr, "\";");
                                ptr += StrLen("\";");
                        }
                }
                Free(tmpmt);
                tmpmt = tmpmt1;
        }
        *ptr = 0;

        return m;
}

U0 PlaySysMacro(I64 n=1)
{
        CTask   *task = sys_focus_task;
        U8              *m;

        if (TaskValidate(task))
        {
                LBtr(&sys_semas[SEMA_RECORD_MACRO], 0);
                m = SysMacro2Str(&sys_macro_head);
                while (n-- && TaskValidate(task))
                {
                        if (task == Fs)
                                InStr("%s", m);
                        else
                                XTalkStrWait(task, "%s", m);
                }
                Free(m);
        }
}

U0 EdInsCapturedMacro()
{
        U8 *st = SysMacro2Str(&sys_macro_head);

        if (sys_focus_task)
        {
                XTalk(sys_focus_task, "$MA+LIS,T=\"%s\",LM=\"%$Q\"$", captured_macro_name, st);
                Free(st);
        }
}

#define SM_RECORD               0
#define SM_INS                  1
#define SM_PLAY                 2
#define SM_REPEAT_N     3
#define SM_STOP                 4

I64 PopUpMacroMenu()
{
        I64                      res = 0;
        U8                       buf[STR_LEN];
        CJob            *tmpc;
        CDoc            *doc = DocNew;
        CDocEntry       *doc_e = DocPrint(doc, "$DA-P,LEN=STR_LEN-1,A=\"Name:%%s\"$");

        doc_e->data = captured_macro_name;
        DocDataFormat(doc, doc_e);

        doc_e = DocPrint(doc, "\n$DA,A=\"Repeat N:%%d\"$");
        doc_e->data = &sys_macro_repeat_n;
        DocDataFormat(doc, doc_e);

        DocPrint(doc,"\n"
                                "$CM+LX,1,3$$BT,\"RECORD\",LE=SM_RECORD$"
                                "$CM+LX,17,0$$BT,\"INSERT\",LE=SM_INS$"
                                "$CM+LX,1,3$$BT,\"PLAY\",LE=SM_PLAY$"
                                "$CM+LX,17,0$$BT,\"REPEAT N\",LE=SM_REPEAT_N$"
                                "$CM+LX,1,3$$BT,\"STOP\",LE=SM_STOP$"
                                "$CM+LX,17,0$$BT,\"CANCEL\",LE=DOCM_CANCEL$"
                                "\n\n\n$GREEN$SHIFT-F2$FG$ will play macro.\n");

        doc->flags |= DOCF_SIZE_MIN | DOCF_FORM;
        StrPrint(buf, "DocMenu(%d);", doc);
        sys_macro_task = Spawn(&ServerCmdLine, NULL, "Macro Popup",, Fs);
        Fs->popup_task = sys_macro_task;
        LBts(&sys_macro_task->display_flags, DISPLAYf_WIN_ON_TOP);
        tmpc = TaskExe(sys_macro_task, Fs, buf, 1 << JOBf_WAKE_MASTER | 1 << JOBf_FOCUS_MASTER);
        JobResScan(tmpc, &res);
        Fs->popup_task = NULL;
        Kill(sys_macro_task);
        sys_macro_task = NULL;
        DocDataScan(doc, doc_e);
        DocDel(doc);

        return res;
}

U0 MacroTask(I64)
{
        I64 i;

        StrCopy(captured_macro_name, "Click Here");
        sys_macro_repeat_n = 1;
        do
        {
                i = PopUpMacroMenu;
                WinRefocus(sys_focus_task);
                switch (i)
                {
                        case SM_RECORD:
                                LBtr(&sys_semas[SEMA_RECORD_MACRO], 0);
                                QueueDel(&sys_macro_head,TRUE);
                                LBts(&sys_semas[SEMA_RECORD_MACRO], 0);
                                break;

                        case SM_PLAY:
                                PlaySysMacro;
                                break;

                        case SM_REPEAT_N:
                                PlaySysMacro(sys_macro_repeat_n);
                                break;

                        case SM_STOP:
                                LBtr(&sys_semas[SEMA_RECORD_MACRO], 0);
                                break;

                        case SM_INS:
                                LBtr(&sys_semas[SEMA_RECORD_MACRO], 0);
                                EdInsCapturedMacro;
                                break;
                }
        }
        while (i >= 0);
}

U0 EdMacroUtil()
{
        if (!sys_macro_task)
                Spawn(&MacroTask, NULL, "Macro");
}