// File:	BinMNaming_NamingDriver.cxx
// Created:	Thu May 13 16:57:08 2004
// Author:	Sergey ZARITCHNY <szy@opencascade.com>
// Copyright:	Open CasCade S.A. 2004



#include <BinMNaming_NamingDriver.ixx>
#include <TopAbs_ShapeEnum.hxx>
#include <TCollection_ExtendedString.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <CDM_MessageDriver.hxx>
#include <TDF_Attribute.hxx>
#include <TNaming_NameType.hxx>
#include <TNaming_Naming.hxx>
#include <TNaming_NamedShape.hxx>
#include <TNaming_ListIteratorOfListOfNamedShape.hxx>
#include <BinMDF_ADriver.hxx>
#include <BinObjMgt_Persistent.hxx>
#include <BinObjMgt_RRelocationTable.hxx>
#include <BinObjMgt_SRelocationTable.hxx>
//=======================================================================
static Standard_Character NameTypeToChar(const TNaming_NameType theNameType)
{
  switch(theNameType) {
    case TNaming_UNKNOWN      : return 'N';
    case TNaming_IDENTITY     : return 'I';
    case TNaming_MODIFUNTIL   : return 'M';
    case TNaming_GENERATION   : return 'G';
    case TNaming_INTERSECTION : return 'S';
    case TNaming_UNION        : return 'U';
    case TNaming_SUBSTRACTION : return 'B';
    case TNaming_CONSTSHAPE   : return 'C';
    case TNaming_FILTERBYNEIGHBOURGS : return 'F';
  default:
    Standard_DomainError::Raise("TNaming_NameType:: Name Type Unknown");
  }
  return 'N'; // To avoid compilation error message.
}

//=======================================================================
static TNaming_NameType CharTypeToName(const Standard_Character theCharType)
{
  switch(theCharType) {
    case 'N'  : return TNaming_UNKNOWN;
    case 'I'  : return TNaming_IDENTITY;
    case 'M'  : return TNaming_MODIFUNTIL;
    case 'G'  : return TNaming_GENERATION;
    case 'S'  : return TNaming_INTERSECTION;
    case 'U'  : return TNaming_UNION;
    case 'B'  : return TNaming_SUBSTRACTION;
    case 'C'  : return TNaming_CONSTSHAPE;
    case 'F'  : return TNaming_FILTERBYNEIGHBOURGS;
  default:
    Standard_DomainError::Raise("TNaming_NameType:: Name Type Unknown");
  }
  return TNaming_UNKNOWN; // To avoid compilation error message.
}

//=======================================================================
static Standard_Character ShapeTypeToChar(const TopAbs_ShapeEnum theShapeType)
{
  switch (theShapeType)
    {
    case TopAbs_COMPOUND  : return 'C';
    case TopAbs_COMPSOLID : return 'O';
    case TopAbs_SOLID     : return 'S';
    case TopAbs_SHELL     : return 'H';
    case TopAbs_FACE      : return 'F';
    case TopAbs_WIRE      : return 'W';
    case TopAbs_EDGE      : return 'E';
    case TopAbs_VERTEX    : return 'V';
    case TopAbs_SHAPE     : return 'A';
    }
  return 'A'; // To avoid compilation error message.
}
//=======================================================================
static TopAbs_ShapeEnum CharToShapeType(const Standard_Character theCharType)
{
  switch (theCharType)
    {
    case 'C' : return TopAbs_COMPOUND;
    case 'O' : return TopAbs_COMPSOLID;
    case 'S' : return TopAbs_SOLID;
    case 'H' : return TopAbs_SHELL;
    case 'F' : return TopAbs_FACE;
    case 'W' : return TopAbs_WIRE;
    case 'E' : return TopAbs_EDGE;
    case 'V' : return TopAbs_VERTEX;
    case 'A' : return TopAbs_SHAPE;
    }
  return TopAbs_SHAPE; // To avoid compilation error message.
}
//=======================================================================
//function : BinMNaming_NamingDriver
//purpose  : Constructor
//=======================================================================

BinMNaming_NamingDriver::BinMNaming_NamingDriver
                        (const Handle(CDM_MessageDriver)& theMsgDriver)
     : BinMDF_ADriver (theMsgDriver, STANDARD_TYPE(TNaming_Naming)->Name())
{
}

//=======================================================================
//function : NewEmpty
//purpose  : 
//=======================================================================

Handle(TDF_Attribute) BinMNaming_NamingDriver::NewEmpty() const
{
  return new TNaming_Naming();
}

//=======================================================================
//function : Paste
//purpose  : persistent -> transient (retrieve)
//=======================================================================

