// Created by: CKY / Contract Toubro-Larsen
// Copyright (c) 1993-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 <IGESData_DirChecker.hxx>
#include <IGESData_Dump.hxx>
#include <IGESData_IGESDumper.hxx>
#include <IGESData_IGESReaderData.hxx>
#include <IGESData_IGESWriter.hxx>
#include <IGESData_ParamReader.hxx>
#include <IGESDefs_AttributeDef.hxx>
#include <IGESDefs_HArray1OfHArray1OfTextDisplayTemplate.hxx>
#include <IGESDefs_ToolAttributeDef.hxx>
#include <IGESGraph_HArray1OfTextDisplayTemplate.hxx>
#include <IGESGraph_TextDisplayTemplate.hxx>
#include <Interface_Check.hxx>
#include <Interface_CopyTool.hxx>
#include <Interface_EntityIterator.hxx>
#include <Interface_HArray1OfHAsciiString.hxx>
#include <Interface_Macros.hxx>
#include <Interface_ShareTool.hxx>
#include <Message_Messenger.hxx>
#include <TCollection_HAsciiString.hxx>
#include <TColStd_HArray1OfInteger.hxx>
#include <TColStd_HArray1OfReal.hxx>
#include <TColStd_HArray1OfTransient.hxx>

#include <stdio.h>

IGESDefs_ToolAttributeDef::IGESDefs_ToolAttributeDef() {}

