/*
    GNU Octave level-set package.
    Copyright (C) 2014  Daniel Kraft <d@domob.eu>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/* Template implementations of Utils.hpp.  */

/**
 * Check and possibly return dimensions of an array.  If d1 and d2 are
 * both given as positive numbers, check that the array has the given size.
 * If one of them is negative (-1), return the dimension along this
 * dimension and check only the other one.  Throw if mismatch.
 * @param var The array to check.
 * @param d1 Row dimension.
 * @param d2 Column dimension.
 * @return Possibly the -1 dimension size.
 */
template<typename Arr>
  unsigned
  getDimensionReal (const Arr& var, const std::string& name,
                    int d1, int d2)
{
  const dim_vector size = var.dims ();
  if (size.length () > 2)
    throw std::runtime_error ("Expected at most two dimensions for "
                              + name + ".");
  assert (size.length () == 2);

  const int expected[2] = {d1, d2};
  unsigned res = 0;
  bool foundRes = false;
  for (unsigned i = 0; i < 2; ++i)
    if (expected[i] < 0)
      {
        if (foundRes)
          throw std::runtime_error ("Two dimensions unknown for " + name + ".");

        foundRes = true;
        res = size(i);
      }
    else if (expected[i] != size(i))
      {
        std::ostringstream msg;
        msg << "Dimension mismatch for " << name
            << " in dimension " << (i + 1) << ": ";
        msg << "expected " << expected[i] << ", got " << size(i);
        throw std::runtime_error (msg.str ());
      }

  return res;
}

/**
 * Convert a generic container to an Octave ColumnVector.
 * @param cont Generic container (e. g., std::vector<double>).
 * @return ColumnVector with the container's content.
 */
template<typename C>
  ColumnVector
  convertToColumnVector (const C& cont)
{
  ColumnVector res(cont.size ());

  unsigned ind = 0;
  for (const auto& el : cont)
    res(ind++) = el;
  assert (ind == cont.size ());
  
  return res;
}
