/** *************************************************************************
                          deepskyitem.h  -  K Desktop Planetarium
                             -------------------
    begin                : 18/06/2016
    copyright            : (C) 2016 by Artem Fedoskin
    email                : afedoskin3@gmail.com
 ***************************************************************************/
/** *************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#pragma once

#include "skyitem.h"
#include "skyopacitynode.h"
#include "deepskycomponent.h"
#include "skynodes/trixelnode.h"

class DeepSkyComponent;
class SkyMesh;
class StarBlockFactory;
class MeshIterator;

/**
 * @short This class represents DSOs from particular catalog. To create a node, first create a DSOTrixelNode,
 * (if a node of this trixelID is not a child of m_trixels yet), append it to m_trixels and then append
 * DeepSkyNode to DSOTrixelNode
 */
class DSOIndexNode : public SkyOpacityNode
{
  public:
    DSOIndexNode(DeepSkyIndex *index, LabelsItem::label_t labelType, QString colorString);

    /** @short hides the catalog nodes and their labels */
    virtual void hide();

    /** @short shows the catalog nodes and their labels */
    virtual void show();

    DeepSkyIndex *m_index { nullptr };
    QSGNode *m_trixels { nullptr };
    /** @short m_labelType holds label type of this catalog */
    LabelsItem::label_t m_labelType;
    /** @short schemeColor holds the color, with which nodes of this catalog should be drawn */
    QString schemeColor;
};

/**
 * @short The DSOTrixelNode class represents trixel. Symbols should be appended to m_symbols, labels to
 * m_labels and DeepSkyNodes directly to DSOTrixelNode
 */
class DSOTrixelNode : public TrixelNode
{
  public:
    explicit DSOTrixelNode(Trixel trixelID);

    virtual void deleteAllChildNodes();

    TrixelNode *m_labels { nullptr };
    QSGNode *m_symbols { nullptr };
};

/**
 * @class DeepSkyItem
 *
 * @short Class that handles representation of Deep Sky Objects.
 *
 * @author Artem Fedoskin
 * @version 1.0
 */
class DeepSkyItem : public SkyItem
{
  public:
    /**
     * @short Constructor. Instantiates DSOIndexNodes for catalogs
     * @param dsoComp pointer to DeepSkyComponent that handles data
     * @param rootNode parent RootNode that instantiated this object
     */
    DeepSkyItem(DeepSkyComponent *dsoComp, RootNode *rootNode);

    /** @short Call update on all DSOIndexNodes (catalogs) */
    virtual void update();

    /**
     * @short update all nodes needed to represent DSO in the given DSOIndexNode
     * In this function we perform some tricks to reduce memory consumption:
     * 1. Each TrixelNode has hideCount() function that returns the number of updates, during which this TrixelNode
     * was hidden. Whenever TrixelNode becomes visible this counter is set to 0 and is not being incremented.
     * 2. Based on the zoom level we calculate the limit for hideCount. If hideCount() of particular TrixelNode is
     * larger than the limit, we delete all nodes of this TrixelNode.
     * 3. If DSOTrixelNode is visible, we iterate over its DeepSkyObjects and DeepSkyNodes. If hideCount of DeepSkyNode
     * is larger than the limit we delete it. If DeepSkyObject is visible but no DeepSkyNode to represent this object
     * is created, we instantiate a new one.
     * @param node - DSOIndexNode(catalog) that should be updated
     * @param drawObject - true if objects from this catalog should be drawn, false otherwise
     * @param region - MeshIterator that should be used to iterate over visible trixels
     * @param drawImage - true if images for objects should be drawn, false otherwise
     */
    void updateDeepSkyNode(DSOIndexNode *node, bool drawObject, MeshIterator *region, bool drawImage = false);

  private:
    DeepSkyComponent *m_dsoComp { nullptr };
    SkyMesh *m_skyMesh { nullptr };

    DSOIndexNode *m_Messier { nullptr };
    DSOIndexNode *m_NGC { nullptr };
    DSOIndexNode *m_IC { nullptr };
    DSOIndexNode *m_other { nullptr };
};