Standard_Boolean BinMNaming_NamingDriver::Paste
                                (const BinObjMgt_Persistent&  theSource,
                                 const Handle(TDF_Attribute)& theTarget,
                                 BinObjMgt_RRelocationTable&  theRelocTable) const
{
  Handle(TNaming_Naming) anAtt = Handle(TNaming_Naming)::DownCast(theTarget);
  TNaming_Name& aName = anAtt->ChangeName();
  TCollection_ExtendedString aMsg;
// NameType
  Standard_Character aValue;
  Standard_Boolean ok = theSource >> aValue;
  if (ok) {
    aName.Type(CharTypeToName(aValue));

// ShapeType    
    ok = theSource >> aValue;
    if (ok) {
      aName.ShapeType(CharToShapeType(aValue));
      
// Args
      Standard_Integer aNbArgs=0;
      Standard_Integer anIndx;
      Handle(TNaming_NamedShape) aNS;
      ok = theSource >> aNbArgs;
      if (ok) {
	if(aNbArgs > 0) {
	  Standard_Integer i;
	  for(i=1; i<=aNbArgs;i++) {
	    ok = theSource >> anIndx;
	    if(!ok) break;
	    else {
	      if (theRelocTable.IsBound(anIndx))
		aNS = Handle(TNaming_NamedShape)::DownCast(theRelocTable.Find(anIndx));
	      else {
		aNS = new TNaming_NamedShape;
		theRelocTable.Bind(anIndx, aNS);
	      }
	      aName.Append(aNS);
	    }
	  }
	}
// StopNS
	ok = theSource >> anIndx;
	if(ok) {
	  if(anIndx > 0) {
	    if (theRelocTable.IsBound(anIndx))
	      aNS = Handle(TNaming_NamedShape)::DownCast(theRelocTable.Find(anIndx));
	    else
	      {
		aNS = new TNaming_NamedShape;
		theRelocTable.Bind(anIndx, aNS);
	      }
	    aName.StopNamedShape(aNS);  
	  }
	  
// Index
	  ok = theSource >> anIndx;
	  if(ok) 
	    aName.Index(anIndx);
	  else {
	    aMsg = TCollection_ExtendedString(
	       "BinMNaming_NamingDriver: Cannot retrieve Index of Name");
	    WriteMessage (aMsg); 
	  }
	} else {
	  aMsg = TCollection_ExtendedString(
	       "BinMNaming_NamingDriver: Cannot retrieve reference on StopNamedShape");
	WriteMessage (aMsg); 
	}
      } else {
	aMsg = TCollection_ExtendedString(
	       "BinMNaming_NamingDriver: Cannot retrieve reference on Arguments of Name");
	WriteMessage (aMsg);
      }
    }
  }
  return ok;
}

//=======================================================================
//function : Paste
//purpose  : transient -> persistent (store)
//=======================================================================

void BinMNaming_NamingDriver::Paste (const Handle(TDF_Attribute)&  theSource,
                                       BinObjMgt_Persistent&       theTarget,
                                       BinObjMgt_SRelocationTable& theRelocTable) const
{
  Handle(TNaming_Naming) anAtt = Handle(TNaming_Naming)::DownCast(theSource);
  const TNaming_Name& aName = anAtt->GetName();

//1. << NameType to Char
  theTarget << NameTypeToChar(aName.Type());

//2. << ShapeType to Char
  theTarget << ShapeTypeToChar(aName.ShapeType());

//3. Keep Args
  Standard_Integer anIndx;
  Standard_Integer aNbArgs = aName.Arguments().Extent();
  theTarget << aNbArgs; // keep Number
  if (aNbArgs > 0) {
    Standard_Integer i=0;
    TColStd_Array1OfInteger anArray(1, aNbArgs);
    for (TNaming_ListIteratorOfListOfNamedShape it (aName.Arguments()); it.More(); it.Next()) {
      Handle(TNaming_NamedShape) anArg = it.Value();
      anIndx = 0; i++;
      if (!anArg.IsNull()) {
        anIndx = theRelocTable.FindIndex(anArg);
        if (anIndx == 0)
          anIndx = theRelocTable.Add(anArg);
      }
      anArray.SetValue(i, anIndx);
    }
    theTarget.PutIntArray ((BinObjMgt_PInteger) &anArray.Value(1), ((Standard_Integer)sizeof(Standard_Integer))); // keep Array
  }

// keep StopNS
  Handle(TNaming_NamedShape) aStopNS = aName.StopNamedShape();
  if (!aStopNS.IsNull()) {
    anIndx = theRelocTable.FindIndex(aStopNS);
    if (anIndx == 0)
      anIndx = theRelocTable.Add(aStopNS);
  }
  theTarget << anIndx;

// keep Index
  theTarget << aName.Index();
}
