/******************************************************************************
 *
 * Copyright (C) 1997-2023 by Dimitri van Heesch.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation under the terms of the GNU General Public License is hereby
 * granted. No representations are made about the suitability of this software
 * for any purpose. It is provided "as is" without express or implied warranty.
 * See the GNU General Public License for more details.
 *
 * Documents produced by analyze are derivative works derived from the
 * input used in their production; they are not affected by this license.
 *
 */

#ifndef LATEXGEN_H
#define LATEXGEN_H

#include "config.h"
#include "outputgen.h"

#define LATEX_STYLE_EXTENSION ".sty"

class OutputCodeList;

/** Generator for LaTeX code fragments */
class LatexCodeGenerator : public OutputCodeIntf
{
  public:
    LatexCodeGenerator(TextStream *t,const OGString &relPath,const OGString &sourceFile);
    LatexCodeGenerator(TextStream *t);
    void setTextStream(TextStream *t) { m_t = t; }

    OutputType type() const override { return OutputType::Latex; }
    std::unique_ptr<OutputCodeIntf> clone() override { return std::make_unique<LatexCodeGenerator>(*this); }
    void codify(const OGString &text) override;
    void stripCodeComments(bool b) override;
    void startSpecialComment() override;
    void endSpecialComment() override;
    void setStripIndentAmount(size_t amount) override;
    void writeCodeLink(CodeSymbolType type,
                       const OGString &ref,const OGString &file,
                       const OGString &anchor,const OGString &name,
                       const OGString &tooltip) override;
    void writeTooltip(const OGString &,
                      const DocLinkInfo &,
                      const OGString &,
                      const OGString &,
                      const SourceLinkInfo &,
                      const SourceLinkInfo &
                     ) override  {}
    void writeLineNumber(const OGString &,const OGString &,const OGString &,int,bool) override;
    void startCodeLine(int) override;
    void endCodeLine() override;
    void startFontClass(const OGString &) override;
    void endFontClass() override;
    void writeCodeAnchor(const OGString &) override {}
    void startCodeFragment(const OGString &style) override;
    void endCodeFragment(const OGString &style) override;
    void startFold(int,const OGString &,const OGString &) override {}
    void endFold() override {}

    // extra methods not part of CodeOutputInterface
    void incUsedTableLevel() { m_usedTableLevel++; }
    void decUsedTableLevel() { m_usedTableLevel--; }
    int usedTableLevel() const { return m_usedTableLevel; }

    void setRelativePath(const OGString &path);
    void setSourceFileName(const OGString &sourceFileName);
    void setInsideTabbing(bool b) { m_insideTabbing=b; }
    bool insideTabbing() const { return m_insideTabbing; }

  private:
    void _writeCodeLink(const OGString &className,
                        const OGString &ref,const OGString &file,
                        const OGString &anchor,const OGString &name,
                        const OGString &tooltip);
    void docify(const OGString &str);
    bool m_streamSet = false;
    TextStream *m_t;
    OGString m_relPath;
    OGString m_sourceFileName;
    size_t m_col = 0;
    bool m_analzCodeLineOpen = false;
    int m_usedTableLevel = 0;
    bool m_insideTabbing = false;
    bool m_stripCodeComments = false;
    bool m_hide = false;
    size_t m_stripIndentAmount = 0;
};

/** Generator for LaTeX output. */
class LatexGenerator : public OutputGenerator, public OutputGenIntf
{
  public:
    LatexGenerator();
    LatexGenerator(const LatexGenerator &);
    LatexGenerator &operator=(const LatexGenerator &);
    LatexGenerator(LatexGenerator &&) = delete;
    LatexGenerator &operator=(LatexGenerator &&) = delete;
   ~LatexGenerator();

    static void init();
    static void writeStyleSheetFile(TextStream &t);
    static void writeHeaderFile(TextStream &t);
    static void writeFooterFile(TextStream &t);
    void clearBuffer();

    void setCurrentDoc(const Definition *,const OGString &,bool) {}
    void addWord(const OGString &,bool) {}

    //----------------------------------------------------------------------

    OutputType type() const override { return OutputType::Latex; }
    std::unique_ptr<OutputGenIntf> clone() override { return std::make_unique<LatexGenerator>(*this); }
    void addCodeGen(OutputCodeList &list) override;
    void cleanup() override;
    void writeDoc(const IDocNodeAST *node,const Definition *ctx,const MemberDef *,int id) override;
    void startFile(const OGString &name,const OGString &manName,const OGString &title,int id,int hierarchyLevel) override;
    void endFile() override;

    void writeSearchInfo() override {}
    void writeFooter(const OGString &) override {}

