// Copyright (c) 2013-2020, SIB - Swiss Institute of Bioinformatics and
//                          Biozentrum - University of Basel
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


#include <boost/python.hpp>
#include <promod3/core/export_helper.hh>
#include <promod3/core/message.hh>

#include <promod3/core/geom_base.hh>
#include <promod3/core/geom_stems.hh>

using namespace promod3::core;
using namespace boost::python;

namespace {

boost::python::list
WrapEvaluateGromacsPosRule(uint rule, uint number,
                           const boost::python::list& anchor_list) {
  // check input
  if (number > 3) {
    throw promod3::Error("Can generate at most 3 positions!");
    // NOTE: actual number depends on rule (not checked!)
  }
  if (boost::python::len(anchor_list) > 4) {
    throw promod3::Error("Can have at most 4 anchors!");
  }
  // get pos
  geom::Vec3 anchors[4];    // max. 4 anchors
  geom::Vec3 positions[3];  // max. 3 positions
  ConvertListToCArray(anchor_list, anchors);
  EvaluateGromacsPosRule(rule, number, anchors, positions);
  // get them out
  boost::python::list result;
  AppendToList(positions, positions + number, result);
  return result;
}

boost::python::tuple
WrapConstructCTerminalOxygens(const geom::Vec3& c_pos, const geom::Vec3& ca_pos,
                              const geom::Vec3& n_pos) {
  geom::Vec3 o_pos, oxt_pos;
  ConstructCTerminalOxygens(c_pos, ca_pos, n_pos, o_pos, oxt_pos);
  return boost::python::make_tuple(o_pos, oxt_pos);
}

geom::Vec3 WrapConstructAtomPos(const geom::Vec3& A, const geom::Vec3& B,
                                const geom::Vec3& C, Real bond_length,
                                Real angle, Real dihedral) {
  geom::Vec3 D;
  ConstructAtomPos(A, B, C, bond_length, angle, dihedral, D);
  return D;
}

geom::Vec3 WrapConstructCBetaPos(const geom::Vec3& n_pos,
                                 const geom::Vec3& ca_pos,
                                 const geom::Vec3& c_pos) {
  geom::Vec3 cb_pos;
  ConstructCBetaPos(n_pos, ca_pos, c_pos, cb_pos);
  return cb_pos;
}

} // anon ns

void export_geom() {
  def("EvaluateGromacsPosRule", WrapEvaluateGromacsPosRule,
      (arg("rule"), arg("number"), arg("anchor_list")));
  def("ConstructCTerminalOxygens", WrapConstructCTerminalOxygens,
      (arg("c_pos"), arg("ca_pos"), arg("n_pos")));
  def("ConstructAtomPos", WrapConstructAtomPos,
      (arg("A"), arg("B"), arg("C"), arg("bond_length"), arg("angle"),
       arg("dihedral")));
  def("ConstructCBetaPos", WrapConstructCBetaPos,
      (arg("n_pos"), arg("ca_pos"), arg("c_pos")));
  def("RotationAroundLine", RotationAroundLine,
      (arg("axis"), arg("anchor"), arg("angle")));
  def("RotationAroundAxis", RotationAroundAxis, (arg("axis"), arg("angle")));

  class_<StemCoords>("StemCoords", no_init)
    .def(init<>())
    .def(init<const ost::mol::ResidueHandle&>(arg("res")))
    .def_readwrite("n_coord", &StemCoords::n_coord)
    .def_readwrite("ca_coord", &StemCoords::ca_coord)
    .def_readwrite("c_coord", &StemCoords::c_coord)
  ;
  
  class_<StemPairOrientation>("StemPairOrientation", no_init)
    .def(init<>())
    .def(init<const StemCoords&, const StemCoords&>(
         (arg("n_stem"), arg("c_stem"))))
    .def_readwrite("distance", &StemPairOrientation::distance)
    .def_readwrite("angle_one", &StemPairOrientation::angle_one)
    .def_readwrite("angle_two", &StemPairOrientation::angle_two)
    .def_readwrite("angle_three", &StemPairOrientation::angle_three)
    .def_readwrite("angle_four", &StemPairOrientation::angle_four)
  ;
}
