/*
    This file is part of KCachegrind.

    SPDX-FileCopyrightText: 2002-2016 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>

    SPDX-License-Identifier: GPL-2.0-only
*/

#ifndef COST_H
#define COST_H

#include <QString>

#include "subcost.h"
#include "context.h"
#include "utils.h"

class EventType;
class EventTypeSet;
class EventTypeMapping;
class TracePart;
class TraceData;

/**
 * Base class for cost items.
 */
class CostItem
{
public:

    explicit CostItem(ProfileContext*);
    virtual ~CostItem();

    ProfileContext* context() const { return _context; }
    ProfileContext::Type type() const { return context()->type(); }

    /**
     * Returns dynamic name info (without type)
     */
    virtual QString name() const;

    /**
     * Similar to name, but prettyfied = more descriptive to humans
     */
    virtual QString prettyName() const;

    /**
     * A HTMLified version of name, can return empty string
     */
    virtual QString formattedName() const;

    /**
     * Returns text of all cost metrics
     */
    virtual QString costString(EventTypeSet*);

    /**
     * Returns type name + dynamic name
     */
    QString fullName() const;

    /**
     * Returns full name + cost text
     */
    QString toString();

    /**
     * Set all cost counters to zero
     */
    virtual void clear();

    /** Invalidate the cost attributes.
     * An invalidated object needs to be recalculated when a cost
     * attribute is requested (e.g. by subCost()).
     * Has to be overwritten by subclasses when the cost influences costs of
     * other cost items. If only one item depends on the cost of this item,
     * it can by set with setDependent() without a need for overwriting.
     */
    virtual void invalidate();

    /**
     * Sets a dependent to be invalidated when this cost is invalidated.
     * Call this function directly after the constructor.
     */
    void setDependent(CostItem* d) { _dep = d; }

    CostItem* dependent() { return _dep; }

    /**
     * If this item is from a single profile data file, position
     * points to a TracePart, otherwise to a TraceData object.
     */
    void setPosition(CostItem* p) { _position = p; }

    /**
     * Redefine the context after construction
     */
    void setContext(ProfileContext* context) { _context = context; }

    // getters for specific positions, to be overwritten
    virtual TracePart* part();
    virtual const TracePart* part() const;
    virtual TraceData* data();
    virtual const TraceData* data() const;

protected:
    /** Updates cost attributes.
     * This has to be called by subclasses that access cost attributes
     * directly
     */
    virtual void update();

    ProfileContext* _context;
    bool _dirty;

    CostItem* _position;
    CostItem* _dep;
};


// The maximal number of subcosts in a ProfileCostArray and
// event types in a EventSet. Does not really matter for memory
// consumption as cost for a ProfileCostArray is dynamically
// allocated depending on used number of event types, and there
// will be only a low number of objects for EventType{,Set,Mapping}.
#define MaxRealIndexValue 200

/**
 * An array of basic cost metrics for a trace item.
 *
 * The semantic of specific indexes is stored in the
 * EventTypeSet of the TraceData object holding this ProfileCostArray.
 */
class ProfileCostArray: public CostItem
{
    friend class EventType;
public:
    /**
     */
    static const int MaxRealIndex;
    static const int InvalidIndex;


    explicit ProfileCostArray(ProfileContext*);
    ProfileCostArray();
    ~ProfileCostArray() override;

    QString costString(EventTypeSet*) override;

    void clear() override;

    // reserve space for cost
    void reserve(int);

    // set costs according to the mapping order of event types
    void set(EventTypeMapping*, const char*);
    void set(EventTypeMapping*, FixString&);
    // add costs according to the mapping order of event types
    void addCost(EventTypeMapping*, const char*);
    void addCost(EventTypeMapping*, FixString&);
    // add the cost of another item
    void addCost(ProfileCostArray* item);
    void addCost(int index, SubCost value);

    // maximal cost
    void maxCost(EventTypeMapping*, FixString&);
    void maxCost(ProfileCostArray* item);
    void maxCost(int index, SubCost value);
    ProfileCostArray diff(ProfileCostArray* item);

    void invalidate() override;

    /** Returns a sub cost. This automatically triggers
     * a call to update() if needed.
     */
    SubCost subCost(EventType*);

    /** Returns a cost attribute converted to a string
     * (with space after every 3 digits)
     */
    QString prettySubCost(EventType*);

    QString prettySubCostPerCall(EventType* t, uint64 calls);

protected:
    void update() override;

private:
    // Only used by friend class EventType: return subcost by index
    SubCost subCost(int);

    SubCost* _cost;
    int _count; // only _count first indexes of _cost are used
    int _allocCount; // number of allocated subcost entries

    // cache last virtual subcost for faster access
    SubCost _cachedCost;
    EventType* _cachedType;
};


#endif // COST_H