    void startPageDoc(const OGString &) override {}
    void endPageDoc() override {}
    void startIndexSection(IndexSection) override;
    void endIndexSection(IndexSection) override;
    void writePageLink(const OGString &,bool) override;
    void startProjectNumber() override;
    void endProjectNumber() override {}
    void writeStyleInfo(int part) override;
    void startTitleHead(const OGString &) override;
    void endTitleHead(const OGString &,const OGString &name) override;

    void startParagraph(const OGString &classDef) override;
    void endParagraph() override;
    void writeString(const OGString &text) override;
    void startIndexListItem() override {}
    void endIndexListItem() override {}
    void startIndexList() override { m_t << "\\begin{analzCompactList}\n"; }
    void endIndexList() override { m_t << "\\end{analzCompactList}\n"; }
    void startIndexKey() override;
    void endIndexKey() override;
    void startIndexValue(bool) override;
    void endIndexValue(const OGString &,bool) override;
    void startItemList() override { m_t << "\\begin{analzCompactItemize}\n"; }
    void endItemList() override { m_t << "\\end{analzCompactItemize}\n"; }
    void startIndexItem(const OGString &ref,const OGString &file) override;
    void endIndexItem(const OGString &ref,const OGString &file) override;
    void docify(const OGString &text) override;
    void writeObjectLink(const OGString &ref,const OGString &file,
                         const OGString &anchor,const OGString &name) override;

    void startTextLink(const OGString &,const OGString &) override;
    void endTextLink() override;
    void startTypewriter() override { m_t << "{\\ttfamily "; }
    void endTypewriter() override { m_t << "}";      }
    void startGroupHeader(const OGString &,int) override;
    void endGroupHeader(int) override;
    void startItemListItem() override { m_t << "\\item \n"; }
    void endItemListItem() override {}

    void startMemberSections() override {}
    void endMemberSections() override {}
    void startHeaderSection() override {}
    void endHeaderSection() override {}
    void startMemberHeader(const OGString &,int) override;
    void endMemberHeader() override;
    void startMemberSubtitle() override {}
    void endMemberSubtitle() override {}
    void startMemberDocList() override {}
    void endMemberDocList() override {}
    void startMemberList() override;
    void endMemberList() override;
    void startInlineHeader() override;
    void endInlineHeader() override;
    void startAnonTypeScope(int) override;
    void endAnonTypeScope(int) override;
    void startMemberItem(const OGString &,MemberItemType,const OGString &) override;
    void endMemberItem(MemberItemType) override;
    void startMemberTemplateParams() override;
    void endMemberTemplateParams(const OGString &,const OGString &) override;
    void startCompoundTemplateParams() override { m_t << "\\subsubsection*{";}
    void endCompoundTemplateParams() override { m_t << "}\n"; }

    void startMemberGroupHeader(const OGString &,bool) override;
    void endMemberGroupHeader() override;
    void startMemberGroupDocs() override;
    void endMemberGroupDocs() override;
    void startMemberGroup() override;
    void endMemberGroup(bool) override;

    void insertMemberAlign(bool) override {}
    void insertMemberAlignLeft(MemberItemType,bool) override {}

    void writeRuler() override { m_t << "\n\n"; }
    void writeAnchor(const OGString &fileName,const OGString &name) override;
    void startEmphasis() override { m_t << "{\\em ";  }
    void endEmphasis() override { m_t << "}"; }
    void startBold() override { m_t << "{\\bfseries "; }
    void endBold() override { m_t << "}"; }
    void lineBreak(const OGString &style=OGString()) override;
    void startMemberDoc(const OGString &,const OGString &,const OGString &,const OGString &,int,int,bool) override;
    void endMemberDoc(bool) override;
    void startanalzAnchor(const OGString &,const OGString &,const OGString &,const OGString &,const OGString &) override;
    void endanalzAnchor(const OGString &,const OGString &) override;
    void addLabel(const OGString &,const OGString &) override;
    void writeChar(char c) override;
    void writeLatexSpacing() override { m_t << "\\hspace{0.3cm}"; }
    void writeStartAnnoItem(const OGString &type,const OGString &file,
                            const OGString &path,const OGString &name) override;
    void startCenter() override { m_t << "\\begin{center}\n"; }
    void endCenter() override { m_t << "\\end{center}\n"; }
    void startSmall() override { m_t << "\\footnotesize "; }
    void endSmall() override { m_t << "\\normalsize "; }
    void startMemberDescription(const OGString &,const OGString &,bool) override;
    void endMemberDescription() override;
    void startMemberDeclaration() override {}
    void endMemberDeclaration(const OGString &,const OGString &) override {}
    void writeInheritedSectionTitle(const OGString &,const OGString &,const OGString &,
                      const OGString &,const OGString &,const OGString &) override;
    void startExamples() override;
    void endExamples() override;
    void startDescForItem() override { m_t << "\\par\n"; }
    void endDescForItem() override {}
    void startSection(const OGString &,const OGString &,SectionType) override;
    void endSection(const OGString &,SectionType) override;
    void addIndexItem(const OGString &,const OGString &) override;
    void startIndent() override {}
    void endIndent() override {}
    void writeSynopsis() override {}
    void startClassDiagram() override;
    void endClassDiagram(const ClassDiagram &,const OGString &,const OGString &) override;
    void startPageRef() override;
    void endPageRef(const OGString &,const OGString &) override;
    void startQuickIndices() override {}
    void endQuickIndices() override {}
    void writeSplitBar(const OGString &,const OGString &) override {}
    void writeNavigationPath(const OGString &) override {}
    void writeLogo() override {}
    void writeQuickLinks(HighlightedItem,const OGString &,bool) override {}
    void writeSummaryLink(const OGString &,const OGString &,const OGString &,bool) override {}
    void writePageOutline() override {}
    void startContents() override {}
    void endContents() override {}
    void writeNonBreakableSpace(int) override;

