#pragma once
#include <string>
#include <tuple>
#include <chrono>
#include "Vector.h"

namespace Aftr
{

class WO;
class ModelMesh;

class SelectionQueryResult
{
public:

   using clock_type = std::chrono::system_clock;

   SelectionQueryResult();
   SelectionQueryResult( WO* const wo,
      ModelMesh* const lastSelectedMesh, 
      const int lastSelectedMeshIdx,
      const unsigned int x_pix, const unsigned int y_pix,
      Vector const& coord );
   SelectionQueryResult( SelectionQueryResult const& toCopy );
   SelectionQueryResult( SelectionQueryResult&& toMove ) noexcept = delete;
   ~SelectionQueryResult() = default;

   SelectionQueryResult& operator=( SelectionQueryResult const& toCopyAssign );
   //SelectionQueryResult& operator=( SelectionQueryResult&& toMoveAssign ) noexcept = delete;

   std::string toString() const;

   WO* getLastSelectedWO() const noexcept { return this->wo; }
   WO* getLastSelectedWO()       noexcept { return this->wo; }

   ModelMesh* getLastSelectedModelMesh() const noexcept { return this->modelMesh; }
   ModelMesh* getLastSelectedModelMesh() noexcept { return this->modelMesh; }

   int getLastSelectedModelMeshIdx() const noexcept { return this->modelMeshIdx; }
   std::optional<Vector> getLastSelectedCoordinate() const noexcept { return this->coord; }
   unsigned int getX() const noexcept { return x; }
   unsigned int getY() const noexcept { return x; }
   std::tuple<unsigned int,unsigned int> getXY() const noexcept { return std::make_tuple(this->x,this->y); }
   clock_type::time_point getTimeOfSelection() const noexcept { return this->timeCreated; }

private:

   /**
      When the user crtl-clicks an object in the world, selection is enabled. If the user clicked on a WO or any child WO,
      this variable shall be set to point at the selected WO. For example, if the user clicks on the human's lower arm,
      this variable points at the human's lower arm. If the user only want the top most parent; ie, the pointer to the human,
      the user can simply call the wo->getParentWO() until nullptr is returned. At this point, the parent is selected.

      The lastSelectedWorldObject is owned and deleted by GLView. Therefore the user shall never need to call delete lastSelectedWorldObject.
   */
   WO* wo = nullptr;

   /**
      After a selection of a World Object is completed, this points at the global coordinate
      in three space where the selection actually took place. The user NEVER owns this vector
      and shall never call delete on it.
   */
   //std::optional<Aftr::Vector> getLastSelectedCoordinate() const noexcept;

   //void setLastSelectedCoordinate( const Vector& vec );

   /**
      When the user crtl-clicks an object in the world, selection is enabled. If the user clicked on a WO that has a valid
      ModelDataShared containing a std::vector< ModelMesh* > meshes. The selected mesh will be populated here.
      For example, if the user clicks on the a car made of 15 meshes, and selects the mesh comprising the windshield, at
      meshes[idx], a this variable will be set to meshes[idx].

      The lastSelectedModelMesh is owned and deleted by GLView. Therefore the user shall never need to call delete lastSelectedModelMesh.
   */
   ModelMesh* modelMesh = nullptr;
   int modelMeshIdx = -1; //only valid when lastSelectedModelMesh is not nullptr, otherwise, this will be -1

   unsigned int x = 0; ///< X pixel of selection query
   unsigned int y = 0; ///< Y pixel of selection query

   std::optional< Vector > coord; //bool indicates if this variable holds a valid Vector. 
                                                      //If false, no Vector was found on most recent query.
                                                      //If true, Vector contains most recent query world space coordinate.

   clock_type::time_point timeCreated;

};

} //namespace Aftr
