// Created on: 1997-07-30
// Created by: Denis PASCAL
// Copyright (c) 1997-1999 Matra Datavision
// 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.

#include <DDataStd.hxx>

#include <DDF.hxx>
#include <Draw_Interpretor.hxx>
#include <Draw_Appli.hxx>

#include <TDF_Data.hxx>
#include <TDF_Label.hxx>
#include <TDF_ChildIterator.hxx>
#include <TDF_Tool.hxx>

#include <TNaming_NamedShape.hxx>

#include <TDataStd_Real.hxx>
#include <TDataStd_Integer.hxx>
#include <TDataXtd_Constraint.hxx>
#include <TDataXtd_PatternStd.hxx>
#include <TDataXtd_Position.hxx>
#include <TCollection_AsciiString.hxx>

#include <Standard_Macro.hxx>

//=======================================================================
// function : DDataStd_SetConstraint
// purpose  : SetConstraint (DF,entry,keyword,geometrie/value[,geometrie])",
//=======================================================================
static Standard_Integer DDataStd_SetConstraint(Draw_Interpretor& di,
                                               Standard_Integer  nb,
                                               const char**      arg)
{
  if (nb < 5)
  {
    di << "usage: SetConstraint DF entry keyword geometrie [geometrie ...]\n";
    di << "or SetConstraint DF entry \"plane\" geometrie - to set plane for existing constraint\n";
    di << "or SetConstraint DF entry \"value\" value - to set value for existing constraint\n";
    return 1;
  }

  Handle(TDF_Data) DF;
  if (!DDF::GetDF(arg[1], DF))
    return 1;

  TDF_Label L;
  if (!DDF::FindLabel(DF, arg[2], L))
    return 1;

  TDataXtd_ConstraintEnum aCT;
  const char*             aT = arg[3];

  if (strcmp(aT, "plane") == 0)
  {
    Handle(TDataXtd_Constraint) C;
    if (!L.FindAttribute(TDataXtd_Constraint::GetID(), C))
      return 1;

    TDF_Label aLab;
    if (!DDF::FindLabel(DF, arg[4], aLab))
      return 1;
    Handle(TNaming_NamedShape) aSh;
    if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aSh))
    {
      C->SetPlane(aSh);
    }
  }
  else if (strcmp(aT, "value") == 0)
  {
    Handle(TDataXtd_Constraint) C;
    if (!L.FindAttribute(TDataXtd_Constraint::GetID(), C))
      return 1;

    TDF_Label aLab;
    if (!DDF::FindLabel(DF, arg[4], aLab))
      return 1;
    Handle(TDataStd_Real) aR;
    if (aLab.FindAttribute(TDataStd_Real::GetID(), aR))
    {
      C->SetValue(aR);
    }
  }
  else
  {
    Handle(TDataXtd_Constraint) C = TDataXtd_Constraint::Set(L);

    // planar constraints
    if (strcmp(aT, "rad") == 0)
      aCT = TDataXtd_RADIUS;
    else if (strcmp(aT, "dia") == 0)
      aCT = TDataXtd_DIAMETER;
    else if (strcmp(aT, "minr") == 0)
      aCT = TDataXtd_MINOR_RADIUS;
    else if (strcmp(aT, "majr") == 0)
      aCT = TDataXtd_MAJOR_RADIUS;
    else if (strcmp(aT, "tan") == 0)
      aCT = TDataXtd_TANGENT;
    else if (strcmp(aT, "par") == 0)
      aCT = TDataXtd_PARALLEL;
    else if (strcmp(aT, "perp") == 0)
      aCT = TDataXtd_PERPENDICULAR;
    else if (strcmp(aT, "concentric") == 0)
      aCT = TDataXtd_CONCENTRIC;
    else if (strcmp(aT, "equal") == 0)
      aCT = TDataXtd_COINCIDENT;
    else if (strcmp(aT, "dist") == 0)
      aCT = TDataXtd_DISTANCE;
    else if (strcmp(aT, "angle") == 0)
      aCT = TDataXtd_ANGLE;
    else if (strcmp(aT, "eqrad") == 0)
      aCT = TDataXtd_EQUAL_RADIUS;
    else if (strcmp(aT, "symm") == 0)
      aCT = TDataXtd_SYMMETRY;
    else if (strcmp(aT, "midp") == 0)
      aCT = TDataXtd_MIDPOINT;
    else if (strcmp(aT, "eqdist") == 0)
      aCT = TDataXtd_EQUAL_DISTANCE;
    else if (strcmp(aT, "fix") == 0)
      aCT = TDataXtd_FIX;
    else if (strcmp(aT, "rigid") == 0)
      aCT = TDataXtd_RIGID;
    // placement constraints
    else if (strcmp(aT, "from") == 0)
      aCT = TDataXtd_FROM;
    else if (strcmp(aT, "axis") == 0)
      aCT = TDataXtd_AXIS;
    else if (strcmp(aT, "mate") == 0)
      aCT = TDataXtd_MATE;
    else if (strcmp(aT, "alignf") == 0)
      aCT = TDataXtd_ALIGN_FACES;
    else if (strcmp(aT, "aligna") == 0)
      aCT = TDataXtd_ALIGN_AXES;
    else if (strcmp(aT, "axesa") == 0)
      aCT = TDataXtd_AXES_ANGLE;
    else if (strcmp(aT, "facesa") == 0)
      aCT = TDataXtd_FACES_ANGLE;
    else if (strcmp(aT, "round") == 0)
      aCT = TDataXtd_ROUND;
    else if (strcmp(aT, "offset") == 0)
      aCT = TDataXtd_OFFSET;
    else
    {
      di << "DDataStd_SetConstraint : unknown type, must be one of:\n";
      di << "rad/dia/minr/majr/tan/par/perp/concentric/equal/dist/angle/eqrad/symm/midp/\n";
      di << "eqdist/fix/rigid or from/axis/mate/alignf/aligna/axesa/facesa/round/offset\n";
      di << "or plane/value\n";
      return 1;
    }

    // set type
    C->SetType(aCT);

    // retrieve and set geometries
    Standard_Integer           i = 1, nbSh = nb - 4;
    Handle(TNaming_NamedShape) aSh;
    TDF_Label                  aLab;

    for (i = 1; i <= nbSh; i++)
    {
      if (!DDF::FindLabel(DF, arg[i + 3], aLab))
        return 1;
      if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aSh))
      {
        C->SetGeometry(i, aSh);
      }
    }
  }
  return 0;
}

