// Created on: 2004-11-23
// Created by: Pavel TELKOV
// Copyright (c) 2004-2014 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.

// The original implementation Copyright: (C) RINA S.p.A

#include <TObj_Model.hxx>

#include <OSD_File.hxx>
#include <TDataStd_Integer.hxx>
#include <TDF_Tool.hxx>
#include <TDocStd_Owner.hxx>

#include <TObj_Assistant.hxx>
#include <TObj_Application.hxx>
#include <TObj_CheckModel.hxx>
#include <TObj_HiddenPartition.hxx>
#include <TObj_LabelIterator.hxx>
#include <TObj_ModelIterator.hxx>
#include <TObj_Object.hxx>
#include <TObj_Partition.hxx>
#include <TObj_TObject.hxx>
#include <TObj_TModel.hxx>
#include <TObj_TNameContainer.hxx>
#include <Message_Msg.hxx>
#include <OSD_OpenFile.hxx>

IMPLEMENT_STANDARD_RTTIEXT(TObj_Model, Standard_Transient)

#ifdef _MSC_VER
  #include <io.h>
#else
  #include <unistd.h>
#endif

//=================================================================================================

TObj_Model::TObj_Model()
{
  myMessenger = GetApplication()->Messenger();
}

//=================================================================================================

const Handle(TObj_Application) TObj_Model::GetApplication()
{
  return TObj_Application::GetInstance();
}

//=================================================================================================

TObj_Model::~TObj_Model()
{
  Close();
}

//=======================================================================
// function : CloseDocument
// purpose  : free OCAF document
//=======================================================================

void TObj_Model::CloseDocument(const Handle(TDocStd_Document)& theDoc)
{
  // prevent Abort of the following modifs at document destruction if
  // a transaction is open: see theDoc->myUndoTransaction.~()
  if (theDoc->HasOpenCommand())
    theDoc->AbortCommand();

  // Application
  const Handle(TObj_Application) anApplication = GetApplication();

  // just all other attributes
  theDoc->Main().Root().ForgetAllAttributes(Standard_True);
  anApplication->Close(theDoc);
}

//=======================================================================
// function : Load
// purpose  : Loads the model from the file
//=======================================================================

Standard_Boolean TObj_Model::Load(const TCollection_ExtendedString& theFile)
{
  // Return status
  Standard_Boolean aStatus = Standard_True;

  // Document
  Handle(TDocStd_Document) aDoc;

  // Application
  const Handle(TObj_Application) anApplication = GetApplication();

  // Current model
  const Handle(TObj_Model) me = this;
  TObj_Assistant::SetCurrentModel(me);
  TObj_Assistant::ClearTypeMap();

  Standard_Boolean isFileEmpty = checkDocumentEmpty(theFile);
  if (isFileEmpty)
  {
    // theFile is empty, create new TDocStd_Document for this model
    aStatus = anApplication->CreateNewDocument(aDoc, GetFormat());

    if (aStatus == Standard_True)
    {
      // Put model in a new attribute on root label
      TDF_Label           aLabel = aDoc->Main();
      Handle(TObj_TModel) anAtr  = new TObj_TModel;
      aLabel.AddAttribute(anAtr);
      anAtr->Set(me);
      // Record that label in the model object, and initialise the new model
      SetLabel(aLabel);
    }
  }
  else
  {
    // retrieve TDocStd_Document from <theFile>
    Messenger()->Send(Message_Msg("TObj_M_LoadDocument") << theFile, Message_Info);
    aStatus = anApplication->LoadDocument(theFile, aDoc);

    if (aStatus == Standard_True)
    {
      // Check for validity of the model read:
      // if it had wrong type, it has not been not properly restored
      TDF_Label        aLabel  = GetLabel();
      Standard_Boolean isValid = !aLabel.IsNull() && !aDoc.IsNull();
      {
        try
        {
          isValid = isValid && aLabel.Data() == aDoc->GetData();
        }
        catch (Standard_Failure const&)
        {
          isValid = Standard_False;
        }
      }
      if (!isValid)
      {
        if (!aDoc.IsNull())
          CloseDocument(aDoc);
        myLabel.Nullify();
        Messenger()->Send(Message_Msg("TObj_M_WrongFile") << theFile, Message_Alarm);
        aStatus = Standard_False;
      }
    }
    else
    {
      // release document from session
      // no message is needed as it has been put in anApplication->LoadDocument()
      if (!aDoc.IsNull())
        CloseDocument(aDoc);
      myLabel.Nullify();
    }
  }
  //    initialise the new model
  if (aStatus == Standard_True)
  {
    Standard_Boolean isInitOk = Standard_False;
    {
      try
      {
        isInitOk = initNewModel(isFileEmpty);
      }
      catch (Standard_Failure const& anException)
      {
#ifdef OCCT_DEBUG
        TCollection_ExtendedString aString(anException.DynamicType()->Name());
        aString = aString + ": " + anException.GetMessageString();
        Messenger()->Send(Message_Msg("TObj_Appl_Exception") << aString);
#endif
        (void)anException;
        Messenger()->Send(Message_Msg("TObj_M_WrongFile") << theFile, Message_Alarm);
      }
    }
    if (!isInitOk)
    {
      if (!aDoc.IsNull())
        CloseDocument(aDoc);
      myLabel.Nullify();
      aStatus = Standard_False;
    }
  }
  TObj_Assistant::UnSetCurrentModel();
  TObj_Assistant::ClearTypeMap();
  return aStatus;
}