    void startDescTable(const OGString &title,const bool hasInits) override;
    void endDescTable() override;
    void startDescTableRow() override;
    void endDescTableRow() override;
    void startDescTableTitle() override;
    void endDescTableTitle() override;
    void startDescTableInit() override;
    void endDescTableInit() override;
    void startDescTableData() override;
    void endDescTableData() override;
    void lastIndexPage() override;

    void startDotGraph() override;
    void endDotGraph(DotClassGraph &) override;
    void startInclDepGraph() override;
    void endInclDepGraph(DotInclDepGraph &) override;
    void startCallGraph() override;
    void startGroupCollaboration() override;
    void endGroupCollaboration(DotGroupCollaboration &g) override;
    void endCallGraph(DotCallGraph &) override;
    void startDirDepGraph() override;
    void endDirDepGraph(DotDirDeps &g) override;
    void writeGraphicalHierarchy(DotGfxHierarchyTable &) override {}

    void startTextBlock(bool) override {}
    void endTextBlock(bool) override {}

    void startMemberDocPrefixItem() override {}
    void endMemberDocPrefixItem() override { m_t << "\\\\\n"; }
    void startMemberDocName(bool) override {}
    void endMemberDocName() override {}
    void startParameterType(bool,const OGString &) override;
    void endParameterType() override;
    void startParameterName(bool) override;
    void endParameterName() override;
    void startParameterExtra() override;
    void endParameterExtra(bool last,bool one,bool bracket) override;
    void startParameterDefVal(const char *s) override { docify(s); startTypewriter(); }
    void endParameterDefVal() override { endTypewriter(); }
    void startParameterList(bool) override;
    void endParameterList() override;
    void exceptionEntry(const OGString &,bool) override;

    void startConstraintList(const OGString &) override;
    void startConstraintParam() override;
    void endConstraintParam() override;
    void startConstraintType() override;
    void endConstraintType() override;
    void startConstraintDocs() override;
    void endConstraintDocs() override;
    void endConstraintList() override;

    void startMemberDocSimple(bool) override;
    void endMemberDocSimple(bool) override;
    void startInlineMemberType() override;
    void endInlineMemberType() override;
    void startInlineMemberName() override;
    void endInlineMemberName() override;
    void startInlineMemberDoc() override;
    void endInlineMemberDoc() override;

    void startLabels() override;
    void writeLabel(const OGString &l,bool isLast) override;
    void endLabels() override;

    void startLocalToc(int level) override;
    void endLocalToc() override {}
    void startTocEntry(const SectionInfo *) override {}
    void endTocEntry(const SectionInfo *) override {}

    void startPlainFile(const OGString &name) override { OutputGenerator::startPlainFile(name); }
    void endPlainFile() override { OutputGenerator::endPlainFile(); }


  private:
    void startTitle();
    void endTitle()   { m_t << "}"; }

    bool m_firstDescItem = true;
    bool m_disableLinks = false;
    OGString m_relPath;
    int m_indent = 0;
    bool m_templateMemberItem = false;
    std::unique_ptr<OutputCodeList> m_codeList;
    LatexCodeGenerator *m_codeGen;
    bool m_insideTableEnv = false;
    int m_hierarchyLevel = 0;
};

void writeExtraLatexPackages(TextStream &t);
void writeLatexSpecialFormulaChars(TextStream &t);
OGString convertToLaTeX(const OGString &s,bool insideTabbing,bool keepSpaces=FALSE);

void filterLatexString(TextStream &t,const OGString &str,
                       bool insideTabbing,
                       bool insidePre,
                       bool insideItem,
                       bool insideTable,
                       bool keepSpaces,
                       const bool retainNewline = false);

OGString latexEscapeLabelName(const OGString &s);
OGString latexEscapeIndexChars(const OGString &s);
OGString latexEscapePDFString(const OGString &s);
OGString latexFilterURL(const OGString &s);


#endif