//=======================================================================
// function : DDataStd_GetConstraint
// purpose  : GetConstraints (document, label)
//=======================================================================
static Standard_Integer DDataStd_GetConstraint(Draw_Interpretor& di,
                                               Standard_Integer  nb,
                                               const char**      arg)
{
  Handle(TDataXtd_Constraint) CTR;
  if (nb == 3)
  {
    Handle(TDF_Data) DF;
    TDF_Label        L;
    if (!DDF::GetDF(arg[1], DF))
      return 1;
    if (!DDF::FindLabel(DF, arg[2], L))
      return 1;
    if (L.FindAttribute(TDataXtd_Constraint::GetID(), CTR))
    {
      Standard_SStream aStream;
      DDataStd::DumpConstraint(CTR, aStream);
      di << aStream;
    }
    else
    {
      TDF_ChildIterator it(L, Standard_True);
      for (; it.More(); it.Next())
      {
        const TDF_Label& current = it.Value();
        if (current.FindAttribute(TDataXtd_Constraint::GetID(), CTR))
        {
          Standard_SStream aStream;
          DDataStd::DumpConstraint(CTR, aStream);
          di << aStream;
        }
      }
    }
    return 0;
  }
  di << "DDataStd_GetConstraint : Error : not done\n";
  return 1;
}

