/*
    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 xxxchart.h The declaration for the FlowChart class.
* @ingroup libxxx_files */

#ifndef Flow_GRAPHS_H
#define Flow_GRAPHS_H

#include "cgencommon.h"
#include "flowstyle.h"
#include "steps.h"

/** This is the namespace containing flowchart elements, except parsing.*/
namespace flow {

class FlowElement;

/** The chart class.*/
class FlowChart : public ChartBase<FlowContext>
{
public:
    /** @name Language attributes
    * @{ */
    std::string GetLanguageDescription() const override { return "Flow Chart"; } ///<Returns the human-readable (UTF-8) short description
    std::vector<std::string> GetLanguageExtensions() const override { return{"flow"}; } ///<Returns a set of extensions in order of preference
    std::string GetLanguageEntityName() const override { return "node"; }
    std::string GetLanguageDefaultText() const override; ///<Returns the default text of the chart in UTF-8
    bool GetLanguageHasAutoheading() const override { return false; } ///<True if the chart has automatic headings
    bool GetLanguageHasElementControls() const override { return false; } ///<True if the elements of the chart support GUI controls
    std::unique_ptr<Csh> CshFactory(Csh::FileListProc proc, const LanguageCollection* languages) const override;
    std::map<std::string, std::string> RegisterLibraries() const override { return {}; };
    /** @} */
public:
    const double defaultGap = 20;
    const double arrowGap = 20;
    const EDir sdir = EDir::RIGHT; //the series direction
    const EDir ndir = EDir::DOWN;  //the nodes direction within a series
    EDir ConvertDir(ELogicalDir ld) const { return flow::ConvertDir(ld, sdir, ndir); }
    FElementList steps;
    std::vector<StepList> series;

    FlowChart(FileReadProcedure *p, void *param, const LanguageCollection* languages);
    ~FlowChart() override = default;

    std::unique_ptr<FlowElement> PopContext();    ///<Closes a scope

    static std::unique_ptr<Chart> Factory(FileReadProcedure *p, void *param, const LanguageCollection* languages)
        { return std::make_unique<FlowChart>(p, param, languages); }

    bool AddCommandLineArg(const std::string & arg) override;
    void AddCommandLineOption(const Attribute & a) override;
    bool DeserializeGUIState(std::string_view) override;
    std::string SerializeGUIState() const override;
    bool ControlClicked(Element *, EGUIControlType) override;
    bool ApplyForcedDesign(const string & name) override;
    bool GetPedantic() const noexcept override { return forced_pedantic.value_or(true); }
    void SetPedantic(bool pedantic) noexcept override { Chart::SetPedantic(pedantic); }

    bool AddChartOption(const Attribute &a);
    FlowElement *AddAttribute(const Attribute&);
    bool AddDesignAttribute(const Attribute&);
    void AddElements(FElementList *l) { if (l) { steps.Append(l); delete l; } }

    void ParseText(std::string_view input, const FileLineCol& first_char) override;
    void CompleteParse(bool autoPaginate = false,
                       bool addHeading = true, XY pageSize = XY(0, 0),
                       bool fitWidth = true, bool collectLinkInfo = false) override;
    size_t NewStepList() { series.emplace_back(); return series.back().id = series.size()-1; }
    void BestOrdering();
    size_t ConvertToSeries(FElementList &list, bool allocate_new=true);
    void ConvertToSeries();
    NodeRef FindRefNameInSeries(const std::string &refname) const;
    void DeleteItemFromSeries(NodeRef t, NodeRef replaceto);
    void DeleteColumnFromSeries(int col);

    void Layout();
    XY GetSidePoint(const NodeRef &n, EDir dir) const { return series[n.col].nodes[n.element].step->GetSidePoint(dir); }
    XY GetKneePoint(const KneePos &k) const;
    void ExtendTotal(const Block &b) { total += b; }

    void PostPosProcess();
    void CollectIsMapElements(Canvas & canvas) override;
    void RegisterAllLabels() override;
    void Draw(Canvas & canvas, bool pageBreaks, unsigned page) override;
    void SetToEmpty() override;
};

}; //namespace

using flow::FlowChart;

#endif