void IGESDefs_ToolAttributeDef::ReadOwnParams(const Handle(IGESDefs_AttributeDef)&   ent,
                                              const Handle(IGESData_IGESReaderData)& IR,
                                              IGESData_ParamReader&                  PR) const
{
  // Standard_Boolean st; //szv#4:S4163:12Mar99 moved down
  Handle(TCollection_HAsciiString)                       aName;
  Standard_Integer                                       aListType;
  Handle(TColStd_HArray1OfInteger)                       attrTypes;
  Handle(TColStd_HArray1OfInteger)                       attrValueDataTypes;
  Handle(TColStd_HArray1OfInteger)                       attrValueCounts;
  Handle(TColStd_HArray1OfTransient)                     attrValues;
  Handle(IGESDefs_HArray1OfHArray1OfTextDisplayTemplate) attrValuePointers;
  Standard_Integer                                       nbval;
  Standard_Integer                                       fn = ent->FormNumber();

  if (PR.DefinedElseSkip())
    // clang-format off
    PR.ReadText(PR.Current(), "Attribute Table Name", aName); //szv#4:S4163:12Mar99 `st=` not needed

  PR.ReadInteger(PR.Current(), "Attribute List Type", aListType); //szv#4:S4163:12Mar99 `st=` not needed
  // clang-format on

  Standard_Boolean st = PR.ReadInteger(PR.Current(), "Number of Attributes", nbval);
  if (st && nbval > 0)
  {
    attrTypes          = new TColStd_HArray1OfInteger(1, nbval);
    attrValueDataTypes = new TColStd_HArray1OfInteger(1, nbval);
    attrValueCounts    = new TColStd_HArray1OfInteger(1, nbval);
    if (fn > 0)
      attrValues = new TColStd_HArray1OfTransient(1, nbval);
    if (fn > 1)
      attrValuePointers = new IGESDefs_HArray1OfHArray1OfTextDisplayTemplate(1, nbval);
  }
  else
    PR.AddFail("Number of Attributes: Not Positive");

  if (!attrTypes.IsNull())
    for (Standard_Integer i = 1; i <= nbval; i++)
    {
      Standard_Integer attrType;
      Standard_Integer attrValueDataType;
      Standard_Integer avc;
      //  Value according type
      Handle(IGESGraph_HArray1OfTextDisplayTemplate) attrValuePointer;

      // st = PR.ReadInteger(PR.Current(), "Attribute Type", attrType); //szv#4:S4163:12Mar99 moved
      // in if
      if (PR.ReadInteger(PR.Current(), "Attribute Type", attrType))
        attrTypes->SetValue(i, attrType);

      st = PR.ReadInteger(PR.Current(), "Attribute Data Type", attrValueDataType);
      if (st)
        attrValueDataTypes->SetValue(i, attrValueDataType);

      if (PR.DefinedElseSkip())
        st = PR.ReadInteger(PR.Current(), "Attribute Value Count", avc);
      else
        avc = 1;

      if (st)
      {
        attrValueCounts->SetValue(i, avc);
        if (fn > 1)
          attrValuePointer = new IGESGraph_HArray1OfTextDisplayTemplate(1, avc);
      }

      if (!attrValues.IsNull())
        if (fn > 0)
        {
          Handle(TColStd_HArray1OfInteger)        attrInt;
          Handle(TColStd_HArray1OfReal)           attrReal;
          Handle(Interface_HArray1OfHAsciiString) attrStr;
          Handle(IGESData_HArray1OfIGESEntity)    attrEnt;
          switch (attrValueDataType)
          {
            case 1:
              attrInt = new TColStd_HArray1OfInteger(1, avc);
              attrValues->SetValue(i, attrInt);
              break;
            case 2:
              attrReal = new TColStd_HArray1OfReal(1, avc);
              attrValues->SetValue(i, attrReal);
              break;
            case 3:
              attrStr = new Interface_HArray1OfHAsciiString(1, avc);
              attrValues->SetValue(i, attrStr);
              break;
            case 4:
              attrEnt = new IGESData_HArray1OfIGESEntity(1, avc);
              attrValues->SetValue(i, attrEnt);
              break;
            case 6:
              attrInt = new TColStd_HArray1OfInteger(1, avc);
              attrValues->SetValue(i, attrInt);
              break;
            default:
              break;
          }
          for (Standard_Integer j = 1; j <= avc; j++)
          {
            switch (attrValueDataType)
            {
              case 0: {
                PR.SetCurrentNumber(PR.CurrentNumber() + 1); // passer
                ////			attrValue->SetValue(j, NULL);    par defaut
                break;
              }
              case 1: {
                Standard_Integer temp;
                // st = PR.ReadInteger(PR.Current(), "Attribute Value", temp); //szv#4:S4163:12Mar99
                // moved in if
                if (PR.ReadInteger(PR.Current(), "Attribute Value", temp))
                  attrInt->SetValue(j, temp);
              }
              break;
              case 2: {
                Standard_Real temp;
                // st = PR.ReadReal(PR.Current(), "Attribute Value", temp); //szv#4:S4163:12Mar99
                // moved in if
                if (PR.ReadReal(PR.Current(), "Attribute Value", temp))
                  attrReal->SetValue(j, temp);
              }
              break;
              case 3: {
                Handle(TCollection_HAsciiString) temp;
                // st = PR.ReadText(PR.Current(), "Attribute Value", temp); //szv#4:S4163:12Mar99
                // moved in if
                if (PR.ReadText(PR.Current(), "Attribute Value", temp))
                  attrStr->SetValue(j, temp);
              }
              break;
              case 4: {
                Handle(IGESData_IGESEntity) temp;
                // st = PR.ReadEntity(IR, PR.Current(), "Attribute Value", temp);
                // //szv#4:S4163:12Mar99 moved in if
                if (PR.ReadEntity(IR, PR.Current(), "Attribute Value", temp))
                  attrEnt->SetValue(j, temp);
              }
              break;
              case 5:
                PR.SetCurrentNumber(PR.CurrentNumber() + 1); // skip
                break;
              case 6: {
                Standard_Boolean temp;
                // st = PR.ReadBoolean(PR.Current(), "Attribute Value", temp); //szv#4:S4163:12Mar99
                // moved in if
                if (PR.ReadBoolean(PR.Current(), "Attribute Value", temp))
                  attrInt->SetValue(j, (temp ? 1 : 0));
              }
              break;
            }
            if (fn == 2)
            {
              Handle(IGESGraph_TextDisplayTemplate) tempText;
              // st = PR.ReadEntity(IR,PR.Current(),"Attribute Val. Pointer",
              // STANDARD_TYPE(IGESGraph_TextDisplayTemplate), tempText); //szv#4:S4163:12Mar99
              // moved in if
              if (PR.ReadEntity(IR,
                                PR.Current(),
                                "Attribute Val. Pointer",
                                STANDARD_TYPE(IGESGraph_TextDisplayTemplate),
                                tempText))
                attrValuePointer->SetValue(j, tempText);
            }
          }
          if (fn == 2)
            attrValuePointers->SetValue(i, attrValuePointer);
        }
    }

  DirChecker(ent).CheckTypeAndForm(PR.CCheck(), ent);
  ent->Init(aName,
            aListType,
            attrTypes,
            attrValueDataTypes,
            attrValueCounts,
            attrValues,
            attrValuePointers);
}