//=======================================================================
// function : DDataStd_SetPattern
// purpose  : SetPattern
// (DF,entry,signature,NSentry[realEntry,intEntry[,NSentry,realEntry,intEntry]])
//=======================================================================
static Standard_Integer DDataStd_SetPattern(Draw_Interpretor& di,
                                            Standard_Integer  nb,
                                            const char**      arg)
{
  if (nb < 5)
  {
    di << "usage: SetPattern "
          "(DF,entry,signature,NSentry[realEntry,intEntry[,NSentry,realEntry,intEntry]])\n";
    return 1;
  }

  Handle(TDF_Data) DF;
  if (!DDF::GetDF(arg[1], DF))
    return 1;

  TDF_Label L;
  if (!DDF::FindLabel(DF, arg[2], L))
    return 1;

  Handle(TDataXtd_PatternStd) aP = TDataXtd_PatternStd::Set(L);

  // set signature
  Standard_Integer signature = Draw::Atoi(arg[3]);
  aP->Signature(signature);

  TDF_Label                  aLab;
  Handle(TNaming_NamedShape) TNS;
  Handle(TDataStd_Real)      TReal;
  Handle(TDataStd_Integer)   TInt;

  // set other parameters
  if (signature < 5)
  {
    if (nb < 7)
    {
      di << "usage:\n";
      di << "SetPattern (DF,entry,signature<=2,NSentry,realEntry,intEntry)\n";
      di << "SetPattern "
            "(DF,entry,2<signature<5,NSentry,realEntry,intEntry,NSentry,realEntry,intEntry)\n";
      return 1;
    }

    // NSentry
    if (!DDF::FindLabel(DF, arg[4], aLab))
      return 1;
    if (aLab.FindAttribute(TNaming_NamedShape::GetID(), TNS))
    {
      aP->Axis1(TNS);
    }

    // realEntry
    if (!DDF::FindLabel(DF, arg[5], aLab))
      return 1;
    if (aLab.FindAttribute(TDataStd_Real::GetID(), TReal))
    {
      aP->Value1(TReal);
    }

    // intEntry
    if (!DDF::FindLabel(DF, arg[6], aLab))
      return 1;
    if (aLab.FindAttribute(TDataStd_Integer::GetID(), TInt))
    {
      aP->NbInstances1(TInt);
    }

    if (signature > 2)
    {
      if (nb < 10)
      {
        di << "usage:\n";
        di << "SetPattern "
              "(DF,entry,2<signature<5,NSentry,realEntry,intEntry,NSentry,realEntry,intEntry)\n";
        return 1;
      }

      // NSentry
      if (!DDF::FindLabel(DF, arg[7], aLab))
        return 1;
      if (aLab.FindAttribute(TNaming_NamedShape::GetID(), TNS))
      {
        aP->Axis2(TNS);
      }

      // realEntry
      if (!DDF::FindLabel(DF, arg[8], aLab))
        return 1;
      if (aLab.FindAttribute(TDataStd_Real::GetID(), TReal))
      {
        aP->Value2(TReal);
      }

      // intEntry
      if (!DDF::FindLabel(DF, arg[9], aLab))
        return 1;
      if (aLab.FindAttribute(TDataStd_Integer::GetID(), TInt))
      {
        aP->NbInstances2(TInt);
      }
    }
  }
  else
  {
    if (nb > 5)
    {
      di << "usage: SetPattern (DF,entry,signature>=5,NSentry)\n";
      return 1;
    }

    if (!DDF::FindLabel(DF, arg[4], aLab))
      return 1;
    if (aLab.FindAttribute(TNaming_NamedShape::GetID(), TNS))
    {
      aP->Mirror(TNS);
    }
  }

  return 0;
}

//=======================================================================
// function : DDataStd_DumpPattern
// purpose  : DumpPattern (DF, entry)
//=======================================================================
static Standard_Integer DDataStd_DumpPattern(Draw_Interpretor& di,
                                             Standard_Integer  nb,
                                             const char**      arg)
{
  Handle(TDataXtd_PatternStd) CTR;
  if (nb == 3)
  {
    Handle(TDF_Data) DF;
    TDF_Label        L;
    if (!DDF::GetDF(arg[1], DF))
      return 1;
    if (!DDF::FindLabel(DF, arg[2], L))
      return 1;
    if (L.FindAttribute(TDataXtd_PatternStd::GetID(), CTR))
    {
      //      Standard_SStream aStream;
      //      CTR->Dump(aStream);
      //      aStream << std::ends;
      //      di << aStream.rdbuf()->str();

      TCollection_AsciiString S;
      TDF_Tool::Entry(CTR->Label(), S);
      di << S.ToCString() << " signature = " << CTR->Signature();

      if (!CTR->Axis1().IsNull())
      {
        TDF_Tool::Entry(CTR->Axis1()->Label(), S);
        di << " Axis1 (" << S.ToCString() << ")";
      }

      if (!CTR->Value1().IsNull())
      {
        TDF_Tool::Entry(CTR->Value1()->Label(), S);
        di << " Val1 (" << S.ToCString() << ")";
      }

      if (!CTR->NbInstances1().IsNull())
      {
        TDF_Tool::Entry(CTR->NbInstances1()->Label(), S);
        di << " NbIns1 (" << S.ToCString() << ")";
      }

      if (!CTR->Axis2().IsNull())
      {
        TDF_Tool::Entry(CTR->Axis2()->Label(), S);
        di << " Axis2 (" << S.ToCString() << ")";
      }

      if (!CTR->Value2().IsNull())
      {
        TDF_Tool::Entry(CTR->Value2()->Label(), S);
        di << " Val2 (" << S.ToCString() << ")";
      }

      if (!CTR->NbInstances2().IsNull())
      {
        TDF_Tool::Entry(CTR->NbInstances2()->Label(), S);
        di << " NbIns2 (" << S.ToCString() << ")";
      }

      if (!CTR->Mirror().IsNull())
      {
        TDF_Tool::Entry(CTR->Mirror()->Label(), S);
        di << " Mirror (" << S.ToCString() << ")";
      }
    }
    else
    {
      TDF_ChildIterator it(L, Standard_True);
      for (; it.More(); it.Next())
      {
        const TDF_Label& current = it.Value();
        if (current.FindAttribute(TDataXtd_PatternStd::GetID(), CTR))
        {
          Standard_SStream aStream;
          //          DDataStd::DumpPattern (CTR,aStream);
          CTR->Dump(aStream);
          di << aStream;
        }
      }
    }
    return 0;
  }
  di << "DDataStd_DumpPattern : Error : not done\n";
  return 1;
}

