#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 & 7);
                                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, *st;

        if (filename)
        {
                st = ExtChange(filename, "html");
                if (st && StrLen(st) > 3 && !StrNCompare(st + 1, ":/", 2))
                        res = MStrPrint("http://www.tomawezome.github.io/ZealOS/%s#l%d", st + 3, line_num);
                Free(st);
        }

        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.05\">\n";
        if (!body_header)
                body_header =
                                        "<body>\n"
                                        "<pre style=\"font-family:courier;font-size:10pt\">\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(0, width - 1); //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);
}