// Copyright (c) 2015 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.

#include <StdLPersistent_Collection.hxx>

#include <TColStd_HPackedMapOfInteger.hxx>
#include <TCollection_HExtendedString.hxx>

struct StdLPersistent_Collection::noConversion
{
  noConversion(const Handle(TDF_Data)&) {}

  template <class Type>
  Type operator()(Type theValue) const
  {
    return theValue;
  }
};

struct StdLPersistent_Collection::byteConverter
{
  byteConverter(const Handle(TDF_Data)&) {}

  Standard_Byte operator()(Standard_Integer theValue) const
  {
    return static_cast<Standard_Byte>(theValue);
  }
};

struct StdLPersistent_Collection::boolConverter
{
  boolConverter(const Handle(TDF_Data)&) {}

  Standard_Boolean operator()(Standard_Integer theValue) const { return theValue != 0; }
};

struct StdLPersistent_Collection::stringConverter
{
  stringConverter(const Handle(TDF_Data)&) {}

  const TCollection_ExtendedString& operator()(const Handle(StdObjMgt_Persistent)& theValue) const
  {
    static TCollection_ExtendedString anEmptyString;
    if (theValue.IsNull())
      return anEmptyString;

    Handle(TCollection_HExtendedString) aString = theValue->ExtString();
    return aString ? aString->String() : anEmptyString;
  }
};

struct StdLPersistent_Collection::referenceConverter
{
  referenceConverter(const Handle(TDF_Data)& theDF)
      : myDF(theDF)
  {
  }

  TDF_Label operator()(const Handle(StdObjMgt_Persistent)& theValue) const
  {
    return theValue->Label(myDF);
  }

private:
  Handle(TDF_Data) myDF;
};

template <class Base>
template <class ArrayHandle, class Converter>
void StdLPersistent_Collection::booleanArrayBase<Base>::import(const ArrayHandle& theArray,
                                                               Converter theConverter) const
{
  Handle(TColStd_HArray1OfByte) aByteArray =
    new TColStd_HArray1OfByte(theArray->Lower(), theArray->Upper());

  for (Standard_Integer i = theArray->Lower(); i <= theArray->Upper(); i++)
    aByteArray->SetValue(i, theConverter(theArray->Value(i)));

  this->myTransient->Init(myLower, myUpper);
  this->myTransient->SetInternalArray(aByteArray);
}

template <class Base>
template <class ArrayHandle, class Converter>
void StdLPersistent_Collection::directArrayBase<Base>::import(const ArrayHandle& theArray,
                                                              Converter) const
{
  this->myTransient->ChangeArray(theArray);
}

template <class Base>
template <class ArrayHandle, class Converter>
void StdLPersistent_Collection::arrayBase<Base>::import(const ArrayHandle& theArray,
                                                        Converter          theConverter) const
{
  this->myTransient->Init(theArray->Lower(), theArray->Upper());
  for (Standard_Integer i = theArray->Lower(); i <= theArray->Upper(); i++)
    this->myTransient->SetValue(i, theConverter(theArray->Value(i)));
}

template <class Base>
template <class ArrayHandle, class Converter>
void StdLPersistent_Collection::listBase<Base>::import(const ArrayHandle& theArray,
                                                       Converter          theConverter) const
{
  for (Standard_Integer i = theArray->Lower(); i <= theArray->Upper(); i++)
    this->myTransient->Append(theConverter(theArray->Value(i)));
}

template <class Base>
template <class ArrayHandle, class Converter>
void StdLPersistent_Collection::mapBase<Base>::import(const ArrayHandle& theArray,
                                                      Converter          theConverter) const
{
  Handle(TColStd_HPackedMapOfInteger) anHMap = new TColStd_HPackedMapOfInteger;
  for (Standard_Integer i = theArray->Lower(); i <= theArray->Upper(); i++)
    anHMap->ChangeMap().Add(theConverter(theArray->Value(i)));
  this->myTransient->ChangeMap(anHMap);
}

//=======================================================================
// function : ImportAttribute
// purpose  : Import transient attribute from the persistent data
//=======================================================================
template <template <class> class BaseT, class HArrayClass, class AttribClass, class Converter>
void StdLPersistent_Collection::instance<BaseT, HArrayClass, AttribClass, Converter>::
  ImportAttribute()
{
  Handle(HArrayClass) anHArray = Handle(HArrayClass)::DownCast(this->myData);
  if (anHArray)
  {
    typename HArrayClass::ArrayHandle anArray = anHArray->Array();
    if (anArray)
      this->import(anArray, Converter(this->myTransient->Label().Data()));
    this->myData.Nullify();
  }
}

