/*
This file is part of Msc-generator.
Copyright (C) 2008-2024 Zoltan Turanyi
Distributed under GNU Affero General Public License.

Msc-generator is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Msc-generator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with Msc-generator.  If not, see <http://www.gnu.org/licenses/>.
*/

/** @defgroup libs The engines of Msc-generator. */


/** @defgroup libcgencommon The base engine of Msc-generator.
  @ingroup libs

Originally, Msc-generator supported only signalling charts. When support for graphs
were added, the engine was split into a generic and a chart specific part.
Libcgencommon is the common part - but you can still see some chart specific
remnants, unfortunately.

# Concepts

- *Language* is synonymous to 'chart type'

- *Elements* are all visual elements in a chart that can be tracked (when clicked
on them in the GUI they briefly flash). In signalling charts all entity headings,
arrows, boxes, notes, etc. are elements. In graphs, all nodes, edges and visible
(cluster) subgraphs. They are all descendants of class Element.

- *Attributes* are a concept expected to be used in all languages, thus the base
engine has wide support for them. We have class Attribute, which is holds the name
and value of the attribute and can be translated to processed versions such as
LineAttr, FillAttr, etc. The engine has support for fill, line, text, arrowhead,
numbering and shadow attributes, but you are free to use any other.
Text attributes support parsing and interpretation of text formatting escapes.

- *Color* definitions can be changed in most languages. See class ColorSet.

- *Shapes* provide a means for the user to define Bezier-curve delimited arbitrary
shapes. This is used in signalling charts for entity headings, but can be utilized
for free drawing or could be used in graphs as well, to draw nodes. Shapes can be
saved in embedded objects in on Windows. They can also be part of design libraries.

-  *Styles* contain attribute values. All languages of Msc-generator is expected
to adhere to the attribute concept and style introduced originally into graphviz.
Consequently all languages benefit from styles, so the base engine contains support
for them (including coloring and hints, see later). Each language can define, how
what attributes it supports and how styles are constructed. All styles are supposed
to be a descendant of class Style. Use SimpleStyle, if you need only simple line,
fill, shadow and text attributes. Styles support a copy-on-write mechanism, since
it is expected that many elements will share the same style in a large chart.

- *Context* is the state of styles and color definitions and a few other parameters
in-between curly brackets during parsing. Other parameters include the value of
chart options (like 'pedantic'), see MscContext for many examples.
A new Context is placed on a stack each time
a new curly brace opens and popped when closed. This way changes to styles and
other parameters will only impact the section of chart description between the
curly braces they were made. Contexts are all descendants of class Context, but
you are more likely to use the template class ContextBase (a descendant of Context,
I know, bad naming), which takes one parameter, the Style class to use. Each Context
is supposed to provide a default set of style values, which is the plain design via
the Context::Plain() function.

- *Designs* are indeed contexts, that is, colors, styles and other parameters, but
not for the temporary use during parsing, but as storages of visual design information.
Designs can be applied to a chart to change appearance. Some designs (usually
defined via the 'defdesign' command) can be placed in a design library, which is
really a text in the language of the chart containing only design definitions.

- *Chart* each chart type has a central class (descendant of class Chart), which
contains all data of a compiled chart and the necessary members to manipulate it
(drawing, GUI actions, etc.) You are likely to use the template class ChartBase
(a descendant of Chart, sorry), which takes four template parameters in a decorator
pattern. The first one is the type of Context to use, which needs to be a descendant
of class Context. The second is the class that tracks progress of compilation, which
needs to be a descendant of class ProgressBase (which does not do anything and can be
used if you do not implement progress tracking). The third holds information on
references inside the chart (see the '\ r' text escape) and defaults to RefNameData,
which holds the textual representation of the number of the element and the position
of its 'refname' attribute (or similar). Such references are then put into a map,
where the name of the element (a string, the value of the 'refname' attribute) is
mapped to this class. The fourth one must be a descendant of class PageBreakData
and holds information on each page of the chart. If overwhelmed, just specify the
first attribute.

- *Csh* While the chart class governs compilation and drawing, there is a second
way to parse a chart text file and this is for color syntax highlighting. Such
parses follow the same language definition, but each action is ifdef'ed into two
parts, one for regular parsing (filling a Chart descendant) and csh parsing
(filling a Csh descendant). Thereby two parsers are generated from a single yacc
file. All coloring and hint information is collected into a descendant of class Csh.
Coloring info is added via the Csh::AddCSH_XXX functions, whereas for hints we first
check if the cursor is in the grammar construct we parse via the Csh::CheckHintsXXX
functions and if yes, we can add potential auto-completion and hint values via
Csh::AddToHints(). Csh classes are only needed in the GUI. You can omit doing them
if your language does not support coloring, hints, auto-indent, etc.
Since Csh classes collect keyword and other information at construction via
Csh::FillXXX functions, they are expensive to construct. Thus in the GUI there is only
one copy of them, which is re-used at each Csh run. The Csh::BeforeYaccParsing()
function is called to clean up the result of a previous parse.

- *Contour* is a library within the base engine to support manipulation of geometric
shapes. Its definitions are in namespace contour, with key elements exported.
Its two main classes are class Contour, which describes an enclosed 2D area
(with potential disjoint parts and holes). You can take the union, intersection, etc.
of contours via the +-, etc. operators. You can also use Expand to create an
expanded or shrunken version of the contour, where the new curve is at a fixed distance
from the old one (so it is not just scaling by a factor). Contours can also be
drawn to a cairo context even using double or triple lines (via LineAttr) and fill
(using FillAttr) and with a shadow (using ShadowAttr), see class Canvas.
Elements hold their covered area using this class, which is used both for tracking
and can also be used to manipulate layout.
The other class is Path, which contains a not necessarily open and not necessarily
contiguous curve. It has also basic operations for drawing, etc.
Finally class Area holds a Contour with a reference to an Element. This is used
during tracking by the GUI.
*/


