// File:	BinMXCAFDoc_LocationDriver.cxx
// Created:	Tue May 17 14:43:51 2005
// Author:	Eugeny NAPALKOV <eugeny.napalkov@opencascade.com>
// Copyright:	Open CasCade S.A. 2005

#include <BinMXCAFDoc_LocationDriver.ixx>
#include <XCAFDoc_Location.hxx>

#include <TopLoc_Datum3D.hxx>
#include <TopLoc_Location.hxx>
#include <gp_Trsf.hxx>
#include <gp_Mat.hxx>
#include <gp_XYZ.hxx>
//#include <Precision.hxx>


//=======================================================================
//function :
//purpose  : 
//=======================================================================
BinMXCAFDoc_LocationDriver::BinMXCAFDoc_LocationDriver(const Handle(CDM_MessageDriver)& theMsgDriver)
     : BinMDF_ADriver(theMsgDriver, STANDARD_TYPE(XCAFDoc_Location)->Name()) {
}

//=======================================================================
//function :
//purpose  : 
//=======================================================================
Handle(TDF_Attribute) BinMXCAFDoc_LocationDriver::NewEmpty() const {
  return new XCAFDoc_Location();
}

//=======================================================================
//function :
//purpose  : 
//=======================================================================
Standard_Boolean BinMXCAFDoc_LocationDriver::Paste(const BinObjMgt_Persistent& theSource,
						   const Handle(TDF_Attribute)& theTarget,
						   BinObjMgt_RRelocationTable& theRelocTable) const
{
  Handle(XCAFDoc_Location) anAtt = Handle(XCAFDoc_Location)::DownCast(theTarget);
  TopLoc_Location aLoc;
  Standard_Boolean aRes = Translate(theSource, aLoc, theRelocTable);
  anAtt->Set(aLoc);
  return aRes;
}

//=======================================================================
//function :
//purpose  : 
//=======================================================================
void BinMXCAFDoc_LocationDriver::Paste(const Handle(TDF_Attribute)& theSource,
				       BinObjMgt_Persistent& theTarget,
				       BinObjMgt_SRelocationTable& theRelocTable) const
{
  Handle(XCAFDoc_Location) anAtt = Handle(XCAFDoc_Location)::DownCast(theSource);
  TopLoc_Location aLoc = anAtt->Get();
  Translate(aLoc, theTarget, theRelocTable);
}

//=======================================================================
//function :
//purpose  : 
//=======================================================================
Standard_Boolean BinMXCAFDoc_LocationDriver::Translate(const BinObjMgt_Persistent& theSource,
						       TopLoc_Location& theLoc,
						       BinObjMgt_RRelocationTable& theMap)
{
  Standard_Integer anId = 0;
  theSource >> anId;
  if(anId != 0) {
    Standard_Integer aPower;
    theSource >> aPower;

    Handle(TopLoc_Datum3D) aDatum;
    Standard_Integer aDatumID = -1;
    Standard_Integer aReadDatum = -1;
    theSource >> aReadDatum;
    theSource >> aDatumID;
    if(aReadDatum != -1) {
      if(theMap.IsBound(aDatumID)) {
	aDatum = Handle(TopLoc_Datum3D)::DownCast(theMap.Find(aDatumID));
      } else
	return Standard_False;
    } else {
      // read the datum's trasformation
      gp_Trsf aTrsf;

      Standard_Real aScaleFactor;
      theSource >> aScaleFactor;
      aTrsf._CSFDB_Setgp_Trsfscale(aScaleFactor);

      Standard_Integer aForm;
      theSource >> aForm;
      aTrsf._CSFDB_Setgp_Trsfshape((gp_TrsfForm)aForm);

      Standard_Integer R, C;
      gp_Mat& aMat = (gp_Mat&)aTrsf._CSFDB_Getgp_Trsfmatrix();
      for(R = 1; R <= 3; R++)
	for(C = 1; C <= 3; C++) {
	  Standard_Real aVal;
	  theSource >> aVal;
	  aMat.SetValue(R, C, aVal);
	}

      Standard_Real x, y, z;
      theSource >> x >> y >> z;
      gp_XYZ& aLoc = (gp_XYZ&)aTrsf._CSFDB_Getgp_Trsfloc();
      aLoc.SetX(x);
      aLoc.SetY(y);
      aLoc.SetZ(z);

      aDatum = new TopLoc_Datum3D(aTrsf);
      theMap.Bind(aDatumID, aDatum);
    }

    TopLoc_Location aNextLoc;
    Translate(theSource, aNextLoc, theMap);
    theLoc = aNextLoc * TopLoc_Location(aDatum).Powered(aPower);
  }
  return Standard_True;
}

//=======================================================================
//function :
//purpose  : 
//=======================================================================
void BinMXCAFDoc_LocationDriver::Translate(const TopLoc_Location& theLoc,
					   BinObjMgt_Persistent& theTarget,
					   BinObjMgt_SRelocationTable& theMap) 
{
  if(!theLoc.IsIdentity()) {
    // The location is not identity
    theTarget << 1;

    theTarget << theLoc.FirstPower();
    Handle(TopLoc_Datum3D) aDatum = theLoc.FirstDatum();
    Standard_Integer anId = -1;
    if(theMap.Contains(aDatum)) {
      anId = theMap.FindIndex(aDatum);
      // The datum already stored
      theTarget << 1;
      theTarget << anId;
    } else {
      theTarget << anId;
      anId = theMap.Add(aDatum);
      theTarget << anId;

      // Store datum's transformation
      gp_Trsf aTrsf = aDatum->Transformation();

      theTarget << aTrsf.ScaleFactor();
      theTarget << aTrsf.Form();

      gp_Mat aMat = aTrsf.HVectorialPart();
      
      Standard_Integer R, C;
      for(R = 1; R <= 3; R ++)
	for(C = 1; C <= 3; C++)
	  theTarget << aMat.Value(R, C);

      gp_XYZ aLoc = aTrsf.TranslationPart();
      theTarget << aLoc.X() << aLoc.Y() << aLoc.Z();
    }
    Translate(theLoc.NextLocation(), theTarget, theMap);
  } else {
    // Location is identity
    theTarget << 0;
  }
}