//=======================================================================
// function : Load
// purpose  : Load the OCAF model from a stream. If case of failure,
//           it initializes the model by empty data.
//=======================================================================

Standard_Boolean TObj_Model::Load(Standard_IStream& theIStream)
{
  Handle(TDocStd_Document)       aDoc;
  Standard_Boolean               aStatus = Standard_True, isFileLoaded = Standard_False;
  const Handle(TObj_Application) anApplication = GetApplication();

  // Current model
  const Handle(TObj_Model) me = this;
  TObj_Assistant::SetCurrentModel(me);
  TObj_Assistant::ClearTypeMap();

  // Retrieve TDocStd_Document from the stream.
  Messenger()->Send(Message_Msg("TObj_M_LoadDocument"), Message_Info);
  aStatus = anApplication->LoadDocument(theIStream, aDoc);
  if (aStatus)
  {
    // Check for validity of the model read:
    // if it had wrong type, it has not been not properly restored
    TDF_Label        aLabel  = GetLabel();
    Standard_Boolean isValid = (!aLabel.IsNull() && !aDoc.IsNull());
    try
    {
      isValid = (isValid && aLabel.Data() == aDoc->GetData());
    }
    catch (Standard_Failure const&)
    {
      isValid = Standard_False;
    }
    if (!isValid)
    {
      if (!aDoc.IsNull())
        CloseDocument(aDoc);
      myLabel.Nullify();
      Messenger()->Send(Message_Msg("TObj_M_WrongFile"), Message_Alarm);
      aStatus = Standard_False;
    }
    isFileLoaded = isValid;
  }
  else
  {
    // release document from session
    // no message is needed as it has been put in anApplication->LoadDocument()
    if (!aDoc.IsNull())
      CloseDocument(aDoc);
    myLabel.Nullify();

    aStatus = anApplication->CreateNewDocument(aDoc, GetFormat());
    if (aStatus)
    {
      // Put model in a new attribute on root label
      TDF_Label           aLabel = aDoc->Main();
      Handle(TObj_TModel) anAtr  = new TObj_TModel;
      aLabel.AddAttribute(anAtr);
      anAtr->Set(me);
      // Record that label in the model object, and initialise the new model
      SetLabel(aLabel);
    }
  }

  // Initialise the new model
  if (aStatus)
  {
    Standard_Boolean isInitOk = Standard_False;
    try
    {
      isInitOk = initNewModel(!isFileLoaded);
    }
    catch (Standard_Failure const& anException)
    {
#ifdef OCCT_DEBUG
      TCollection_ExtendedString aString(anException.DynamicType()->Name());
      aString = aString + ": " + anException.GetMessageString();
      Messenger()->Send(Message_Msg("TObj_Appl_Exception") << aString);
#endif
      (void)anException;
      Messenger()->Send(Message_Msg("TObj_M_WrongFile"), Message_Alarm);
    }
    if (!isInitOk)
    {
      if (!aDoc.IsNull())
        CloseDocument(aDoc);
      myLabel.Nullify();
      aStatus = Standard_False;
    }
  }

  TObj_Assistant::UnSetCurrentModel();
  TObj_Assistant::ClearTypeMap();
  return aStatus;
}