/** @defgroup libcgencommon_files The files of the mscgen library.
* @ingroup libcgencommon

 The files are organized in the following logical hierarchy.
- `version`, `utf8tools`, `error` and `cgen_color` Provide basic utilities for
line numbering, errors, UTF8 and color.
- `cgen_attribute`, `cgen_arrowhead`, `stringparse` and `numbering` provide element
attribute handling for lines, fills, shadows, arrows, text formatting and
numbering.
- 'cgen_shapes' contain tools to parse and draw Bezier-based user-defined shapes.
- `style` collects attributes to a common Style class and add ContextBase and Design.
- `canvas` contains Canvas, a helper class to encapsulate a cairo
surface and context. We add logic for pages and fallback operations here
(e.g., for output types (like WMF) that do not support certain operations,
like dashed lines.)
- `element` defines the class that represent the elements of the chart.
- `chartbase` defines the root classes for charts, including Chart and
the template ChartBase, and some bases for supporting classes such as
ProgressBase and RefNameData.
- `csh` implements Color Syntax Highlighting
and hinting (auto-completion) functionality.
- `cgencommon` defines languages in general and a collection for them,
while `commandline` contains all the logic for command-line operation.

@file cgencommon.cpp The implementation of LanguageCollection
@ingroup libcgencommon_files  */

#include "cgencommon.h"

bool LanguageCollection::AddLanguage(Chart::ChartFactoryFunction f, Csh::FileListProc proc)
{
    std::unique_ptr<Chart> chart = f(nullptr, nullptr, this); //we do not provide a file read function to this temp instance.
    if (chart==nullptr)
        return false;
    const std::string name = chart->GetLanguageExtensions().front();
    const bool ret = GetLanguage(name)==nullptr;
    if (ret) {
        languages.emplace_back(chart->GetLanguageExtensions(), chart->GetLanguageDescription(),
                               chart->GetLanguageEntityName(),
                               chart->GetLanguageDefaultText(), chart->CshFactory(proc, this),
                               chart->GetLanguageHasAutoheading(), chart->GetLanguageHasElementControls(), f, this);
        languages.back().pCsh->params = cshParams; //a shared_pt
        auto libs = chart->RegisterLibraries();
        AddLibraries(std::move(libs));
    }
    return ret;
}

std::tuple<std::string, std::string, std::string>
ReadIncludeFileInDesigns(std::string_view, void*, std::string_view) {
    return{"Cannot read include files in design libraries.", "", ""};
}

/* Parse the designs libraries before starting a GUI.
 * If the chart texts given has visual elements, we just ignore those silently.
 * @param [in] design_files A pair of 'design lib text' + 'design lib filename' tuples.
 *        May contain a mix of all languages. Files that have extensions not matching the
 *        any of the languages are silently ignored.
 * @returns the errors we have encountered.*/
MscError LanguageCollection::CompileDesignLibs(std::vector<std::pair<std::string, std::string>> &&design_files) {
    MscError errors;
    for (auto &l: languages) {
        std::vector<std::pair<std::string_view, std::string>> language_designs;
        for (auto &[fn, text] : design_files)
            if (auto dot_pos = fn.find_last_of('.'); dot_pos!=fn.npos && l.HasExtension(fn.substr(dot_pos+1)))
                language_designs.emplace_back(fn, std::move(text));
        if (language_designs.empty()) continue;
        std::unique_ptr<Chart> chart = l.create_chart(ReadIncludeFileInDesigns, this);
        chart->Error.Files = errors.Files;
        chart->SetPedantic(l.pedantic); //whatever has been set (probably the default).
        chart->GetProgress()->StartParse();
        for (auto [fn, text] : language_designs)
            chart->ParseText(text, fn);
        l.pedantic = chart->GetPedantic();
        l.designs = chart->ExportDesigns();
        l.shapes = std::move(chart->Shapes);
        errors.Files = chart->Error.Files;
        l.designlib_errors = std::move(chart->Error);
        errors += l.designlib_errors;
        //create pre-parsed data for csh
        for (auto &[fn, text] : language_designs)
            l.pCsh->ParseDesignText(std::move(text)); //for signalling: This preserves mscgen_compat flag, but uses autodetect. By this we have read the registry and have set the mscgen_compat value, so we need to maintain it.
        //Now clean it up. Keep only FullDesigns, PartialDesigns,
        //the outermost context and forbidden styles
        l.pCsh->CleanupAfterDesignlib();
    }
    return errors;
}
