// This file is part of GOAST, a C++ library for variational methods in Geometry Processing
//
// Copyright (C) 2021 Behrend Heeren & Josua Sassen, University of Bonn <goast@ins.uni-bonn.de>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef SHELL_AUXILIARY_H
#define SHELL_AUXILIARY_H

#include <Eigen/Dense>


namespace shell{
  double getDihedralAngle( const Eigen::Vector3d &nk, const Eigen::Vector3d &nl, const Eigen::Vector3d &e );

  double getDihedralAngle( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                           const Eigen::Vector3d &Pl );

  double getAreaSqr( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk );

  double getArea( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk );

  void getNormal( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                  Eigen::Vector3d &normal );


  void getCrossOp( const Eigen::Vector3d &a, Eigen::Matrix3d &matrix );

  void getProjection( const Eigen::Vector3d& x, Eigen::Matrix3d& m );

  void getReflection( const Eigen::Vector3d& x, Eigen::Matrix3d& m );

  void getAreaGradient( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                        Eigen::Vector3d &grad );

  void getAreaGradK( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                     Eigen::Vector3d &grad );

  void getThetaGradK( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                      Eigen::Vector3d &grad );

  void getThetaGradILeftPart( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                              Eigen::Vector3d &grad );

  void getThetaGradJLeftPart( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                              Eigen::Vector3d &grad );

  void getThetaGradI( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                      const Eigen::Vector3d &Pl, Eigen::Vector3d &grad );

  void getThetaGradJ( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                      const Eigen::Vector3d &Pl, Eigen::Vector3d &grad );

  void getHessAreaKK( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                      Eigen::Matrix3d &Hess );

  void getHessAreaIK( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                      Eigen::Matrix3d &Hess );

  void getHessThetaKK( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                       Eigen::Matrix3d &Hkk );

  void getHessThetaIK( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                       Eigen::Matrix3d &Hik );

  void getHessThetaJK( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                       Eigen::Matrix3d &Hjk );

  void getHessThetaILeftPartI( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                               Eigen::Matrix3d &HiLeft );

  void getHessThetaJLeftPartI( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                               Eigen::Matrix3d &HjLeft );

  void getHessThetaII( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                       const Eigen::Vector3d &Pl, Eigen::Matrix3d &Hii );

  void getHessThetaJI( const Eigen::Vector3d &Pi, const Eigen::Vector3d &Pj, const Eigen::Vector3d &Pk,
                       const Eigen::Vector3d &Pl, Eigen::Matrix3d &Hji );
}
#endif