//=======================================================================
// function : GetFile
// purpose  : Returns the full file name this model is to be saved to,
//           or null if the model was not saved yet
//=======================================================================

Handle(TCollection_HExtendedString) TObj_Model::GetFile() const
{
  Handle(TDocStd_Document) aDoc = GetDocument();
  if (aDoc.IsNull() || !aDoc->IsStored())
  {
    return Handle(TCollection_HExtendedString)();
  }

  TCollection_ExtendedString aPath(aDoc->GetPath());
  return !aPath.IsEmpty() ? new TCollection_HExtendedString(aPath)
                          : Handle(TCollection_HExtendedString)();
}

//=======================================================================
// function : Save
// purpose  : Save the model to the same file
//=======================================================================

Standard_Boolean TObj_Model::Save()
{
  Handle(TDocStd_Document) aDoc = TDocStd_Document::Get(GetLabel());
  if (aDoc.IsNull())
    return Standard_False;

  if (!aDoc->GetPath().IsEmpty())
    return SaveAs(aDoc->GetPath());
  return Standard_True;
}

//=======================================================================
// function : SaveAs
// purpose  : Save the model to a file
//=======================================================================

Standard_Boolean TObj_Model::SaveAs(const TCollection_ExtendedString& theFile)
{
  TObj_Assistant::ClearTypeMap();
  // OCAF document
  Handle(TDocStd_Document) aDoc = TDocStd_Document::Get(GetLabel());
  if (aDoc.IsNull())
    return Standard_False;

  // checking that file is present on disk is not needed because could try to save as new
  // document to existent file
  // checking write access permission
  FILE* aF = OSD_OpenFile(theFile, "w");
  if (aF == NULL)
  {
    Messenger()->Send(Message_Msg("TObj_M_NoWriteAccess") << theFile, Message_Alarm);
    return Standard_False;
  }
  else
    fclose(aF);

  // store transaction mode
  Standard_Boolean aTrMode = aDoc->ModificationMode();
  aDoc->SetModificationMode(Standard_False);
  // store all trancienmt fields of object in OCAF document if any
  Handle(TObj_ObjectIterator) anIterator;
  for (anIterator = GetObjects(); anIterator->More(); anIterator->Next())
  {
    Handle(TObj_Object) anOCAFObj = anIterator->Value();
    if (anOCAFObj.IsNull())
      continue;
    anOCAFObj->BeforeStoring();
  } // end of for(anIterator = ...)
  // set transaction mode back
  aDoc->SetModificationMode(aTrMode);

  // Application
  const Handle(TObj_Application) anApplication = GetApplication();

  // call Application->SaveAs()
  Standard_Boolean aStatus = anApplication->SaveDocument(aDoc, theFile);

  TObj_Assistant::ClearTypeMap();
  return aStatus;
}

//=======================================================================
// function : SaveAs
// purpose  : Save the model to a stream
//=======================================================================

