/*
 * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * 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.
 */


/*===========================================================================*/
/*===============================[ Includes ]================================*/
/*===========================================================================*/
#include "otbGeometriesSet.h"
#include <cassert>

/*===========================================================================*/
/*================================[ Helpers ]================================*/
/*===========================================================================*/
namespace otb { namespace ogr { namespace internal {

/**\ingroup GeometryInternals
 * Access shim: itk smart-pointer to reference.
 * \param[in] ds  itk smart pointer
 * \return a reference to the pointee.
 * \throw None
 * \pre <tt>ds != 0</tt>
 * \since OTB v 3.14.0
 */
template <typename DataType> inline
  DataType & getRef(typename itk::SmartPointer<DataType> const& ds)
    {
    assert(ds && "unexpected nil datasource");
    return *ds;
    }

/**\ingroup GeometryInternals
 * Access shim: const layer to reference.
 * \param[in] layer layer proxy
 * \return the layer proxy
 * \throw None
 * \since OTB v 3.14.0
 */
inline
otb::ogr::Layer const& getRef(otb::ogr::Layer const& layer)
  {
  return layer;
  }

/**\ingroup GeometryInternals
 * Access shim: layer to reference.
 * \param[in] layer layer proxy
 * \return the layer proxy
 * \throw None
 * \since OTB v 3.14.0
 */
inline
otb::ogr::Layer & getRef(otb::ogr::Layer & layer)
  {
  return layer;
  }
} } } // otb::ogr::internal namespaces


/*===========================================================================*/
/*=======================[ Setting and construction ]========================*/
/*===========================================================================*/
otb::GeometriesSet::GeometriesSet()
: m_GeometriesSet(otb::ogr::DataSource::New())
, m_ImageReference(*this)
{
}

otb::GeometriesSet::GeometriesSet(ogr::DataSource::Pointer datasource)
: m_GeometriesSet(datasource)
, m_ImageReference(*this)
{
  assert(datasource && "unexpected nil datasource");
}

otb::GeometriesSet::GeometriesSet(ogr::Layer layer)
: m_GeometriesSet(layer)
, m_ImageReference(*this)
{
}

/*static*/
otb::GeometriesSet::Pointer otb::GeometriesSet::New(ogr::DataSource::Pointer datasource)
{
  Pointer res = new Self(datasource);
  res->UnRegister();
  return res;
}

/*static*/
otb::GeometriesSet::Pointer otb::GeometriesSet::New(ogr::Layer layer)
{
  Pointer res = new Self(layer);
  res->UnRegister();
  return res;
}

/*virtual*/
otb::GeometriesSet::~GeometriesSet()
{
}

void otb::GeometriesSet::Set(ogr::Layer layer)
{
  assert(layer && "unexpected nil layer");
  m_GeometriesSet = layer;
}

void otb::GeometriesSet::Set(ogr::DataSource::Pointer datasource)
{
  assert(datasource && "unexpected nil datasource");
  m_GeometriesSet = datasource;
}

/*===========================================================================*/
/*=================================[ IsSet ]=================================*/
/*===========================================================================*/
namespace otb { namespace ogr { namespace internal {
/**\ingroup GeometryInternals
 * Visitor (functor) to test whether a geometries set is non-null.
 * \param[in] gs geometries set
 * \throw None
 * \since OTB v 3.14.0
 */
struct IsSetTester : boost::static_visitor<bool>
{
  template <typename T>
    bool operator()(T const& gs) const
      {
      return getRef(gs);
      }
};
} } } // otb::ogr::internal namespaces

bool otb::GeometriesSet::IsSet() const
{
  return this->apply(ogr::internal::IsSetTester());
}

/*===========================================================================*/
/*===============================[ Printing ]================================*/
/*===========================================================================*/
namespace otb { namespace ogr { namespace internal {
/**\ingroup GeometryInternals
 * Visitor (functor) to print a geometries set.
 * \param[in] gs geometries set
 * \throw None
 * \since OTB v 3.14.0
 */
struct Printer : boost::static_visitor<>
{
  Printer(std::ostream& os, itk::Indent indent)
    : m_os(os), m_indent(indent) {}
  void operator()(otb::ogr::Layer layer) const
    {
    assert(layer && "unexpected nil layer...");
    layer.PrintSelf(m_os, m_indent);
    }
  void operator()(otb::ogr::DataSource::Pointer datasource) const
    {
    assert(datasource && "unexpected nil datasource...");
    datasource->Print(m_os, m_indent);
    }
private:
  std::ostream &m_os;
  itk::Indent   m_indent;
};
} } } // otb::ogr::internal namespaces

void otb::GeometriesSet::PrintSelf(std::ostream& os, itk::Indent indent) const
{
  this->apply(ogr::internal::Printer(os, indent));
}
