                /*
    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/>.
*/

/** @file mscstyle.h The declaration of styles (MscStyle) and contexts (ContextBase).
* @ingroup libmscgen_files */

#ifndef MSCSTYLE_H
#define MSCSTYLE_H

#include "style.h"
#include "mscattribute.h"
#include "mscarrow.h"

namespace msc {


/** The style used by signalling chart elements.
 * Adds all chart specific attributes, like vline/vfill, aline/atext,
 * solid, vspacing, indicatior, makeroom, side and note. */
class MscStyle : public SimpleStyleWithArrow<MscArrowHeads>
{
protected:
    friend class MscContext;
    MscStyle(EStyleType tt, EColorMeaning cm, EArcArrowType a,
        bool alt, bool t, bool l, bool f, bool s, bool vl,
        bool so, bool nu, bool co, ESideType si, bool i, bool vf, bool mr, bool n,
        bool lo, bool lsym, bool shp, bool tag);
public:
    LineAttr vline;    ///<The vline attributes
    FillAttr vfill;    ///<The vfill attributes
    LineAttr aline;    ///<The aline attibutes influencing arrows starting from an entity.
    StringFormat atext;///<The atext attibutes influencing arrows starting from an entity.
    OptAttr<unsigned char> solid;    ///<The value of the 'solid' attribute (for pipes).
    OptAttr<ESide>         side;     ///<The value of the 'side' attribute (for pipes, verticals or notes).
    OptAttr<double>        vspacing; ///<The value of the 'compress' and 'vspacing' attribute. compress=yes is indicated via seting second to DBL_MIN
    OptAttr<bool>          indicator;///<The value of the 'indicator' attribute.
    OptAttr<bool>          makeroom; ///<The value of the 'makeroom' attribute (for verticals and notes).
    NoteAttr note;         ///<The note attributes

    LineAttr lost_line;    ///<The delta compared to "line" for lost part of the arrow
    AttrCoW<TwoArrowHeads> lost_arrow;  ///<The delta compared to "arrow" for the lost part of the arrow
    StringFormat lost_text;///<The delta for the lost part of the text
    LineAttr  lsym_line;   ///<The line of the loss symbol
    OptAttr<EArrowSize> lsym_size; ///<The size of the loss symbol
    LineAttr tag_line;     ///<The tag.line attributes for boxes
    FillAttr tag_fill;     ///<The tag.fill attributes for boxes
    StringFormat tag_text; ///<The tag.text attributes for boxes

    bool f_vline;      ///<True if the style contains vline attributes.
    bool f_vfill;      ///<True if the style contains vfill attributes.
    bool f_solid;      ///<True if the style contains the 'solid' attributes.
    bool f_vspacing;   ///<True if the style contains the 'compress'/'vspacing' attributes.
    ESideType f_side;  ///<Shows if the style contains the 'side' attributes and what values are acceptable
    bool f_indicator;  ///<True if the style contains the 'indicator' attributes.
    bool f_makeroom;   ///<True if the style contains the 'makeroom' attributes.
    bool f_note;       ///<True if the style contains note attributes.
    bool f_alt;        ///<True if the style has aline and atext
    bool f_lost;       ///<Governs if the style has lost parts.
    bool f_lsym;       ///<Governs if the style has loss symbol
    bool f_tag;        ///<Governs if the style has tag.* attributes

