#help_index "DolDoc/Conversion"

//See ::/Doc/Credits.DD.

#define DOCET_UNDEF_COLOR           0x100000000
#define DOCET_LINK_UNDERLINE        0x200000000
U0 HtmlPutS(CDoc *doc, I64 u32_attr, I64 *_old_u32_attr, Bool underline_update, U8 *st, I64 *_col, U8 *style_bitmap=NULL)
{
    U8 *ch, *ptr;

    u32_attr &= 0xFFFFFF00;
    if (u32_attr & DOCET_INVERT)
        u32_attr.u8[1] = (u32_attr.u8[1] & 15) << 4 | u32_attr.u8[1] >> 4;
    if (underline_update && !(u32_attr & DOCET_UNDERLINE) && *_old_u32_attr & DOCET_UNDERLINE)
    {
        if (!(*_old_u32_attr & DOCET_LINK_UNDERLINE))
            DocPrint(doc, "</u>");
        *_old_u32_attr &= ~DOCET_LINK_UNDERLINE;
    }
    if (!(u32_attr & DOCET_BLINK) && *_old_u32_attr & DOCET_BLINK)
        DocPrint(doc, "</blink>");
    if (u32_attr & 0xFF00 != *_old_u32_attr & 0xFF00)
    {
        if (!(*_old_u32_attr & DOCET_UNDEF_COLOR))
            DocPrint(doc, "</span>");
        DocPrint(doc, "<span class=c%02X>", u32_attr.u8[1]);
        if (style_bitmap)
            LBts(style_bitmap, u32_attr.u8[1]);
    }
    if (u32_attr & DOCET_BLINK && !(*_old_u32_attr & DOCET_BLINK))
        DocPrint(doc, "<blink>");
    if (underline_update)
    {
        if (u32_attr & DOCET_UNDERLINE && !(*_old_u32_attr & DOCET_UNDERLINE))
            DocPrint(doc, "<u>");
    }
    else //Keep same underline status.
        u32_attr = u32_attr & ~DOCET_UNDERLINE | *_old_u32_attr & DOCET_UNDERLINE;

    *_old_u32_attr = u32_attr | *_old_u32_attr & DOCET_LINK_UNDERLINE;

    while (ch = *st++)
    {
        switch (ch)
        {
            case '\t':
                do
                {
                    DocPutKey(doc, CH_SPACE, 0);
                    *_col = *_col + 1;
                }
                while (*_col & 3);
                break;

            start:
                case 'pi':  ptr="pi";       break;
                case 'theta':   ptr="theta";    break;
                case 'phi': ptr="phi";      break;
                case 'omega':   ptr="omega";    break;
                case 'inf': ptr="inf";      break;
                case 'u':   ptr="u";        break;
            end:
                DocPrint(doc, ptr);
                *_col = *_col + StrLen(ptr);
                break;

            start:
                case '&':   ptr = "&amp;";  break;
                case '<':   ptr = "&lt;";   break;
                case '>':   ptr = "&gt;";   break;
                case '"':   ptr = "&quot;"; break;
            end:
                DocPrint(doc, ptr);
                *_col = *_col + 1;
                break;

            default:
                if (CH_SPACE <= ch < 0x7F || ch == '\n')
                    DocPutKey(doc, ch, 0);
                else
                    DocPrint(doc, ".");
                *_col = *_col + 1;
        }
    }
}

U8 *TOSLinkConvert2(U8 *filename, I64 line_num)
{// ::/  --> http://www.templeos.org/Wb/
//Make your own LinkConvert routine
    U8 *res = NULL, *st1, *st2, extension[STR_LEN];

    if (filename)
    {
        st1 = StrNew(filename);
        FileExtRemove(st1, extension);
        if (StrCompare(extension, "html"))
            st2 = MStrPrint("%s.%s.html", st1, extension);
        else
            st2 = MStrPrint("%s.html", st1);
        
//      st = ExtChange(filename, "html");
        if (st2 && StrLen(st2) > 3 && !StrNCompare(st2 + 1, ":/", 2))
            res = MStrPrint("https://zeal-operating-system.github.io/ZealOS/%s#l%d", st2 + 3, line_num);
        Free(st1);
        Free(st2);
    }

    return res;
}

