#pragma once

#include "Vector.h"
#include <string>

namespace Aftr
{

class ModelDataSharedID
{
public:
   ModelDataSharedID();
   ModelDataSharedID( const ModelDataSharedID& toCopy );
   ModelDataSharedID( const std::string& fileName, const Vector& scale );
   ~ModelDataSharedID();
   ModelDataSharedID& operator =( const ModelDataSharedID& id );
   bool operator ==( const ModelDataSharedID& id ) const;
   bool operator < ( const ModelDataSharedID& id ) const;
   std::string toString() const;
   const std::string& getFileName() const { return this->fileName; }
   const Vector& getScaleFactor() const { return this->scale; }
   unsigned int getInstanceCount() const { return this->instanceCount; }
   void incrementInstanceCount() const { ++this->instanceCount; }
   void decrementInstanceCount() const { --this->instanceCount; }
private:
   std::string fileName;
   Vector scale;
   mutable unsigned int instanceCount;
};

} //namespace Aftr

namespace std
{
   //Create a custom hash function for ModelDataSharedID and place it in the std namespace
   // so the std::unordered_multi_map can find this template specialization automatically.
   //https://stackoverflow.com/questions/17016175/c-unordered-map-using-a-custom-class-type-as-the-key

   //Sine we are using a hash function, we are combining a string and vector (3 floats), so
   // we want a good hash function.
   //https://stackoverflow.com/questions/1646807/quick-and-simple-hash-code-combinations/1646913#1646913

   template<>
   struct hash< Aftr::ModelDataSharedID >
   {
      size_t operator()( const Aftr::ModelDataSharedID& k ) const
      {
         std::hash<std::string> str_hasher;
         //uses underlying type of Vector (either float or double or long double, etc)
         using vec_type = std::remove_cvref_t< decltype(std::declval<Aftr::ModelDataSharedID>().getScaleFactor()) >::value_type;
         std::hash<vec_type> vec_hasher;

         size_t hash = 17;
         hash = hash * 31 + str_hasher( k.getFileName() );
         const auto& v = k.getScaleFactor();
         hash = hash * 31 + vec_hasher( v.x );
         hash = hash * 31 + vec_hasher( v.y );
         hash = hash * 31 + vec_hasher( v.z );
         return hash;
      }
   };

   //template<>
   //struct equal< Aftr::ModelDataSharedID >
   //{
   //   size_t operator()( const Aftr::ModelDataSharedID& a, const Aftr::ModelDataSharedID& b ) const
   //   {
   //      return a == b;
   //   }
   //};
}