Standard_Boolean TObj_Model::SaveAs(Standard_OStream& theOStream)
{
  TObj_Assistant::ClearTypeMap();
  // OCAF document
  Handle(TDocStd_Document) aDoc = TDocStd_Document::Get(GetLabel());
  if (aDoc.IsNull())
    return Standard_False;

  // store transaction mode
  Standard_Boolean aTrMode = aDoc->ModificationMode();
  aDoc->SetModificationMode(Standard_False);
  // store all trancienmt fields of object in OCAF document if any
  Handle(TObj_ObjectIterator) anIterator;
  for (anIterator = GetObjects(); anIterator->More(); anIterator->Next())
  {
    Handle(TObj_Object) anOCAFObj = anIterator->Value();
    if (anOCAFObj.IsNull())
      continue;
    anOCAFObj->BeforeStoring();
  } // end of for(anIterator = ...)
    // set transaction mode back
  aDoc->SetModificationMode(aTrMode);

  // call Application->SaveAs()
  Standard_Boolean aStatus = GetApplication()->SaveDocument(aDoc, theOStream);
  TObj_Assistant::ClearTypeMap();
  return aStatus;
}

//=======================================================================
// function : Close
// purpose  : Close the model and free related OCAF document
//=======================================================================

Standard_Boolean TObj_Model::Close()
{
  // OCAF document
  TDF_Label aLabel = GetLabel();
  if (aLabel.IsNull())
    return Standard_False;
  Handle(TDocStd_Document) aDoc = TDocStd_Document::Get(aLabel);
  if (aDoc.IsNull())
    return Standard_False;

  CloseDocument(aDoc);

  myLabel.Nullify();
  return Standard_True;
}

//=======================================================================
// function : GetDocumentModel
// purpose  : returns model which contains a document with the label
//           returns NULL handle if label is NULL
//=======================================================================

Handle(TObj_Model) TObj_Model::GetDocumentModel(const TDF_Label& theLabel)
{
  Handle(TObj_Model) aModel;
  if (theLabel.IsNull())
    return aModel;

  Handle(TDocStd_Document) aDoc;
  Handle(TDF_Data)         aData  = theLabel.Data();
  TDF_Label                aRootL = aData->Root();
  if (aRootL.IsNull())
    return aModel;
  Handle(TDocStd_Owner) aDocOwnerAtt;
  if (aRootL.FindAttribute(TDocStd_Owner::GetID(), aDocOwnerAtt))
    aDoc = aDocOwnerAtt->GetDocument();

  if (aDoc.IsNull())
    return aModel;

  TDF_Label           aLabel = aDoc->Main();
  Handle(TObj_TModel) anAttr;
  if (aLabel.FindAttribute(TObj_TModel::GetID(), anAttr))
    aModel = anAttr->Model();

  return aModel;
}

//=================================================================================================

Handle(TObj_ObjectIterator) TObj_Model::GetObjects() const
{
  Handle(TObj_Model) me = this;
  return new TObj_ModelIterator(me);
}

//=================================================================================================

Handle(TObj_ObjectIterator) TObj_Model::GetChildren() const
{
  Handle(TObj_Partition) aMainPartition = GetMainPartition();
  if (aMainPartition.IsNull())
    return 0;
  return aMainPartition->GetChildren();
}

//=================================================================================================

Handle(TObj_Object) TObj_Model::FindObject(const Handle(TCollection_HExtendedString)& theName,
                                           const Handle(TObj_TNameContainer)& theDictionary) const
{
  Handle(TObj_TNameContainer) aDictionary = theDictionary;
  if (aDictionary.IsNull())
    aDictionary = GetDictionary();
  Handle(TObj_Object) aResult;
  // Check is object with given name is present in model
  if (IsRegisteredName(theName, aDictionary))
  {
    TDF_Label aLabel = aDictionary->Get().Find(theName);
    TObj_Object::GetObj(aLabel, aResult);
  }

  return aResult;
}

//=================================================================================================

Handle(TObj_Object) TObj_Model::GetRoot() const
{
  return getPartition(GetLabel());
}

//=================================================================================================

Handle(TObj_Partition) TObj_Model::GetMainPartition() const
{
  return getPartition(GetLabel());
}

