text: /*****************************************************************************************
   *                                                                                       *
   * OpenSpace                                                                             *
   *                                                                                       *
   * Copyright (c) 2014-2019                                                               *
   *                                                                                       *
   * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
   * software and associated documentation files (the "Software"), to deal in the Software *
   * without restriction, including without limitation the rights to use, copy, modify,    *
   * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
   * permit persons to whom the Software is furnished to do so, subject to the following   *
   * conditions:                                                                           *
   *                                                                                       *
   * The above copyright notice and this permission notice shall be included in all copies *
   * or substantial portions of the Software.                                              *
   *                                                                                       *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
   * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
   * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
   * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
   * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
   * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
   ****************************************************************************************/
  
  #include <openspace/util/transformationmanager.h>
  
  #include <openspace/util/spicemanager.h>
  #include <ghoul/logging/logmanager.h>
  #include <ghoul/misc/assert.h>
  
  #ifdef OPENSPACE_MODULE_KAMELEON_ENABLED
  #ifdef WIN32
  #pragma warning (push)
  #pragma warning (disable : 4619) // #pragma warning: there is no warning number '4675'
  #endif // WIN32
  
  #include <ccmc/Kameleon.h>
  
  #ifdef WIN32
  #pragma warning (pop)
  #endif // WIN32
  #endif
  
  namespace {
      constexpr const char* _loggerCat = "TransformationManager";
  }
  
  namespace openspace {
  
  TransformationManager* TransformationManager::_instance = nullptr;
  
  TransformationManager::TransformationManager() {
  #ifdef OPENSPACE_MODULE_KAMELEON_ENABLED
      _kameleon = std::make_shared<ccmc::Kameleon>();
  #else
      LWARNINGC(
          "TransformationManager",
          "Kameleon module needed for transformations with dynamic frames"
      );
  #endif
      _kameleonFrames = {
          "J2000", "GEI", "GEO", "MAG", "GSE", "GSM", "SM", "RTN", "GSEQ",   //geocentric
          "HEE", "HAE", "HEEQ"                                              //heliocentric
      };
  }
  
  TransformationManager::~TransformationManager() { // NOLINT
  #ifdef OPENSPACE_MODULE_KAMELEON_ENABLED
      _kameleon = nullptr;
  #endif
  }
  
  void TransformationManager::initialize() {
      ghoul_assert(!isInitialized(), "TransformationManager is already initialized");
      _instance = new TransformationManager;
  }
  
  void TransformationManager::deinitialize() {
      ghoul_assert(isInitialized(), "TransformationManager is not initialized");
      delete _instance;
      _instance = nullptr;
  }
  
  bool TransformationManager::isInitialized() {
      return _instance != nullptr;
  }
  
  TransformationManager& TransformationManager::ref() {
      ghoul_assert(isInitialized(), "TransformationManager is not initialized");
      return *_instance;
  }
  
  
  glm::dmat3 TransformationManager::kameleonTransformationMatrix(
                                                   [[maybe_unused]] const std::string& from,
                                                     [[maybe_unused]] const std::string& to,
                                                [[maybe_unused]] double ephemerisTime) const
  {
  #ifdef OPENSPACE_MODULE_KAMELEON_ENABLED
      ccmc::Position in0 = {1.f, 0.f, 0.f};
      ccmc::Position in1 = {0.f, 1.f, 0.f};
      ccmc::Position in2 = {0.f, 0.f, 1.f};
  
      ccmc::Position out0;
      ccmc::Position out1;
      ccmc::Position out2;
  
      _kameleon->_cxform(from.c_str(), to.c_str(), ephemerisTime, &in0, &out0);
      _kameleon->_cxform(from.c_str(), to.c_str(), ephemerisTime, &in1, &out1);
      _kameleon->_cxform(from.c_str(), to.c_str(), ephemerisTime, &in2, &out2);
  
      return glm::dmat3(
          out0.c0 , out0.c1   , out0.c2,
          out1.c0 , out1.c1   , out1.c2,
          out2.c0 , out2.c1   , out2.c2
      );
  #else
      return glm::dmat3(0.0);
  #endif
  }
  
  glm::dmat3 TransformationManager::frameTransformationMatrix(
                                                   [[maybe_unused]] const std::string& from,
                                                     [[maybe_unused]] const std::string& to,
                                                [[maybe_unused]] double ephemerisTime) const
  {
  #ifdef OPENSPACE_MODULE_KAMELEON_ENABLED
      auto fromit = _kameleonFrames.find(from);
      auto toit   = _kameleonFrames.find(to);
  
      bool fromKameleon   = (fromit != _kameleonFrames.end());
      bool toKameleon     = (toit   != _kameleonFrames.end());
  
      if (!fromKameleon && !toKameleon) {
          return  SpiceManager::ref().frameTransformationMatrix(from, to, ephemerisTime);
      }
  
      if (fromKameleon && toKameleon) {
          return kameleonTransformationMatrix(from, to, ephemerisTime);
  
      } else if (fromKameleon && !toKameleon) {
          glm::dmat3 kameleonTransformation = kameleonTransformationMatrix(
              from,
              "J2000",
              ephemerisTime
          );
          glm::dmat3 spiceTransformation = SpiceManager::ref().frameTransformationMatrix(
              "J2000",
              to,
              ephemerisTime
          );
          return spiceTransformation*kameleonTransformation;
      } else if (!fromKameleon && toKameleon) {
          glm::dmat3 spiceTransformation = SpiceManager::ref().frameTransformationMatrix(
              from,
              "J2000",
              ephemerisTime
          );
          glm::dmat3 kameleonTransformation = kameleonTransformationMatrix(
              "J2000",
              to,
              ephemerisTime
          );
  
          return kameleonTransformation*spiceTransformation;
      }
  #else
      LERRORC(
          "TransformationManager",
          "Can not transform dynamic frames without kameleon module enabled"
      );
  #endif
      return glm::dmat3(1.0);
  }
  
  } // namespace openspace
  