//=========================================================================
//  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_simulation_ace3p_DerivedFrom_h
#define smtk_simulation_ace3p_DerivedFrom_h

#include "smtk/common/TypeName.h"
#include "smtk/resource/DerivedFrom.h"
#include "smtk/resource/Resource.h"

namespace smtk
{
namespace simulation
{
namespace ace3p
{

/// This class is used in place of smtk::resource::DerivedFrom in order
/// to workaround a problem compiling with VS2019 on some windows
/// machines.

template<typename Self, typename Parent>
class DerivedFrom : public Parent
{
public:
  typedef Parent ParentResource;

  /// A static index for this resource type.
  ///
  /// NOTE: because we are using CRTP, it is possible to make this value static
  ///       and redefined for each resource type, regardless of inheritance.
  static const ::smtk::resource::Resource::Index type_index;

  /// given a resource index, return whether or not this resource is or is
  /// derived from the resource described by the index.
  virtual bool isOfType(const smtk::resource::Resource::Index& index) const override
  {
    return ::smtk::resource::DerivedFrom<Self, Parent>::type_index == index
      ? true
      : ParentResource::isOfType(index);
  }

  /// given a resource's unique name, return whether or not this resource is or
  /// is derived from the resource described by the name.
  virtual bool isOfType(const std::string& typeName) const override
  {
    return ::smtk::common::typeName<Self>() == typeName ? true : ParentResource::isOfType(typeName);
  }

  virtual int numberOfGenerationsFromBase(const std::string& typeName) const override
  {
    return (
      ::smtk::common::typeName<Self>() == typeName
        ? 0
        : 1 + ParentResource::numberOfGenerationsFromBase(typeName));
  }

protected:
  /// Forward all constructor arguments to the parent class.
  template<typename... T>
  DerivedFrom(T&&... all)
    : Parent(std::forward<T>(all)...)
  {
  }

  // Next 2 constructors are removed
  // DerivedFrom(DerivedFrom&& rhs)
  //   : Parent(std::move(rhs))
  // {
  // }

  // DerivedFrom(const DerivedFrom&) = delete;
};

template<typename Self, typename Parent>
const smtk::resource::Resource::Index DerivedFrom<Self, Parent>::type_index =
  std::type_index(typeid(Self)).hash_code();
} // namespace ace3p
} // namespace simulation
} // namespace smtk

#endif // smtk_simulation_ace3p_DerivedFrom_h