//=======================================================================
// function : DDataStd_SetPosition
// purpose  : SetPosition (DF, entry, X, Y, Z)
//=======================================================================
static Standard_Integer DDataStd_SetPosition(Draw_Interpretor& di,
                                             Standard_Integer  nb,
                                             const char**      arg)
{
  if (nb == 6)
  {
    Handle(TDF_Data) DF;
    if (!DDF::GetDF(arg[1], DF))
      return 1;
    TDF_Label L;
    DDF::AddLabel(DF, arg[2], L);

    Standard_Real X = Draw::Atof(arg[3]), Y = Draw::Atof(arg[4]), Z = Draw::Atof(arg[5]);
    gp_Pnt        aPos(X, Y, Z);

    TDataXtd_Position::Set(L, aPos);
    return 0;
  }
  di << "Usage: SetPosition (DF, entry, X, Y, Z)\n";
  return 1;
}

//=======================================================================
// function : DDataStd_GetPosition
// purpose  : GetPosition (DF, entry, X(out), Y(out), Z(out))
//=======================================================================
static Standard_Integer DDataStd_GetPosition(Draw_Interpretor& di,
                                             Standard_Integer  nb,
                                             const char**      arg)
{
  if (nb == 6)
  {
    Handle(TDF_Data) DF;
    if (!DDF::GetDF(arg[1], DF))
      return 1;
    TDF_Label L;
    DDF::AddLabel(DF, arg[2], L);

    gp_Pnt aPos;
    if (!TDataXtd_Position::Get(L, aPos))
    {
      di << "There is no TDataStd_Position attribute on this label\n";
      return -1;
    }

    Draw::Set(arg[3], TCollection_AsciiString(aPos.X()).ToCString());
    Draw::Set(arg[4], TCollection_AsciiString(aPos.Y()).ToCString());
    Draw::Set(arg[5], TCollection_AsciiString(aPos.Z()).ToCString());
    return 0;
  }
  di << "Usage: GetPosition (DF, entry, X(out), Y(out), Z(out))\n";
  return 1;
}

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

void DDataStd::ConstraintCommands(Draw_Interpretor& theCommands)

{
  static Standard_Boolean done = Standard_False;
  if (done)
    return;
  done          = Standard_True;
  const char* g = "DData : Standard Attribute Commands";

  theCommands.Add("SetConstraint",
                  "SetConstraint (DF,entry,keyword,geometrie/value[,geometrie])",
                  __FILE__,
                  DDataStd_SetConstraint,
                  g);

  theCommands.Add("GetConstraint",
                  "GetConstraint (DF, entry)",
                  __FILE__,
                  DDataStd_GetConstraint,
                  g);

  theCommands.Add(
    "SetPattern",
    "SetPattern (DF,entry,signature,NSentry[realEntry,intEntry[,NSentry,realEntry,intEntry]])",
    __FILE__,
    DDataStd_SetPattern,
    g);

  theCommands.Add("DumpPattern", "DumpPattern (DF, entry)", __FILE__, DDataStd_DumpPattern, g);

  theCommands.Add("SetPosition",
                  "SetPosition (DF, entry, X, Y, Z)",
                  __FILE__,
                  DDataStd_SetPosition,
                  g);

  theCommands.Add("GetPosition",
                  "GetPosition (DF, entry, X(out), Y(out), Z(out))",
                  __FILE__,
                  DDataStd_GetPosition,
                  g);
}
