#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");
}