//=================================================================================================

void TObj_Model::SetNewName(const Handle(TObj_Object)& theObject)
{
  Handle(TObj_Partition) aPartition = TObj_Partition::GetPartition(theObject);

  // sets name if partition is found
  if (aPartition.IsNull())
    return;

  Handle(TCollection_HExtendedString) name = aPartition->GetNewName();
  if (!name.IsNull())
    theObject->SetName(name);
}

//=================================================================================================

Standard_Boolean TObj_Model::IsRegisteredName(
  const Handle(TCollection_HExtendedString)& theName,
  const Handle(TObj_TNameContainer)&         theDictionary) const
{
  Handle(TObj_TNameContainer) aDictionary = theDictionary;
  if (aDictionary.IsNull())
    aDictionary = GetDictionary();

  if (aDictionary.IsNull())
    return Standard_False;
  return aDictionary->IsRegistered(theName);
}

//=================================================================================================

void TObj_Model::RegisterName(const Handle(TCollection_HExtendedString)& theName,
                              const TDF_Label&                           theLabel,
                              const Handle(TObj_TNameContainer)&         theDictionary) const
{
  Handle(TObj_TNameContainer) aDictionary = theDictionary;
  if (aDictionary.IsNull())
    aDictionary = GetDictionary();

  if (!aDictionary.IsNull())
    aDictionary->RecordName(theName, theLabel);
}

//=================================================================================================

void TObj_Model::UnRegisterName(const Handle(TCollection_HExtendedString)& theName,
                                const Handle(TObj_TNameContainer)&         theDictionary) const
{
  Handle(TObj_TNameContainer) aDictionary = theDictionary;
  if (aDictionary.IsNull())
    aDictionary = GetDictionary();

  if (!aDictionary.IsNull())
    aDictionary->RemoveName(theName);
}

//=================================================================================================

Handle(TObj_TNameContainer) TObj_Model::GetDictionary() const
{
  Handle(TObj_TNameContainer) A;
  TDF_Label                   aLabel = GetLabel();
  if (!aLabel.IsNull())
    aLabel.FindAttribute(TObj_TNameContainer::GetID(), A);
  return A;
}

//=================================================================================================

Handle(TObj_Partition) TObj_Model::getPartition(const TDF_Label&       theLabel,
                                                const Standard_Boolean theHidden) const
{
  Handle(TObj_Partition) aPartition;
  if (theLabel.IsNull())
    return aPartition;
  Handle(TObj_TObject) A;

  if (!theLabel.FindAttribute(TObj_TObject::GetID(), A))
  {
    if (theHidden)
      aPartition = new TObj_HiddenPartition(theLabel);
    else
      aPartition = TObj_Partition::Create(theLabel);
  }
  else
    aPartition = Handle(TObj_Partition)::DownCast(A->Get());

  return aPartition;
}

//=================================================================================================

Handle(TObj_Partition) TObj_Model::getPartition(const TDF_Label&                  theLabel,
                                                const Standard_Integer            theIndex,
                                                const TCollection_ExtendedString& theName,
                                                const Standard_Boolean            theHidden) const
{
  Handle(TObj_Partition) aPartition;
  if (theLabel.IsNull())
    return aPartition;

  TDF_Label        aLabel = theLabel.FindChild(theIndex, Standard_False);
  Standard_Boolean isNew  = Standard_False;
  // defining is partition new
  if (aLabel.IsNull())
  {
    aLabel = theLabel.FindChild(theIndex, Standard_True);
    isNew  = Standard_True;
  }
  // obtaining the partition
  aPartition = getPartition(aLabel, theHidden);

  // setting name to new partition
  if (isNew)
    aPartition->SetName(new TCollection_HExtendedString(theName));
  return aPartition;
}

//=================================================================================================

Handle(TObj_Partition) TObj_Model::getPartition(const Standard_Integer            theIndex,
                                                const TCollection_ExtendedString& theName,
                                                const Standard_Boolean            theHidden) const
{
  return getPartition(GetMainPartition()->GetChildLabel(), theIndex, theName, theHidden);
}