U8 *URLBibleGateway(U8 *src)
{
    U8 buf[STR_LEN], *dst = buf;

    if (!MemCompare(src, "BF:", 3))
        src += 3;
    while (*src)
    {
        if (*src == CH_SPACE || *src == ',')
            *dst++ = '+';
        else
            *dst++ = *src;
        src++;
    }
    *dst = 0;
    if (StrOcc(buf, '-'))
        return MStrPrint("http://www.biblegateway.com/passage/?search=%s&version=NIV", buf);
    else
        return MStrPrint("http://www.biblegateway.com/verse/en/%s", buf);
}

U8 *TOSLinkConvert1(U8 *link_st)
{
    static CDoc *bible=NULL;
    static I64 locks=0;
    U8 *res=NULL, *filename, *needle;
    I64 i, num;

    if (link_st)
    {
        switch (i = EdLinkConvert(link_st, &filename, &needle, &num))
        {
            case LK_FILE_LINE:
            case LK_PLAIN_LINE:
            case LK_FILE:
                res = TOSLinkConvert2(filename, num);
                break;

            case -1:
            case LK_DEF:
            case LK_HELP_INDEX:
            case LK_DOC:
            case LK_DOC_ANCHOR:
            case LK_DOC_FIND:
            case LK_DOC_LINE:
                break;

            case LK_BIBLE_FIND:
                while (LBts(&locks, 0))
                    Yield;
                if (!bible)
                    bible = Sys("DocRead(\"%s\");", filename);
                if (DocFind(bible, num, needle))
                    res = URLBibleGateway(link_st);
                LBtr(&locks, 0);
                break;

            default:
                if (DocFileEd(i, filename, needle, &num, EDF_UNCOLLAPSE | EDF_BAIL))
                    res = TOSLinkConvert2(filename, num);
        }
        Free(filename);
        Free(needle);
    }

    return res;
}