    MscStyle(EStyleType tt = EStyleType::STYLE, EColorMeaning cm = EColorMeaning::NOHOW); //Has all the components, but is empty
    MscStyle(const MscStyle&) = default;
    MscStyle(MscStyle&&) = default;
    MscStyle &operator=(const MscStyle&) = default;
    MscStyle &operator=(MscStyle&&) = default;
    void Empty() override;
    bool IsEmpty() const noexcept override;
    void MakeCompleteButText() override;
    Style &operator +=(const Style &toadd) override;
    bool AddAttribute(const Attribute &a, Chart *chart) override;
    bool DoIAcceptUnqualifiedColorAttr() const override;
    void AttributeNames(Csh &csh) const override;
    bool AttributeValues(std::string_view attr, Csh &csh) const override;
};

/** A copy-on-write version of MscStyle. */
typedef StyleCoW<MscStyle> MscStyleCoW;

/** Enumerates procedure parameter types.*/
enum class EMscProcParamType
{
    ANY = 0,    ///<These parameters may hold anything
    ATTR_VALUE, ///<These may hold attribute values
    ENTITY,     ///<These parameters may hold entity names
    MARKER,     ///<These parameters may hold marker names
};


/** The context for Mscs.
 * In addition to styles, colors, chart options  (e.g., 'compress', 'numbering',
 * 'indicator', 'slant_angle' and 'hscale'. Other chart options are not really
 * options, but rather generate chart elements, such as background.).
 * It also includes the current comment line and fill style, the default font
 * and current numbering style.
*/
class MscContext : public ContextBase<MscStyle>
{
public:
    OptAttr<double> hscale;      ///<The 'hscale' chart option.
    OptAttr<bool>   numbering;   ///<The 'numbering' chart option.
    OptAttr<double> vspacing;    ///<The 'compress'/'vspacing' chart option.
    OptAttr<bool>   indicator;   ///<The 'indicator' chart option.
    OptAttr<double> slant_angle; ///<The 'slant_angle' chart option.
    OptAttr<double> slant_depth; ///<The 'arcgradient' chart option.
    OptAttr<bool>   auto_heading;///<The 'auto_heading' chart option.
    LineAttr defCommentLine;     ///<The style of the comment line
    FillAttr defCommentFill;     ///<The fill of the comment area
    FillAttr defBackground;      ///<The background
    /** This constructor is used to create an empty context or one set to plain.
     * Used an initializing the first context at parse, when starting to record
     * a design, storing a procedure or moving a newly defined design to the design
     * store.
     * @param [in] f If true, the context contains a value for all styles and attributes (Full)
     * @param [in] p Tells us what components to observe and how to behave during parsing.
     * @param [in] t Tells us with what content to create the context. It should not be 'COPY
     * @param [in] l The first character of the context in the input file.*/
    MscContext(bool f, EContextParse p, EContextCreate t, const FileLineCol &l) :
        ContextBase<MscStyle>(f, p, EContextCreate::CLEAR, l)
    { switch (t) {
        default: _ASSERT(0); FALLTHROUGH;
        case EContextCreate::PLAIN: Plain(); break;
        case EContextCreate::EMPTY: Empty(); break;
        case EContextCreate::CLEAR: defCommentFill.Empty(); defCommentLine.Empty(); defBackground.Empty();
            hscale.reset(); numbering.reset(); vspacing.reset(); indicator.reset(); slant_angle.reset(); slant_depth.reset(); auto_heading.reset();
    }}
    /** This constructor is used when a context needs to be duplicated due to
     * the opening of a new scope. You can change the parse mode, e.g., when
     * parsing the not-selected branch of an ifthenelse.*/
    MscContext(const MscContext &o, EContextParse p, const FileLineCol &l) :
        ContextBase<MscStyle>(o, p, l), hscale(o.hscale), numbering(o.numbering), vspacing(o.vspacing),
        indicator(o.indicator), slant_angle(o.slant_angle), slant_depth(o.slant_depth), auto_heading(o.auto_heading),
        defCommentLine(o.defCommentLine), defCommentFill(o.defCommentFill), defBackground(o.defBackground) {}
    void Empty() override; ///<Make the context empty
    void Plain() override; ///<Set the context to the 'plain' design
    void MscgenCompat(); ///<Set the context to the 'mscgen' incremental design - used for mscgen compatibility
    /** Semi copy operator: copy only user-defined context content. If o is full, we overwrite us, else just merge.*/
    void ApplyContextContent(const MscContext &o);
    /** Semi move operator: move only user-defined context content. If o is full, we overwrite us, else just merge.*/
    void ApplyContextContent(MscContext &&o);
};

} //namespace

#endif //MSCSTYLE_H