#pragma once

#include "object.h"
#include "junction.h"
#include <maps/wikimap/mapspro/services/editor/src/geom.h>
#include <maps/wikimap/mapspro/services/editor/src/common.h>
#include <maps/wikimap/mapspro/services/editor/src/views/fwd.h>

namespace maps {
namespace wiki {

class LinearElement : public GeoObject
{
public:
    using ViewType = views::LinearViewObject;

    template <class T> friend class Constructor;

    LinearElement(const TRevisionId& id, ObjectsCache& cache);

    //From GeoObject
    virtual void applyVisitor(ObjectVisitor& visitor) const;
    virtual void applyProcessor(ObjectProcessor& processor);
    virtual double geometryCompareTolerance() const { return STRONG_CALCULATION_TOLERANCE; }


    /**
    * Check if can merge with other
    * conflicting values, limits
    */
    bool canMerge(const LinearElement* other) const;

    /**
    * Check if both linear elements have
    * non conflicting directions at common point
    */
    bool isDirectionContinuous(const LinearElement* other) const;

    bool doesUseJunction(TOid junctionId) const;

    TOid junctionAId() const;
    TOid junctionBId() const;

    virtual const std::string& tablename() const
    { return ObjectsClassInfos::linearElementClassInfo.tableName; }

    TOid commonJunction(const LinearElement* other) const;

    //! Set junction specific attributes in segment
    void setJunctionSpecificAttributes(
        double offsetFromA, double offsetFromB, const Attributes& attrs,
        size_t partNum, size_t totalParts);

    TOid affectedBySplitId() const { return affectedBySplitId_; }
    void setAffectedBySplitId(TOid id) { affectedBySplitId_ = id;  }

    bool isPartOfPrimary() const { return partOfPrimary_; }
    void setPartOfPrimary() { partOfPrimary_ = true; }

protected:
    //!choose rigth value for junction specific argument
    void chooseJunctionSpecificValue(
        double distanceToA, double distanceToB,
        const AttrDefPtr& attrDef, const Attributes& attrs,
        const std::string& policyValue,
        size_t partNum, size_t totalParts);

    virtual ObjectPtr clone() const
    {
        return ObjectPtr(new LinearElement(*this));
    }

    friend class TopoStorage;
    friend class DeleteJunctionCallback;
    friend class TopoAddLinearElementCallback;
    friend class TopoMoveLinearElementCallback;

    void cloneNoGeom(LinearElement* other) const;

private:
    TOid affectedBySplitId_;
    bool partOfPrimary_;

};

} // namespace wiki
} // namespace maps