public CDoc *Doc2Html(CDoc *doc_in, U8 *html_header=NULL, U8 *body_header=NULL, 
                      U8 *body_footer=NULL, U8 *html_footer=NULL, Bool line_anchors=TRUE, 
                      U8 (*link_convert)(U8 *link_st)=&TOSLinkConvert1, Bool line_nums=FALSE)
{//Convert DolDocdoc to HTML file.
    CDocEntry   *doc_e, *style, *doc_e2;
    I64          i, y, old_y = I64_MIN, col, old_u32_attr = DOCET_UNDEF_COLOR, old_attr, digits;
    U32         *hl, *src;
    U8          *st, st_2[2], *link_st, *style_bitmap = CAlloc(256 / 8);
    CBGR24       p[COLORS_NUM];
    GrPaletteGet(p);
    CDoc        *doc_out = DocNew;
    Bool         unlock_doc_in = DocLock(doc_in), no_bwd;

    old_attr = doc_in->win_task->text_attr;
    doc_in->win_task->text_attr = DOC_ATTR_DEFAULT_TEXT;

    for (i = 0xF0; i <= 0xFF; i++)
        LBts(style_bitmap, i);

    DocRecalc(doc_in, RECALCt_NORMAL | RECALCF_TO_HTML);

    digits = Log10(doc_in->head.last->y + 1) + 1;

    st_2[0] = 0;
    st_2[1] = 0;
    doc_out->flags |= DOCF_PLAIN_TEXT | DOCF_NO_CURSOR;

    if (!html_header)
        html_header =
                    "<!DOCTYPE HTML>\n"
                    "<html>\n"
                    "<head>\n"
                    "<meta http-equiv=\"Content-Type\" "
                    "content=\"text/html;charset=US-ASCII\">\n"
                    "<meta name=\"generator\" content=\"ZealOS V0.14\">\n";
    if (!body_header)
        body_header =
                    "<body>\n"
                    "<pre style=\"font-family:monospace;font-size:12pt\">\n";
    if (!body_footer)
        body_footer =
                    "</pre></body>\n";
    if (!html_footer)
        html_footer =
                    "</html>\n";

    DocPrint(doc_out, "%s", html_header);

    DocPrint(doc_out, "<style type=\"text/css\">\n");
    style = doc_out->cur_entry->last;
    DocPrint(doc_out, 
                "</style>\n"
                "</head>\n");
    DocPrint(doc_out, "%s", body_header);

    doc_e = doc_in->head.next;
    col = doc_e->x;
    y = doc_e->y;
    while (doc_e != doc_in)
    {
        if (!(doc_e->de_flags & DOCEF_SKIP))
        {
            if (y != old_y)
            {
                if (line_anchors)
                    DocPrint(doc_out, "<a name=\"l%d\"></a>", y + 1);
                if (line_nums)
                    DocPrint(doc_out, "%0*d ", digits, y + 1);
                old_y = y;
            }
            while (y < doc_e->y)
            {
                HtmlPutS(doc_out, doc_e->settings.final_u32_attr, &old_u32_attr, FALSE, "\n", &col, style_bitmap);
                if (++y != old_y)
                {
                    if (line_anchors)
                        DocPrint(doc_out, "<a name=\"l%d\"></a>", y + 1);
                    if (line_nums)
                        DocPrint(doc_out, "%0*d ", digits, y + 1);
                    old_y = y;
                }
                col = 0;
            }

            no_bwd = TRUE;
            doc_e2 = doc_e->next;
            while (doc_e2 != doc_in && doc_e2->y == doc_e->y)
            {
                if (doc_e2->x < doc_e->x)
                {
                    no_bwd = FALSE;
                    break;
                }
                doc_e2 = doc_e2->next;
            }

            if (no_bwd)
                while (col < doc_e->x)
                    HtmlPutS(doc_out,
                            doc_e->settings.final_u32_attr & ~DOCET_UNDERLINE, &old_u32_attr, TRUE, " ", &col, style_bitmap);

            link_st = NULL;
            if (doc_e->de_flags & DOCEF_HTML_LINK)
                link_st = StrNew(doc_e->html_link);
            else if (st = DocEntryLink(doc_in, doc_e))
            {
                link_st = link_convert(st);
                Free(st);
            }

            if (link_st)
            {
                if (old_u32_attr & DOCET_UNDERLINE && !(old_u32_attr & DOCET_LINK_UNDERLINE))
                    DocPrint(doc_out, "</u>");
                if (old_u32_attr & DOCET_BLINK)
                    DocPrint(doc_out, "</blink>");
                if (!(old_u32_attr & DOCET_UNDEF_COLOR))
                    DocPrint(doc_out, "</span>");
                old_u32_attr = DOCET_UNDEF_COLOR | DOCET_UNDERLINE | DOCET_LINK_UNDERLINE;
                DocPrint(doc_out, "<a href=\"%s\">", link_st);
            }

            switch (doc_e->type_u8)
            {
                case DOCT_TEXT:
                    if (doc_e->de_flags & DOCEF_HIGHLIGHT)
                    {
                        if (doc_e->last == doc_in)
                            MemCopy(&doc_e->settings, &doc_in->settings_head, sizeof(CDocSettings));
                        else
                            MemCopy(&doc_e->settings, &doc_e->last->settings, sizeof(CDocSettings));
                        src = hl = DocHighlight(doc_e, doc_e->tag, StrLen(doc_e->tag), doc_e->type & 0xFF00);
                        while (*src)
                        {
                            st_2[0] = *src & 0xFF;
                            HtmlPutS(doc_out, *src++, &old_u32_attr, TRUE, st_2, &col, style_bitmap);
                        }
                        Free(hl);
                    }
                    else
                        HtmlPutS(doc_out,
                                    doc_e->settings.final_u32_attr, &old_u32_attr, TRUE, doc_e->tag, &col, style_bitmap);
                    break;

                case DOCT_TAB:
                    HtmlPutS(doc_out, doc_e->settings.final_u32_attr, &old_u32_attr, TRUE, "\t", &col, style_bitmap);
                    break;

                case DOCT_HTML_CODE:
                    if (old_u32_attr & DOCET_UNDERLINE && !(old_u32_attr & DOCET_LINK_UNDERLINE))
                        DocPrint(doc_out, "</u>");
                    if (old_u32_attr & DOCET_BLINK)
                        DocPrint(doc_out, "</blink>");
                    if (!(old_u32_attr & DOCET_UNDEF_COLOR))
                        DocPrint(doc_out, "</span>");
                    old_u32_attr = DOCET_UNDEF_COLOR;
                    DocPrint(doc_out, "%s", doc_e->tag);
                    break;

                case DOCT_SPRITE:
                    HtmlPutS(doc_out, doc_e->settings.final_u32_attr, &old_u32_attr, TRUE, doc_e->tag, &col, style_bitmap);
                    HtmlPutS(doc_out, doc_e->settings.final_u32_attr, &old_u32_attr, TRUE,
                                                                "/* Graphics Not Rendered in HTML */", &col, style_bitmap);
                    break;

                default:
                    if (doc_e->de_flags & DOCEF_TAG)
                        HtmlPutS(doc_out,
                                    doc_e->settings.final_u32_attr, &old_u32_attr, TRUE, doc_e->tag, &col, style_bitmap);
            }
            if (link_st)
            {
                if (old_u32_attr & DOCET_UNDERLINE && !(old_u32_attr & DOCET_LINK_UNDERLINE))
                    DocPrint(doc_out, "</u>");
                if (old_u32_attr & DOCET_BLINK)
                    DocPrint(doc_out, "</blink>");
                if (!(old_u32_attr & DOCET_UNDEF_COLOR))
                    DocPrint(doc_out, "</span>");
                DocPrint(doc_out, "</a>");
                old_u32_attr = DOCET_UNDEF_COLOR | DOCET_UNDERLINE | DOCET_LINK_UNDERLINE;
                Free(link_st);
            }
        }
        doc_e = doc_e->next;
    }
    while (y++ < doc_e->y)
    {
        HtmlPutS(doc_out, doc_e->settings.final_u32_attr, &old_u32_attr, TRUE, "\n", &col, style_bitmap);
        col = 0;
    }
    if (old_u32_attr & DOCET_UNDERLINE && !(old_u32_attr & DOCET_LINK_UNDERLINE))
        DocPrint(doc_out, "</u>");
    if (old_u32_attr & DOCET_BLINK)
        DocPrint(doc_out, "</blink>");
    if (!(old_u32_attr & DOCET_UNDEF_COLOR))
        DocPrint(doc_out, "</span>");
    old_u32_attr = DOCET_UNDEF_COLOR;
    DocPrint(doc_out, "%s", body_footer);
    DocPrint(doc_out, "%s", html_footer);

    doc_out->cur_entry = style->next;
    DocPrint(doc_out, "body {background-color:#%02x%02x%02x;}\n", p[WHITE].r, p[WHITE].g, p[WHITE].b);
    for (i = 0; i < 256; i++)
        if (Bt(style_bitmap, i))
            DocPrint(doc_out, 
                        ".c%02X{color:#%02x%02x%02x;background-color:#%02x%02x%02x;}\n", 
                        i, p[i & 15].r, p[i & 15].g, p[i & 15].b, 
                        p[i/16].r, p[i / 16].g, p[i / 16].b);
    doc_out->cur_entry = &doc_out->head;
    DocRecalc(doc_out);

    doc_in->win_task->text_attr = old_attr;

    if (unlock_doc_in)
        DocUnlock(doc_in);

    return doc_out;
}

