//See TextBase Layer.

#define ATTR (BLACK << 12 + WHITE << 8)

U32 text[TEXT_ROWS][TEXT_COLS];

U0 DrawIt(CTask *task, CDC *)
{ //gr.text_base gets clear 60fps, so we must use our own permanent text array.
    MemCopy(gr.text_base + TEXT_COLS, text, (TEXT_ROWS - 1) * TEXT_COLS * sizeof(U32));

    // You can copy it this way, if you like:
    //  I64 i, j;
    //  for (j = 0; j < TEXT_ROWS; j++)
    //      for (i = 0; i < TEXT_COLS; i++)
    //       TextChar(task,, i, j, text[j][i]);

    TextPrint(task, 0, 0, ATTR >> 8, "Draw a maze with left button.");
    TextPrint(task, 0, 1, ATTR >> 8, "Solve maze starting at right click.");
}

#define STACK_SIZE 2048
//We would put these as local variables
//in SolveMaze() but the system stack size
//is limited, so it's a bad habit.  The heap
//is the normal ZealOS technique, but
//it's a pain in this case.
I64 stack_ptr,  stack_x  [STACK_SIZE], 
                stack_y  [STACK_SIZE], 
                stack_dir[STACK_SIZE];

//Four directions:
//  0=Up, 1=right,2=down,3=left
I64 dir_x[4] = { 0, +1,  0, -1},   // Could use gr_x_offsets2,gr_y_offsets2
    dir_y[4] = {+1,  0, -1,  0};

U0 SolveMaze(I64 x, I64 y)
{
    I64 dir = 0;

    stack_ptr = 0;
    stack_x[stack_ptr] = x;
    stack_y[stack_ptr] = y;
    stack_dir[stack_ptr++] = dir;
    while (TRUE)
    {
        if (!(0 <= x < MinI64(Fs->win_width,  TEXT_COLS)) ||
            !(0 <= y < MinI64(Fs->win_height, TEXT_ROWS)) )
        {
            Beep;
            Beep;
            break;
        }
        if (!text[y][x].u8[0])
            text[y][x] = '.' + ATTR;
        x += dir_x[dir];
        y += dir_y[dir];
//u8.[0] is the ASCII
        if (text[y][x].u8[0])
        {
            x -= dir_x[dir];
            y -= dir_y[dir];
            if (++dir == 4)
            {
                if (--stack_ptr < 0)
                    return;
                x = stack_x[stack_ptr];
                y = stack_y[stack_ptr];
                dir = stack_dir[stack_ptr];
            }
        }
        else
        {
            dir = 0;
            stack_x[stack_ptr] = x;
            stack_y[stack_ptr] = y;
            stack_dir[stack_ptr++] = dir;
            if (stack_ptr == STACK_SIZE)
                return;
            Sleep(100);
            if (CharScan)
                throw;
        }
    }
}

U0 Maze()
{
    I64 ch, x, y;

    SettingsPush; //See SettingsPush
    AutoComplete;
    WinBorder;
    WinMax;
    DocCursor;
    DocClear;
    Fs->draw_it     = &DrawIt;
    Fs->win_inhibit = WIG_TASK_DEFAULT - WIF_SELF_FOCUS - WIF_SELF_BORDER;

    try
        do
        {
            MemSet(text, 0, sizeof(text));
            while (!(ch = CharScan))
            {
                x = mouse.pos_text.x - Fs->win_left - Fs->scroll_x / FONT_WIDTH;
                y = mouse.pos_text.y - Fs->win_top  - Fs->scroll_y / FONT_HEIGHT;
                if (mouse.lb && !winmgr.grab_scroll)
                    text[y][x] = CH_SPACE + ATTRF_INVERT + ATTR;
                if (mouse.rb && !winmgr.grab_scroll)
                {
                    text[y][x] = '*'+ATTR;
                    SolveMaze(x, y);
                    ch = CharGet;
                    break;
                }
                Refresh;
            }
        }
        while (ch != CH_SHIFT_ESC && ch != CH_ESC);

    catch
        PutExcept;
    SettingsPop;
}

Maze;