/*
    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 mscarrow.h Msc Arrowhead classes.
* @ingroup libmscgen_files */


#ifndef MSCARROW_H
#define MSCARROW_H
#include "cgen_arrowhead.h"
#include "canvas.h"

namespace msc {

/** Signalling chart specific interface to class FullArrowHeads. */
class MscArrowHeads : public FullArrowHeads
{
public:
    using FullArrowHeads::FullArrowHeads;

    /** Transform the space for angled arrows.
     * Useful, so that we can draw angled arrows as if they were horizontal.
     * Transform space such that if we draw a horizontal arrow, it will be of
     * angle="radian" on the canvas.
     * In the transformed space (sx,y) will be the same, the space will be rotated by "radian".
     * @param [in] degree The angle to rotate clockwise (with y growing downwards.
     *                    Assumed to be between -45..+45 degrees.
     * @param [in] sx The x coordinate of the center of the rotation.
     * @param [in] y The y coordinate of the center of the rotation.
     * @param canvas The canvas to rotate.
     *
     * Saves cairo context, always call MscArrowHeads::UntransformCanvas() to kill it,
     * when done.*/
    static void TransformCanvasForAngle(double degree, Canvas &canvas, double sx, double y)
        { canvas.Transform_Rotate(XY(sx, y), degree*M_PI/180.); }
    /** Rotates back the canvas rotated by MscArrowHeads::TransformCanvasForAngle()*/
    static void UnTransformCanvas(Canvas& canvas)
        { canvas.UnTransform(); }

    /** @name Functions for line arrowheads
     * @{ */
    double getHeight(bool bidir, EArrowEnd which, const LineAttr &mainline_before, const LineAttr &mainline_after) const;
    DoublePair getWidths(bool forward, bool bidir, EArrowEnd which, const LineAttr &mainline_left, const LineAttr &mainline_right) const;
    Contour EntityLineCover(XY xy, bool /*forward*/, bool bidir, EArrowEnd which, const LineAttr &mainline_left, const LineAttr &mainline_right) const;
    Contour ClipForLine(XY xy, double act_size, bool forward, bool bidir, EArrowEnd which,
                        const LineAttr &mainline_left, const LineAttr &mainline_right) const;
    Contour Cover(XY xy, double act_size, bool forward, bool bidir, EArrowEnd which,
                  const LineAttr &mainline_left, const LineAttr &mainline_right) const;
    //This actually draws an arrowhead
    void Draw(Canvas&, XY xy, double act_size, bool forward, bool bidir, EArrowEnd which,
              const LineAttr &mainline_left, const LineAttr &mainline_right) const;
    /** @} */

    /** @name Functions for block arrowheads
     * @{ */
    DoublePair getBigWidthsForSpace(bool forward, bool bidir, EArrowEnd which,
                                    double body_height, double act_size, const LineAttr &ltype) const;
    double getBigMargin(Contour text_cover, double sy, double dy, bool margin_side_is_left,
                        bool forward, bool bidir, EArrowEnd which, const LineAttr &ltype) const;
    double bigYExtent(double budy_height, bool forward, bool bidir, const LineAttr *line, const std::vector<LineAttr> *lines=nullptr) const;
    Contour BigContourOneEntity(double x, double act_size, double sy, double dy,
                                bool forward, bool bidir, EArrowEnd which, bool left,
                                const LineAttr &ltype, double *body_margin=nullptr) const;
    Contour BigContour(const std::vector<double> &xPos, const std::vector<double> &act_size,
                       double sy, double dy, bool forward, bool bidir,
                       const LineAttr *line, const std::vector<LineAttr> *lines,
                       std::vector<Contour> &result) const;
    Contour BigHeadContour(const std::vector<double> &xPos, const std::vector<double> &act_size,
                           double sy, double dy, bool forward, bool bidir,
                           const LineAttr *line, const std::vector<LineAttr> *lines, double compressGap) const;
    void BigDrawFromContour(std::vector<Contour> &result, const LineAttr *line, const std::vector<LineAttr> *lines,
                 const FillAttr &fill, const ShadowAttr &shadow, Canvas &canvas,
                 double angle_radian=0) const;
    void BigDrawEmptyMid(const std::vector<double> &xPos, double sy, double dy,
                         Canvas &canvas, const LineAttr &line, const Contour *clip=nullptr) const;
    void BigCalculateAndDraw(const std::vector<double> &xPos, const std::vector<double> &act_size,
                             double sy, double dy, bool forward, bool bidir,
                             const LineAttr *line, const std::vector<LineAttr> *lines,
                             const FillAttr &fill, const ShadowAttr &shadow, Canvas &canvas,
                             const Contour *clip=nullptr, double angle_radian=0) const;
    /** @} */
};

}

#endif //MSCARROW_H