void IGESDefs_ToolAttributeDef::WriteOwnParams(const Handle(IGESDefs_AttributeDef)& ent,
                                               IGESData_IGESWriter&                 IW) const
{
  if (ent->HasTableName())
    IW.Send(ent->TableName());
  else
    IW.SendVoid();
  IW.Send(ent->ListType());
  Standard_Integer upper = ent->NbAttributes();
  IW.Send(upper);

  for (Standard_Integer i = 1; i <= upper; i++)
  {
    Standard_Integer check = ent->AttributeValueDataType(i);
    Standard_Integer count = ent->AttributeValueCount(i);
    IW.Send(ent->AttributeType(i));
    IW.Send(check);
    IW.Send(count);
    if (ent->FormNumber() > 0)
    {
      for (Standard_Integer j = 1; j <= count; j++)
      {
        switch (check)
        {
          case 0:
            IW.SendVoid();
            break;
          case 1:
            IW.Send(ent->AttributeAsInteger(i, j));
            break;
          case 2:
            IW.Send(ent->AttributeAsReal(i, j));
            break;
          case 3:
            IW.Send(ent->AttributeAsString(i, j));
            break;
          case 4:
            IW.Send(ent->AttributeAsEntity(i, j));
            break;
          case 5:
            IW.SendVoid();
            break;
          case 6:
            IW.SendBoolean(ent->AttributeAsLogical(i, j));
            break;
          default:
            break;
        }
        if (ent->FormNumber() == 2)
          IW.Send(ent->AttributeTextDisplay(i, j));
      }
    }
  }
}

void IGESDefs_ToolAttributeDef::OwnShared(const Handle(IGESDefs_AttributeDef)& ent,
                                          Interface_EntityIterator&            iter) const
{
  Standard_Integer upper = ent->NbAttributes();
  for (Standard_Integer i = 1; i <= upper; i++)
  {
    Standard_Integer check = ent->AttributeValueDataType(i);
    Standard_Integer count = ent->AttributeValueCount(i);
    if (ent->FormNumber() > 0)
    {
      for (Standard_Integer j = 1; j <= count; j++)
      {
        if (check == 4)
          iter.GetOneItem(ent->AttributeAsEntity(i, j));
        if (ent->FormNumber() == 2)
          iter.GetOneItem(ent->AttributeTextDisplay(i, j));
      }
    }
  }
}

