// 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 Handle(Transfer_ActorOfTransientProcess)& actor,
  const Handle(Interface_InterfaceModel)&         amodel)
{
  theproc = new Transfer_TransientProcess(amodel->NbEntities());
  theproc->SetActor(actor);
  themodel = amodel;
  //  thescope = Standard_False;
  //  theundef = Transfer_UndefIgnore;
}

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

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

Handle(Interface_InterfaceModel) Transfer_TransferOutput::Model() const
{
  return themodel;
}

Handle(Transfer_TransientProcess) Transfer_TransferOutput::TransientProcess() const
{
  return theproc;
}

void Transfer_TransferOutput::Transfer(const 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");
  //  Standard_Integer scope = 0;
  //  if (thescope) scope = theproc->NewScope (obj);

  //: 1 modified by ABV 5 Nov 97
  //: 1  if (!theproc->Transfer(obj)) return;    // auparavant, traitement Undefined
  //  Standard_Boolean 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
    }
  */
}

//  Resultats :
//   Pour transferer tout simplement toutes les racines d'un modele d'interface
//   Chacune est notee "Root" dans le Process final

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

void Transfer_TransferOutput::TransferRoots(const Handle(Interface_Protocol)& protocol,
                                            const Message_ProgressRange&      theProgress)
{
  theproc->SetRootManagement(Standard_False);
  Interface_ShareFlags     tool(themodel, protocol);
  Interface_EntityIterator list = tool.RootEntities();
  Message_ProgressScope    aPS(theProgress, NULL, list.NbEntities());
  for (list.Start(); list.More() && aPS.More(); list.Next())
  {
    const Handle(Standard_Transient)& ent = list.Value();
    //    Standard_Integer 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(Standard_False);
  Interface_ShareFlags tool(G);
  theproc->SetModel(G.Model());
  Interface_EntityIterator list = tool.RootEntities();
  Message_ProgressScope    aPS(theProgress, NULL, list.NbEntities());
  for (list.Start(); list.More() && aPS.More(); list.Next())
  {
    const Handle(Standard_Transient)& ent = list.Value();
    //    Standard_Integer 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 Standard_Boolean normal,
                                                                const Standard_Boolean roots) const
{
  Interface_EntityIterator list;
  Standard_Integer         max = (roots ? theproc->NbRoots() : theproc->NbMapped());
  for (Standard_Integer i = 1; i <= max; i++)
  {
    const Handle(Transfer_Binder)& binder = (roots ? theproc->RootItem(i) : theproc->MapItem(i));
    if (binder.IsNull())
      continue;
    Transfer_StatusExec statex = binder->StatusExec();
    Standard_Boolean    ok = (statex == Transfer_StatusInitial || statex == Transfer_StatusDone);
    if (ok == normal)
      list.AddItem((roots ? theproc->Root(i) : theproc->Mapped(i)));
  }
  return list;
}

Handle(Interface_InterfaceModel) Transfer_TransferOutput::ModelForStatus(
  const Handle(Interface_Protocol)& protocol,
  const Standard_Boolean            normal,
  const Standard_Boolean            roots) const
{
  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;
}
