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

#ifndef MSC_ELEMENT_H
#define MSC_ELEMENT_H

#include "element.h"
#include "canvas.h"
#include "mscstyle.h" 

namespace msc {

/** A list of drawing passes.*/
enum class EMscDrawPass
{
    INVALID = 0,         ///<The invalid value
    BEFORE_BACKGROUND,   ///<The first drawing pass: before the background (e.g., for transparent bkg)
    BEFORE_ENTITY_LINES, ///<The first drawing pass: before the entity lines are drawn
    AFTER_ENTITY_LINES,  ///<A drawing pass just after the entity lines are drawn
    DEFAULT,             ///<The default drawing pass, when most elements are drawn
    AFTER_DEFAULT,       ///<A drawing pass after the default pass
    NOTE,                ///<A drawing pass to draw floating notes
    AFTER_NOTE           ///<The last drawing pass: after drawing floating notes.
};

class MscChart;
class Note;
class EntityDistanceMap;
class DistanceRequirements;

/** Indicates that the note shall be deleted */
#define DELETE_NOTE ((MscElement * )1)
/** A list of Note object pointers, not owning the notes. */
typedef NPtrList<Note> CommandNoteList;


/** The base class for all signalling chart elements.
 * Supports side comments, indicators, draw pass, and the basic flow of
 * signalling chart construction.*/
class MscElement : public Element
{
public:
    MscChart *const    chart;           ///<The msc chart this element belongs to.  
protected:
    mutable double     yPos;            ///<The y position of this element.
    CommandNoteList    comments;        ///<A pointer to comments attached to this element. Comments exist independently and will not be deleted on the deletion of this element.
    double             comment_height;  ///<Total height of the comments attached (max of the two sides)
    const MscStyleCoW  indicator_style; ///<The style to be used if we need to replace this with an indicator
    /** Returns the size of an indicator that is supposed to replace us considering `indicator_style`*/
    XY GetIndicatorSize() const { return Element::GetIndicatorSize(indicator_style.read().line, indicator_style.read().fill, indicator_style.read().shadow); }

public:
    EMscDrawPass    draw_pass; ///<Gives the Z-order position of this arc

    /** Default constructor. */
    explicit MscElement(MscChart *m);
    /** Copy constructor, but does not copy comments*/
    MscElement(const MscElement&);
    virtual ~MscElement();

    virtual bool AddAttribute(const Attribute &a);
    static void AttributeNames(Csh &csh);
    static bool AttributeValues(std::string_view attr, Csh &csh);
    void ShiftBy(double y) override;
    virtual void AttachComment(Note *cn);
    void CombineComments(MscElement *); //move comments to us

    /** Lay out the comments made to this elements. The comments' cover is returned in 'cover'.*/
    void LayoutComments(Canvas &canvas, AreaList *cover) { double l = 0, r = 0; LayoutCommentsHelper(canvas, cover, l, r); }
    virtual void LayoutCommentsHelper(Canvas &canvas, AreaList *cover, double &l, double &r);
    virtual void RegisterCover(EMscDrawPass pass) const;

    Block GetIndicatorCover(const XY& pos) const { return Element::GetIndicatorCover(pos, indicator_style.read().line, indicator_style.read().fill, indicator_style.read().shadow); }
    void DrawIndicator(const XY& pos, Canvas* canvas) const { Element::DrawIndicator(pos, canvas, indicator_style.read().line, indicator_style.read().fill, indicator_style.read().shadow); }
};

} //msc namespace


#endif