//=================================================================================================

Standard_Boolean TObj_Model::initNewModel(const Standard_Boolean IsNew)
{
  // set names map
  TObj_TNameContainer::Set(GetLabel());

  // do something for loaded model.
  if (!IsNew)
  {
    // Register names of model in names map.
    Handle(TObj_ObjectIterator) anIterator;
    for (anIterator = GetObjects(); anIterator->More(); anIterator->Next())
    {
      Handle(TObj_Object) anOCAFObj = anIterator->Value();
      if (anOCAFObj.IsNull())
        continue;
      anOCAFObj->AfterRetrieval();
    } // end of for(anIterator = ...)
    // update back references for loaded model by references
    updateBackReferences(GetMainPartition());

    if (isToCheck())
    {
      // check model consistency
      Handle(TObj_CheckModel) aCheck = GetChecker();
      aCheck->Perform();
      aCheck->SendMessages();
      // tell that the model has been modified
      SetModified(Standard_True);
    }
  }
  return Standard_True;
}

//=================================================================================================

void TObj_Model::updateBackReferences(const Handle(TObj_Object)& theObject)
{
  // recursive update back references
  if (theObject.IsNull())
    return;
  Handle(TObj_ObjectIterator) aChildren = theObject->GetChildren();
  for (; aChildren->More(); aChildren->Next())
  {
    Handle(TObj_Object) aChild = aChildren->Value();
    updateBackReferences(aChild);
  }
  // update back references of reference objects
  Handle(TObj_LabelIterator) anIter =
    Handle(TObj_LabelIterator)::DownCast(theObject->GetReferences());

  if (anIter.IsNull()) // to avoid exception
    return;

  // LH3D15722. Remove all back references to make sure there will be no unnecessary
  // duplicates, since some back references may already exist after model upgrading.
  // (do not take care that object can be from other document, because
  // we do not modify document, all modifications are made in transient fields)
  for (; anIter->More(); anIter->Next())
  {
    Handle(TObj_Object) anObject = anIter->Value();
    if (!anObject.IsNull())
      anObject->RemoveBackReference(theObject, Standard_False);
  }
  // and at last create back references
  anIter = Handle(TObj_LabelIterator)::DownCast(theObject->GetReferences());
  if (!anIter.IsNull())
    for (; anIter->More(); anIter->Next())
    {
      Handle(TObj_Object) anObject = anIter->Value();
      if (!anObject.IsNull())
        anObject->AddBackReference(theObject);
    }
}

//=================================================================================================

Handle(TDocStd_Document) TObj_Model::GetDocument() const
{
  Handle(TDocStd_Document) D;
  TDF_Label                aLabel = GetLabel();
  if (!aLabel.IsNull())
    D = TDocStd_Document::Get(aLabel);
  return D;
}

//=================================================================================================

Standard_Boolean TObj_Model::HasOpenCommand() const
{
  return GetDocument()->HasOpenCommand();
}

//=================================================================================================

void TObj_Model::OpenCommand() const
{
  GetDocument()->OpenCommand();
}

//=================================================================================================

void TObj_Model::CommitCommand() const
{
  GetDocument()->CommitCommand();
}

//=================================================================================================

void TObj_Model::AbortCommand() const
{
  GetDocument()->AbortCommand();
}

//=======================================================================
// function : IsModified
// purpose  : Status of modification
//=======================================================================

Standard_Boolean TObj_Model::IsModified() const
{
  Handle(TDocStd_Document) aDoc = GetDocument();
  return aDoc.IsNull() ? Standard_False : aDoc->IsChanged();
}

//=======================================================================
// function : SetModified
// purpose  : Status of modification
//=======================================================================

void TObj_Model::SetModified(const Standard_Boolean theModified)
{
  Handle(TDocStd_Document) aDoc = GetDocument();
  if (!aDoc.IsNull())
  {
    Standard_Integer aSavedTime = aDoc->GetData()->Time();
    if (theModified)
      --aSavedTime;
    aDoc->SetSavedTime(aSavedTime);
  }
}