//=======================================================================
// function : Read
// purpose  : Read persistent data from a file
//=======================================================================
template <class Instance>
void StdLPersistent_Collection::instance_1<Instance>::Read(StdObjMgt_ReadData& theReadData)
{
  Instance::Read(theReadData);
  theReadData >> myDelta;
}

//=======================================================================
// function : ImportAttribute
// purpose  : Import transient attribute from the persistent data
//=======================================================================
template <class Instance>
void StdLPersistent_Collection::instance_1<Instance>::ImportAttribute()
{
  Instance::ImportAttribute();
  this->myTransient->SetDelta(myDelta);
}

template class StdLPersistent_Collection::instance<StdLPersistent_Collection::booleanArrayBase,
                                                   StdLPersistent_Collection::integer,
                                                   TDataStd_BooleanArray,
                                                   StdLPersistent_Collection::byteConverter>;

template class StdLPersistent_Collection::instance<StdLPersistent_Collection::directArrayBase,
                                                   StdLPersistent_Collection::integer,
                                                   TDataStd_IntegerArray,
                                                   StdLPersistent_Collection::noConversion>;

template class StdLPersistent_Collection::instance<StdLPersistent_Collection::directArrayBase,
                                                   StdLPersistent_Collection::real,
                                                   TDataStd_RealArray,
                                                   StdLPersistent_Collection::noConversion>;

template class StdLPersistent_Collection::instance<StdLPersistent_Collection::arrayBase,
                                                   StdLPersistent_Collection::integer,
                                                   TDataStd_ByteArray,
                                                   StdLPersistent_Collection::byteConverter>;

template class StdLPersistent_Collection::instance<StdLPersistent_Collection::arrayBase,
                                                   StdLPersistent_Collection::persistent,
                                                   TDataStd_ExtStringArray,
                                                   StdLPersistent_Collection::stringConverter>;

template class StdLPersistent_Collection::instance<StdLPersistent_Collection::arrayBase,
                                                   StdLPersistent_Collection::persistent,
                                                   TDataStd_ReferenceArray,
                                                   StdLPersistent_Collection::referenceConverter>;

template class StdLPersistent_Collection::instance<StdLPersistent_Collection::listBase,
                                                   StdLPersistent_Collection::integer,
                                                   TDataStd_IntegerList,
                                                   StdLPersistent_Collection::noConversion>;

template class StdLPersistent_Collection::instance<StdLPersistent_Collection::listBase,
                                                   StdLPersistent_Collection::real,
                                                   TDataStd_RealList,
                                                   StdLPersistent_Collection::noConversion>;

template class StdLPersistent_Collection::instance<StdLPersistent_Collection::listBase,
                                                   StdLPersistent_Collection::integer,
                                                   TDataStd_BooleanList,
                                                   StdLPersistent_Collection::boolConverter>;

template class StdLPersistent_Collection::instance<StdLPersistent_Collection::listBase,
                                                   StdLPersistent_Collection::persistent,
                                                   TDataStd_ExtStringList,
                                                   StdLPersistent_Collection::stringConverter>;

template class StdLPersistent_Collection::instance<StdLPersistent_Collection::listBase,
                                                   StdLPersistent_Collection::persistent,
                                                   TDataStd_ReferenceList,
                                                   StdLPersistent_Collection::referenceConverter>;

template class StdLPersistent_Collection::instance<StdLPersistent_Collection::mapBase,
                                                   StdLPersistent_Collection::integer,
                                                   TDataStd_IntPackedMap,
                                                   StdLPersistent_Collection::noConversion>;

template class StdLPersistent_Collection::instance_1<StdLPersistent_Collection::IntegerArray>;

template class StdLPersistent_Collection::instance_1<StdLPersistent_Collection::RealArray>;

template class StdLPersistent_Collection::instance_1<StdLPersistent_Collection::ByteArray>;

template class StdLPersistent_Collection::instance_1<StdLPersistent_Collection::ExtStringArray>;

template class StdLPersistent_Collection::instance_1<StdLPersistent_Collection::IntPackedMap>;
