/*=========================================================================
 *
 *  Copyright NumFOCUS
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/
#ifndef itkArray_hxx
#define itkArray_hxx

#include "itkArray.h"
#include "itkNumericTraitsArrayPixel.h"

namespace itk
{
/** Default constructor */
template <typename TValue>
Array<TValue>::Array()
  : vnl_vector<TValue>()
{
  m_LetArrayManageMemory = true;
}

/** Copy constructor */
template <typename TValue>
Array<TValue>::Array(const Self & rhs)
  : vnl_vector<TValue>(rhs)
  ,
  // The vnl vector copy constructor creates new memory
  // no matter the setting of let array manage memory of rhs
  m_LetArrayManageMemory(true)
{}

template <typename TValue>
Array<TValue>::Array(const VnlVectorType & rhs)
  : vnl_vector<TValue>(rhs)
  ,
  // The vnl vector copy constructor creates new memory
  // no matter the setting of let array manage memory of rhs
  m_LetArrayManageMemory(true)
{}

/** Constructor with size */
template <typename TValue>
Array<TValue>::Array(SizeValueType dimension)
  : vnl_vector<TValue>(dimension)
  ,
  // The vnl vector copy constructor creates new memory
  // no matter the setting of let array manage memory of rhs
  m_LetArrayManageMemory(true)
{}

/** Constructor with user specified data */
template <typename TValue>
Array<TValue>::Array(ValueType * datain, SizeValueType sz, bool LetArrayManageMemory)
  : m_LetArrayManageMemory(LetArrayManageMemory)
{
  vnl_vector<TValue>::data = datain;
  vnl_vector<TValue>::num_elmts = sz;
}

#if defined(ITK_LEGACY_REMOVE)
/** Constructor with user specified const data */
template <typename TValue>
Array<TValue>::Array(const ValueType * datain, SizeValueType sz)
  : vnl_vector<TValue>(datain, sz)
  ,
  // The vnl vector copy constructor creates new memory
  // no matter the setting of let array manage memory of rhs
  m_LetArrayManageMemory(true)
{}

#else // defined ( ITK_LEGACY_REMOVE )
/** Constructor with user specified const data */
template <typename TValue>
Array<TValue>::Array(const ValueType * datain, SizeValueType sz, bool /* LetArrayManageMemory */)
  : /* NOTE: The 3rd argument "LetArrayManageMemory, was never valid to use, but is
     * preserved to maintain backwards compatibility*/
  vnl_vector<TValue>(datain, sz)
  ,
  // The vnl vector copy constructor creates new memory
  // no matter the setting of let array manage memory of rhs
  m_LetArrayManageMemory(true)
{}
#endif


/** Destructor */
template <typename TValue>
Array<TValue>::~Array()
{
  if (!m_LetArrayManageMemory)
  {
    vnl_vector<TValue>::data = nullptr;
  }
}

template <typename TValue>
void
Array<TValue>::SetDataSameSize(TValue * datain, bool LetArrayManageMemory)
{
  if (m_LetArrayManageMemory)
  {
    vnl_vector<TValue>::destroy();
  }
  vnl_vector<TValue>::data = datain;
  // NOTE: Required to have same size vnl_vector< TValue >::num_elmts = sz;
  m_LetArrayManageMemory = LetArrayManageMemory;
}

template <typename TValue>
void
Array<TValue>::SetData(TValue * datain, SizeValueType sz, bool LetArrayManageMemory)
{
  if (m_LetArrayManageMemory)
  {
    vnl_vector<TValue>::destroy();
  }
  vnl_vector<TValue>::data = datain;
  vnl_vector<TValue>::num_elmts = sz;
  m_LetArrayManageMemory = LetArrayManageMemory;
}

template <typename TValue>
void
Array<TValue>::SetSize(SizeValueType sz)
{
  if (this->size() != sz)
  {
    // If the array doesn't own the data we do not want to erase it
    // on a resize
    if (!m_LetArrayManageMemory)
    {
      vnl_vector<TValue>::data = nullptr;
    }

    // Call the superclass's set_size
    this->set_size(sz);

    // Size we have allocated new data we need to take
    // responsibility for deleting it
    m_LetArrayManageMemory = true;
  }
}

template <typename TValue>
const typename Array<TValue>::Self &
Array<TValue>::operator=(const Self & rhs)
{
  if (this != &rhs)
  {

    // Set the size the same as rhs.
    // The SetSize method takes care of who is responsible
    // for memory management
    //
    this->SetSize(rhs.GetSize());

    // Call the superclass implementation
    this->VnlVectorType::operator=(rhs);
  }
  return *this;
}

template <typename TValue>
const typename Array<TValue>::Self &
Array<TValue>::operator=(const VnlVectorType & rhs)
{
  if (this != &rhs)
  {

    // Set the size the same as rhs.
    // The SetSize method takes care of who is responsible
    // for memory management
    //
    this->SetSize(rhs.size());

    // Call the superclass implementation
    this->VnlVectorType::operator=(rhs);
  }
  return *this;
}
} // namespace itk

#endif