void IGESDefs_ToolAttributeDef::OwnCopy(const Handle(IGESDefs_AttributeDef)& another,
                                        const Handle(IGESDefs_AttributeDef)& ent,
                                        Interface_CopyTool&                  TC) const
{
  Handle(TCollection_HAsciiString) aName;
  if (!another->TableName().IsNull())
    aName = new TCollection_HAsciiString(another->TableName());
  Standard_Integer aListType = another->ListType();

  Handle(TColStd_HArray1OfInteger)                       attrTypes;
  Handle(TColStd_HArray1OfInteger)                       attrValueDataTypes;
  Handle(TColStd_HArray1OfInteger)                       attrValueCounts;
  Handle(TColStd_HArray1OfTransient)                     attrValues;
  Handle(IGESDefs_HArray1OfHArray1OfTextDisplayTemplate) attrValuePointers;
  Standard_Integer                                       nbval = another->NbAttributes();

  attrTypes          = new TColStd_HArray1OfInteger(1, nbval);
  attrValueDataTypes = new TColStd_HArray1OfInteger(1, nbval);
  attrValueCounts    = new TColStd_HArray1OfInteger(1, nbval);
  if (another->HasValues())
    attrValues = new TColStd_HArray1OfTransient(1, nbval);
  if (another->HasTextDisplay())
    attrValuePointers = new IGESDefs_HArray1OfHArray1OfTextDisplayTemplate(1, nbval);

  for (Standard_Integer i = 1; i <= nbval; i++)
  {
    Standard_Integer attrType = another->AttributeType(i);
    attrTypes->SetValue(i, attrType);
    Standard_Integer attrValueDataType = another->AttributeValueDataType(i);
    attrValueDataTypes->SetValue(i, attrValueDataType);
    Standard_Integer avc = another->AttributeValueCount(i);
    attrValueCounts->SetValue(i, avc);
    Handle(IGESGraph_HArray1OfTextDisplayTemplate) attrValuePointer;

    if (another->HasTextDisplay())
      attrValuePointer = new IGESGraph_HArray1OfTextDisplayTemplate(1, avc);

    if (another->HasValues())
    {
      Handle(TColStd_HArray1OfInteger)        attrInt;
      Handle(TColStd_HArray1OfReal)           attrReal;
      Handle(Interface_HArray1OfHAsciiString) attrStr;
      Handle(IGESData_HArray1OfIGESEntity)    attrEnt;
      switch (attrValueDataType)
      {
        case 1:
          attrInt = new TColStd_HArray1OfInteger(1, avc);
          attrValues->SetValue(i, attrInt);
          break;
        case 2:
          attrReal = new TColStd_HArray1OfReal(1, avc);
          attrValues->SetValue(i, attrReal);
          break;
        case 3:
          attrStr = new Interface_HArray1OfHAsciiString(1, avc);
          attrValues->SetValue(i, attrStr);
          break;
        case 4:
          attrEnt = new IGESData_HArray1OfIGESEntity(1, avc);
          attrValues->SetValue(i, attrEnt);
          break;
        case 6:
          attrInt = new TColStd_HArray1OfInteger(1, avc);
          attrValues->SetValue(i, attrInt);
          break;
        default:
          break;
      }
      for (Standard_Integer j = 1; j <= avc; j++)
      {
        switch (attrValueDataType)
        {
          case 0:
            break;
          case 1:
            attrInt->SetValue(j, another->AttributeAsInteger(i, j));
            break;
          case 2:
            attrReal->SetValue(j, another->AttributeAsReal(i, j));
            break;
          case 3:
            attrStr->SetValue(j, new TCollection_HAsciiString(another->AttributeAsString(i, j)));
            break;
          case 4: {
            DeclareAndCast(IGESData_IGESEntity,
                           Ent,
                           TC.Transferred(another->AttributeAsEntity(i, j)));
            attrEnt->SetValue(j, Ent);
          }
          break;
          case 5:
            break;
          case 6:
            attrInt->SetValue(j, (another->AttributeAsLogical(i, j) ? 1 : 0));
            break;
          default:
            break;
        }
        if (another->HasTextDisplay())
        {
          DeclareAndCast(IGESGraph_TextDisplayTemplate,
                         temptext,
                         TC.Transferred(another->AttributeTextDisplay(i, j)));
          attrValuePointer->SetValue(j, temptext);
        }
      }
      if (another->HasTextDisplay())
        attrValuePointers->SetValue(i, attrValuePointer);
    }
  }
  ent->Init(aName,
            aListType,
            attrTypes,
            attrValueDataTypes,
            attrValueCounts,
            attrValues,
            attrValuePointers);
}

IGESData_DirChecker IGESDefs_ToolAttributeDef::DirChecker(
  const Handle(IGESDefs_AttributeDef)& /* ent */) const
{
  IGESData_DirChecker DC(322, 0, 2);
  DC.Structure(IGESData_DefVoid);
  DC.LineFont(IGESData_DefAny);
  DC.LineWeight(IGESData_DefValue);
  DC.Color(IGESData_DefAny);
  DC.BlankStatusIgnored();
  DC.SubordinateStatusRequired(0);
  DC.UseFlagRequired(2);
  DC.GraphicsIgnored(1);
  return DC;
}

void IGESDefs_ToolAttributeDef::OwnCheck(const Handle(IGESDefs_AttributeDef)& ent,
                                         const Interface_ShareTool&,
                                         Handle(Interface_Check)& ach) const
{
  Standard_Integer nb = ent->NbAttributes();
  Standard_Integer fn = ent->FormNumber();
  for (Standard_Integer i = 1; i <= nb; i++)
  {
    char mess[80];
    if (ent->AttributeType(i) < 0 || ent->AttributeType(i) > 9999)
    {
      sprintf(mess, "Attribute Type n0.%d not in <0 - 9999>", ent->AttributeType(i));
      ach->AddFail(mess);
    }
    Standard_Integer aty = ent->AttributeValueDataType(i);
    if (aty < 0 || aty > 6)
    {
      sprintf(mess, "Attribute Value Data Type n0.%d not in <0 - 6>", aty);
      ach->AddFail(mess);
    }
    if (ent->AttributeValueCount(i) <= 0)
      continue;
    Handle(Standard_Transient) list = ent->AttributeList(i);
    if (fn > 0 && ent.IsNull())
    {
      if (aty == 0 || aty == 5)
        continue;
      sprintf(mess, "Form Number > 0 and Attribute Value List n0.%d undefined", aty);
      ach->AddFail(mess);
      continue;
    }
    else if (fn == 0)
      continue;
    mess[0] = '\0';
    switch (aty)
    {
      case 1:
        if (!list->IsKind(STANDARD_TYPE(TColStd_HArray1OfInteger)))
        {
          sprintf(mess, "Attribute List n0.%d (Integers) badly defined", aty);
        }
        break;
      case 2:
        if (!list->IsKind(STANDARD_TYPE(TColStd_HArray1OfReal)))
        {
          sprintf(mess, "Attribute List n0.%d (Reals) badly defined", aty);
        }
        break;
      case 3:
        if (!list->IsKind(STANDARD_TYPE(Interface_HArray1OfHAsciiString)))
        {
          sprintf(mess, "Attribute List n0.%d (Strings) badly defined", aty);
        }
        break;
      case 4:
        if (!list->IsKind(STANDARD_TYPE(IGESData_HArray1OfIGESEntity)))
        {
          sprintf(mess, "Attribute List n0.%d (IGES Pointers) badly defined", aty);
        }
        break;
      case 6:
        if (!list->IsKind(STANDARD_TYPE(TColStd_HArray1OfInteger)))
        {
          sprintf(mess, "Attribute List n0.%d (Logicals i.e. Integers) badly defined", aty);
        }
        break;
      default:
        break;
    }
    if (mess[0] != '\0')
      ach->AddFail(mess);
  }
}

