// Copyright (c) 1999-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.

// szv#4 S4163

#include <Interface_EntityIterator.hxx>
#include <Interface_Graph.hxx>
#include <Interface_InterfaceModel.hxx>
#include <Interface_Protocol.hxx>
#include <Interface_ShareFlags.hxx>
#include <Standard_Transient.hxx>
#include <Transfer_ActorOfTransientProcess.hxx>
#include <Transfer_Binder.hxx>
#include <Transfer_TransferFailure.hxx>
#include <Transfer_TransferOutput.hxx>
#include <Transfer_TransientProcess.hxx>
#include <Message_ProgressScope.hxx>

Transfer_TransferOutput::Transfer_TransferOutput(
  const occ::handle<Transfer_ActorOfTransientProcess>& actor,
  const occ::handle<Interface_InterfaceModel>&         amodel)
{
  theproc = new Transfer_TransientProcess(amodel->NbEntities());
  theproc->SetActor(actor);
  themodel = amodel;
  //  thescope = false;
  //  theundef = Transfer_UndefIgnore;
}

Transfer_TransferOutput::Transfer_TransferOutput(
  const occ::handle<Transfer_TransientProcess>& proc,
  const occ::handle<Interface_InterfaceModel>&  amodel)
{
  theproc  = proc;
  themodel = amodel;
  //  thescope = false; //szv#4:S4163:12Mar99 initialization needed
  //  theundef = Transfer_UndefIgnore;
}

// bool&  Transfer_TransferOutput::ScopeMode ()
//{  return  thescope;  }

occ::handle<Interface_InterfaceModel> Transfer_TransferOutput::Model() const
{
  return themodel;
}

occ::handle<Transfer_TransientProcess> Transfer_TransferOutput::TransientProcess() const
{
  return theproc;
}

void Transfer_TransferOutput::Transfer(const occ::handle<Standard_Transient>& obj,
                                       const Message_ProgressRange&           theProgress)
{
  if (themodel->Number(obj) == 0)
  {
    throw Transfer_TransferFailure(
      "TransferOutput : Transfer, entities do not come from same initial model");
  }
  //  int scope = 0;
  //  if (thescope) scope = theproc->NewScope (obj);

  //: 1 modified by ABV 5 Nov 97
  //: 1  if (!theproc->Transfer(obj)) return;    // auparavant, traitement Undefined
  //  bool ok =
  theproc->Transfer(obj, theProgress);
  //  if (scope > 0) theproc->EndScope (scope);
  //  if ( ! ok ) return;

  /*  switch (theundef) {
      case Transfer_UndefIgnore  : return;
      case Transfer_UndefFailure : throw Transfer_TransferFailure("TransferOutput : Transfer
    Undefined as Failure"); case Transfer_UndefContent : break; // on ne sait pas traiter ... case
    Transfer_UndefUser    : break; // idem
    }
  */
}

//  Results :
//   To transfer quite simply all roots of an interface model
//   Each one is noted "Root" in the final Process

void Transfer_TransferOutput::TransferRoots(const Message_ProgressRange& theProgress)
{
  TransferRoots(Interface_Protocol::Active(), theProgress);
}

void Transfer_TransferOutput::TransferRoots(const occ::handle<Interface_Protocol>& protocol,
                                            const Message_ProgressRange&           theProgress)
{
  theproc->SetRootManagement(false);
  Interface_ShareFlags     tool(themodel, protocol);
  Interface_EntityIterator list = tool.RootEntities();
  Message_ProgressScope    aPS(theProgress, nullptr, list.NbEntities());
  for (list.Start(); list.More() && aPS.More(); list.Next())
  {
    const occ::handle<Standard_Transient>& ent = list.Value();
    //    int scope = 0;
    //    if (thescope) scope = theproc->NewScope (ent);
    if (theproc->Transfer(ent, aPS.Next()))
    {
      theproc->SetRoot(ent);
    }
    //    if (scope > 0) theproc->EndScope (scope);
  }
}

void Transfer_TransferOutput::TransferRoots(const Interface_Graph&       G,
                                            const Message_ProgressRange& theProgress)
{
  theproc->SetRootManagement(false);
  Interface_ShareFlags tool(G);
  theproc->SetModel(G.Model());
  Interface_EntityIterator list = tool.RootEntities();
  Message_ProgressScope    aPS(theProgress, nullptr, list.NbEntities());
  for (list.Start(); list.More() && aPS.More(); list.Next())
  {
    const occ::handle<Standard_Transient>& ent = list.Value();
    //    int scope = 0;
    //    if (thescope) scope = theproc->NewScope (ent);
    if (theproc->Transfer(ent, aPS.Next()))
    {
      theproc->SetRoot(ent);
    }
    //    if (scope > 0) theproc->EndScope (scope);
  }
}

Interface_EntityIterator Transfer_TransferOutput::ListForStatus(const bool normal,
                                                                const bool roots) const
{
  Interface_EntityIterator list;
  int                      max = (roots ? theproc->NbRoots() : theproc->NbMapped());
  for (int i = 1; i <= max; i++)
  {
    const occ::handle<Transfer_Binder>& binder =
      (roots ? theproc->RootItem(i) : theproc->MapItem(i));
    if (binder.IsNull())
    {
      continue;
    }
    Transfer_StatusExec statex = binder->StatusExec();
    bool                ok = (statex == Transfer_StatusInitial || statex == Transfer_StatusDone);
    if (ok == normal)
    {
      list.AddItem((roots ? theproc->Root(i) : theproc->Mapped(i)));
    }
  }
  return list;
}

occ::handle<Interface_InterfaceModel> Transfer_TransferOutput::ModelForStatus(
  const occ::handle<Interface_Protocol>& protocol,
  const bool                             normal,
  const bool                             roots) const
{
  occ::handle<Interface_InterfaceModel> newmod;
  if (themodel.IsNull())
  {
    return newmod;
  }
  newmod                        = themodel->NewEmptyModel();
  Interface_EntityIterator list = ListForStatus(normal, roots);
  for (list.Start(); list.More(); list.Next())
  {
    newmod->AddWithRefs(list.Value(), protocol);
  }
  return newmod;
}
