#define BORDER_CHARS        1

U8   *buf;
I64   size, mp_not_done_flags;
CDoc *doc;

U0 PDNormalize()
{
    U8 *r = MAlloc(size+2*BORDER_CHARS), *src = buf, *dst = r;
    I64 ch;

    *dst++ = '['; //Border
    while (size--)
    {
        ch = *src++;
        if ('a' <= ch <= 'z') //lower is most common so do first
            *dst++ = ch;
        else if ('A' <= ch <= 'Z')
            *dst++ = ch + 'a' - 'A'; //Convert to lower
    }
    *dst++ = ']'; //Border
    Free(buf);
    buf = r;
    size = dst - r - 2 * BORDER_CHARS;
}

U0 PDAnswer(U8 *a, I64 len)
{
    DocLock(doc);
    a -= (len - 1) / 2;
    DocPrint(doc, "CPU%02X Len:%2d ", Gs->num, len);
    while (len--)
        DocPrint(doc, "%C", *a++); //%C is toupper char
    DocPrint(doc, "\n");
    DocUnlock(doc);
}

U0 MPPalindrome(I64 dummy=0)
{
    no_warn dummy;
    U8 *src = buf + BORDER_CHARS + size * Gs->num / mp_count, *f, *b;
    I64 len, best = 0, my_size = (size + mp_count - 1) / mp_count;
    while (my_size--)
    {

        //Odd
        f = src + 1;
        b = src - 1;
        while (*f == *b)
        {
            f++;
            b--;
        }
        len = f - b + 1 - 2;
        if (len > best)
        {
            best = len;
            PDAnswer(src, len);
        }

        //Even
        f = src + 1;
        b = src;
        while (*f == *b)
        {
            f++;
            b--;
        }
        len = f - b + 1 - 2;
        if (len > best)
        {
            best = len;
            PDAnswer(src, len);
        }

        src++;
    }
    LBtr(&mp_not_done_flags, Gs->num);
}

U0 Palindrome(U8 *filename)
{
    I64 i;
    F64 t0 = tS;

    buf = FileRead(filename, &size);
    PDNormalize;

    doc = DocPut;
    mp_not_done_flags = 1 << mp_count - 1;
    for (i = 0; i < mp_count; i++)
        JobQueue(&MPPalindrome, NULL, i);
    while (mp_not_done_flags)
        Yield;

    Free(buf);
    "Time:%9.5f\n", tS - t0;
}

Palindrome(BIBLE_FILENAME);