//=======================================================================
// function : checkDocumentEmpty
// purpose  : Check whether the document contains the Ocaf data
//=======================================================================

Standard_Boolean TObj_Model::checkDocumentEmpty(const TCollection_ExtendedString& theFile)
{
  if (theFile.IsEmpty())
    return Standard_True;

  OSD_Path aPath(theFile);
  OSD_File osdfile(aPath);
  if (!osdfile.Exists())
    return Standard_True;

  FILE* f = OSD_OpenFile(theFile, "r");
  if (f)
  {
    Standard_Boolean isZeroLengh = Standard_False;
    fseek(f, 0, SEEK_END);
    if (ftell(f) == 0)
      isZeroLengh = Standard_True;

    fclose(f);
    return isZeroLengh;
  }
  return Standard_False;
}

//=================================================================================================

Standard_GUID TObj_Model::GetGUID() const
{
  Standard_GUID aGUID("3bbefb49-e618-11d4-ba38-0060b0ee18ea");
  return aGUID;
}

//=================================================================================================

TCollection_ExtendedString TObj_Model::GetFormat() const
{
  return TCollection_ExtendedString("TObjBin");
}

//=================================================================================================

Standard_Integer TObj_Model::GetFormatVersion() const
{
  TDF_Label aLabel = GetDataLabel().FindChild(DataTag_FormatVersion, Standard_False);
  if (aLabel.IsNull())
    return -1;

  Handle(TDataStd_Integer) aNum;
  if (!aLabel.FindAttribute(TDataStd_Integer::GetID(), aNum))
    return -1;
  else
    return aNum->Get();
}

//=================================================================================================

void TObj_Model::SetFormatVersion(const Standard_Integer theVersion)
{
  TDF_Label aLabel = GetDataLabel().FindChild(DataTag_FormatVersion, Standard_True);
  TDataStd_Integer::Set(aLabel, theVersion);
}

//=================================================================================================

TDF_Label TObj_Model::GetDataLabel() const
{
  return GetMainPartition()->GetDataLabel();
}

//=================================================================================================

Standard_Boolean TObj_Model::Paste(Handle(TObj_Model)          theModel,
                                   Handle(TDF_RelocationTable) theRelocTable)
{
  if (theModel.IsNull())
    return Standard_False;
  // clearing dictionary of objects names
  //  theModel->GetDictionary()->NewEmpty()->Paste(theModel->GetDictionary(),
  //                                               new TDF_RelocationTable);
  //  theModel->GetLabel().ForgetAllAttributes(Standard_True);
  TObj_TNameContainer::Set(theModel->GetLabel());
  GetMainPartition()->Clone(theModel->GetLabel(), theRelocTable);
  return Standard_True;
}

//=================================================================================================

void TObj_Model::CopyReferences(const Handle(TObj_Model)&          theTarget,
                                const Handle(TDF_RelocationTable)& theRelocTable)
{
  Handle(TObj_Object) aMyRoot     = GetMainPartition();
  Handle(TObj_Object) aTargetRoot = theTarget->GetMainPartition();
  aMyRoot->CopyReferences(aTargetRoot, theRelocTable);
}

//=======================================================================
// function : GetModelName
// purpose  : Returns the name of the model
//           by default returns TObj
//=======================================================================

Handle(TCollection_HExtendedString) TObj_Model::GetModelName() const
{
  Handle(TCollection_HExtendedString) aName = new TCollection_HExtendedString("TObj");
  return aName;
}

//=======================================================================
// function : Update
// purpose  : default implementation is empty
//=======================================================================

Standard_Boolean TObj_Model::Update()
{
  return Standard_True;
}

//=================================================================================================

Handle(TObj_CheckModel) TObj_Model::GetChecker() const
{
  return new TObj_CheckModel(this);
}