#help_index "Cmd Line (Typically);DolDoc/Conversion;DolDoc/Cmd Line (Typically)"
public U0 ToHtml(U8 *_in_name, U8 *_out_name=NULL, U8 *html_header=NULL, 
                 U8 *body_header=NULL, U8 *body_footer=NULL, U8 *html_footer=NULL, 
                 I64 width=128, Bool line_anchors=TRUE, 
                 U8 (*link_convert)(U8 *link_st)=&TOSLinkConvert1, Bool line_nums=FALSE)
{//Convert DolDocfile to HTML.
//Supply your own link_convert routine.
    U8   *in_name, *out_name;
    CDoc *doc_in, *doc_out;

    SettingsPush; //See SettingsPush
    WinHorz(1, width - 2); //Sets doc width for word wrap.

    in_name=ExtDefault(_in_name, "CC");
    if (_out_name)
        out_name = ExtDefault(_out_name, "html");
    else
        out_name = ExtChange(_in_name, "html");

    doc_in = DocRead(in_name);
    doc_out = Doc2Html(doc_in, html_header, body_header, body_footer, html_footer, 
                line_anchors, link_convert, line_nums);
    StrCopy(&doc_out->filename.name, out_name);

    SettingsPop;

    DocWrite(doc_out);
    DocDel(doc_in);
    DocDel(doc_out);
    Free(in_name);
    Free(out_name);
}