//=========================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt for details.
//
//  This software is distributed WITHOUT ANY WARRANTY; without even
//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//  PURPOSE.  See the above copyright notice for more information.
//=========================================================================
#ifndef smtk_session_aeva_Session_h
#define smtk_session_aeva_Session_h

#include "smtk/common/UUID.h"
#include "smtk/model/EntityRef.h"
#include "smtk/model/Session.h"
#include "smtk/session/aeva/Exports.h"

#include "itkImage.h"
#include "itkImageIOBase.h"

#include "vtkSmartPointer.h"

class vtkDataObject;
class vtkDataSet;

namespace smtk
{
namespace model
{
class Entity;
}
namespace session
{
namespace aeva
{

class Resource;
class Session;
typedef smtk::shared_ptr<Session> SessionPtr;

/**\brief Implement a session from AEVA mesh files to SMTK.
  *
  */
class SMTKAEVASESSION_EXPORT Session : public smtk::model::Session
{
public:
  smtkTypeMacro(Session);
  smtkSuperclassMacro(smtk::model::Session);
  smtkSharedFromThisMacro(smtk::model::Session);
  smtkCreateMacro(smtk::model::Session);
  using SessionInfoBits = smtk::model::SessionInfoBits;

  using PixelType = unsigned char;
  static constexpr unsigned int Dimension = 3;
  using ImageType = itk::Image<PixelType, Dimension>;

  ~Session() override = default;

  SessionInfoBits allSupportedInformation() const override
  {
    return smtk::model::SESSION_EVERYTHING;
  }

  std::string defaultFileExtension(const smtk::model::Model&) const override;

  // TODO: Generalize to other image types:
  vtkSmartPointer<vtkDataObject> findStorage(const smtk::common::UUID& uid) const;
  void addStorage(const smtk::common::UUID& uid, vtkSmartPointer<vtkDataObject> const& storage);
  bool removeStorage(const smtk::common::UUID& uid);

  /// Given VTK data with global IDs on \a fieldType, find the set of primary-geometry components.
  bool primaryGeometries(const vtkSmartPointer<vtkDataObject>& data,
    int fieldType, // one of vtkDataObject::AttributeTypes
    std::set<smtk::model::Entity*>& primaries,
    smtk::resource::Resource* resource) const;

  /// Given a component as input, return its "source" primary geometric component.
  ///
  /// This may be the component itself or a separate component.
  /// It is also possible a side set spans multiple primary geometries, in
  /// which case this function will return a nullptr.
  bool primaryGeometries(const smtk::model::Entity* in,
    std::set<smtk::model::Entity*>& primaries) const;

  /// Given a component as input, return its "source" primary geometric component.
  ///
  /// This may be the component itself or a separate component.
  /// It is also possible a side set spans multiple primary geometries, in
  /// which case this function will return a nullptr.
  smtk::model::Entity* primaryGeometry(const smtk::model::Entity* in) const;

  /// Return the primary geometry that "owns" the given global cell/point ID.
  smtk::common::UUID primaryGeometryForCell(vtkIdType globalId) const;
  smtk::common::UUID primaryGeometryForPoint(vtkIdType globalId) const;

  static void offsetGlobalIds(vtkDataSet* data,
    long pointIdOffset,
    long cellIdOffset,
    long& maxPointId,
    long& maxCellId);

  static void setPrimary(smtk::resource::Component& c, bool isPrimary);
  static bool isPrimary(const smtk::resource::Component& c);
  static bool isSideSet(const smtk::resource::Component& c) { return !Session::isPrimary(c); }

protected:
  Session() = default;

  SessionInfoBits transcribeInternal(const smtk::model::EntityRef& entity,
    SessionInfoBits requestedInfo,
    int depth = -1) override;

  smtk::model::SessionIOPtr createIODelegate(const std::string& format) override;

  std::map<smtk::common::UUID, vtkSmartPointer<vtkDataObject> > m_storage;

private:
  Session(const Session&);        // Not implemented.
  void operator=(const Session&); // Not implemented.
};

} // namespace aeva
} // namespace session
} // namespace smtk

#endif // smtk_session_aeva_Session_h