void IGESDefs_ToolAttributeDef::OwnDump(const Handle(IGESDefs_AttributeDef)& ent,
                                        const IGESData_IGESDumper&           dumper,
                                        Standard_OStream&                    S,
                                        const Standard_Integer               level) const
{
  Standard_Integer sublevel = (level > 4) ? 1 : 0;

  S << "IGESDefs_AttributeDef\n"
    << "Attribute Table Name: ";
  IGESData_DumpString(S, ent->TableName());
  S << "\n"
    << "Attribute List Type  : " << ent->ListType() << "\n"
    << "Number of Attributes : " << ent->NbAttributes() << "\n"
    << "Attribute Types :\n"
    << "Attribute Value Data Types :\n"
    << "Attribute Value Counts :\n";
  if (ent->HasValues())
    S << "Attribute Values :\n";
  if (ent->HasTextDisplay())
    S << "Attribute Value Entities :\n";
  IGESData_DumpVals(S, -level, 1, ent->NbAttributes(), ent->AttributeType);
  S << "\n";
  if (level > 4)
  {
    Standard_Integer upper = ent->NbAttributes();
    for (Standard_Integer i = 1; i <= upper; i++)
    {
      Standard_Integer avc = ent->AttributeValueCount(i);
      Standard_Integer typ = ent->AttributeValueDataType(i);
      S << "[" << i << "]:  "
        << "Attribute Type : " << ent->AttributeType(i) << "  "
        << "Value Data Type : " << typ;
      switch (typ)
      {
        case 0:
          S << "  (Void)";
          break;
        case 1:
          S << " : Integer ";
          break;
        case 2:
          S << " : Real    ";
          break;
        case 3:
          S << " : String  ";
          break;
        case 4:
          S << " : Entity  ";
          break;
        case 5:
          S << " (Not Used)";
          break;
        case 6:
          S << " : Logical ";
          break;
        default:
          break;
      }
      S << "   Count : " << avc << "\n";
      if (ent->HasValues())
      {
        if (level <= 5)
        {
          S << " [ content (Values) : ask level > 5 ]\n";
          continue;
        }
        for (Standard_Integer j = 1; j <= avc; j++)
        {
          S << "[" << j << "]: ";
          switch (ent->AttributeValueDataType(i))
          {
            case 0:
              S << "(Void) ";
              break;
            case 1:
              S << ent->AttributeAsInteger(i, j);
              break;
            case 2:
              S << ent->AttributeAsReal(i, j);
              break;
            case 3:
              IGESData_DumpString(S, ent->AttributeAsString(i, j));
              break;
            case 4:
              dumper.Dump(ent->AttributeAsEntity(i, j), S, level - 5);
              break;
            case 5:
              S << "(Not Used)";
              break;
            case 6:
              S << (ent->AttributeAsLogical(i, j) ? "True" : "False");
              break;
            default:
              break;
          }
          if (ent->HasTextDisplay())
          {
            S << "  Attribute Value Pointer : ";
            dumper.Dump(ent->AttributeTextDisplay(i, j), S, sublevel);
          }
          S << std::endl;
        }
      }
    }
  }
  S << std::endl;
}
