// $Source: /usr/local/SimSoft/Sfx3D/src/gsl/geometry.cpp,v $
// $Revision: 1.2 $
// $Author: baum $
// $Date: 2001/11/29 15:18:09 $
//
// Login name of the user who locked the revision
// $Locker:  $
// Tag name used to checkout the file
// $Name:  $
// State assigned to revision
// $State: Exp $
//
//
// $Log: geometry.cpp,v $
// Revision 1.2  2001/11/29 15:18:09  baum
// -Realzeitsteuerung eingebaut
// -Handsteuerung eingebaut
//

#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "DynArray.h"
#include "Messager.h"
#include "FileSys.h"
#include "Strings.h"
#include "IniFile.h"

#include "Vec3D.h"
#include "HMatrx3D.h"

#include "XGraph/AllPrims.h"
#include "XGraph/XGraph.h"

#include "VrmlPars.h"

#define _GEOMETRY_CPP
#include "modell.h"
#include "geometry.h"

//==================================================================
//              Implementation
//              for class TGBIdentity
//==================================================================

TGBIdentity::TGBIdentity (const TGBIdentity& id)
  : ObjTyp (id.ObjTyp), ObjVariant (id.ObjVariant)
  { }

TGBIdentity::TGBIdentity (unsigned typ, unsigned variant)
  : ObjTyp (typ), ObjVariant (variant)
  { }

TGBIdentity::~TGBIdentity ()
  { }

bool TGBIdentity::operator == (const TGBIdentity& id) {
  return (((ObjTyp == id.ObjTyp) && (ObjVariant == id.ObjVariant)) ? true : false);
}

bool TGBIdentity::operator != (const TGBIdentity& id) {
  return (((ObjTyp != id.ObjTyp) || (ObjVariant != id.ObjVariant)) ? true : false);
}

unsigned TGBIdentity::Typ () const {
  return ObjTyp;
}

unsigned TGBIdentity::Variant () const {
  return ObjVariant;
}

//==================================================================
//              Implementation
//              for class TGBPattern
//==================================================================

/*static*/ unsigned   TGBPattern::ClassRefCounter = 0;
/*static*/ Attribute* TGBPattern::ClassPermAttribute;
/*static*/ Attribute* TGBPattern::ClassTempAttribute;
/*static*/ Attribute* TGBPattern::ClassTextAttribute;

/*static*/ void TGBPattern::setup () {
  TGBPattern::ClassPermAttribute = MaterialAttribute::create ("machinegreen");
  TGBPattern::ClassPermAttribute->incRef ();
  TGBPattern::ClassTempAttribute = MaterialAttribute::create ("silver");
  TGBPattern::ClassTempAttribute->incRef ();
  TGBPattern::ClassTextAttribute = ColorAttribute::create ("black");
  TGBPattern::ClassTextAttribute->incRef ();
}

/*static*/ void TGBPattern::cleanup () {
  TGBPattern::ClassPermAttribute->dispose ();
  TGBPattern::ClassPermAttribute = NULL;
  TGBPattern::ClassTempAttribute->dispose ();
  TGBPattern::ClassTempAttribute = NULL;
  TGBPattern::ClassTextAttribute->dispose ();
  TGBPattern::ClassTextAttribute = NULL;
}

Pattern* TGBPattern::buildText (const Ustring& text,
                                const double& height, const double& thikness,
                                const Vec3D& pos) {
  Pattern* p;
  if ((p = Pattern::find (text.str ())) == NULL) {
    Primitive*   prim = Text::create (text.str (), height, thikness, pos);
    GeoPattern*    gp = GeoPattern::create (*prim, *ClassTextAttribute);
    p = Pattern::create (*gp);
    p->setName (text.str ());
  }
  return p;
}

// constructor
TGBPattern::TGBPattern (unsigned typ, unsigned variant)
  : ObjId (typ, variant),  ObjGeometries  (2),
    ObjNumberHeight (1.0), ObjNumberPos (),
    ObjSymbolHeight (1.0), ObjSymbolPos () {
  if (!(ClassRefCounter++)) {
    setup ();
  }
}

// destructor
TGBPattern::~TGBPattern () {
  while (ObjGeometries.Last ()) delete ObjGeometries.removeLast ();
  if (!(--ClassRefCounter)) {
    cleanup ();
  }
}

GeoObject* TGBPattern::MyGeometry () const {
  return ObjGeometries.First ();
}

const DynArray<GeoObject>& TGBPattern::AllGeometries () const {
  return ObjGeometries;
}

const TGBIdentity& TGBPattern::Id () const {
  return ObjId;
}

const double& TGBPattern::NumberHeight () const {
  return ObjNumberHeight;
}

const Vec3D&  TGBPattern::NumberPos    () const {
  return ObjNumberPos;
}

const double& TGBPattern::SymbolHeight () const {
  return ObjSymbolHeight;
}

const Vec3D&  TGBPattern::SymbolPos    () const {
  return ObjSymbolPos;
}

/*virtual*/ void TGBPattern::read  (TGBLib&) { }

void TGBPattern::readGeometry (TGBLib& tgbLib, int sentenceOffset, unsigned forWhom) {
  int number, primId;
  double x, y, z;
  Ustring objName;
  VrmlParser* p;

  GeoObject* obj = ObjGeometries.First ();
  Pattern* pat = Pattern::create ();
  obj->insert (*pat);

  InputFile *file (tgbLib.TGBFile ());
  SFXToken tok;

  Vec3D begin, end, v1, v2, v3;
  Angle bAngle, eAngle;

  GeoPattern    *gp;
  Primitive     *prim;

  Attribute *attr = (forWhom ? ClassPermAttribute : ClassTempAttribute);

  if (tok.findSentence (sentenceOffset + tgbLib.SegOffset (), *file)) {
    tok.nextToken (*file);
    number = atoi (tok ());

    for (int i = 0; i < number; i++) {
      tok.nextToken (*file);  // read sentenceNumber and forget it!!
      tok.nextToken (*file);
      primId = atoi (tok ());
      switch (primId) {
        case 1:                     // Line
          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          z = 0.0;
          begin = Vec3D (x, y, z);

          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          z = 0.0;
          end = Vec3D (x, y, z);
          
          if (begin == end) {
            Msg.Warning ("TGBPattern::readGeometry (...)",
                         "Primitive Line with null-lenght %d:%d",
                         sentenceOffset + tgbLib.SegOffset (), i + 1);
            break;
          }
          gp = GeoPattern::create (*(Line::create (begin, end)), *attr);
          pat->insert (*gp);
          break;

        case 2:                      // LineArc
          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          z = 0.0;
          begin = Vec3D (x, y, z);

          tok.nextToken (*file); z = atof (tok()); // now z is the radius!!

          tok.nextToken (*file); bAngle = Angle (atof (tok()));
          tok.nextToken (*file); eAngle = Angle (atof (tok()));

          if (!z) {
            Msg.Warning ("TGBPattern::readGeometry (...)",
                         "Primitive Arc with null-radius %d:%d", 
                         sentenceOffset + tgbLib.SegOffset (), i + 1);
            break;
          }
          prim = LineArc::create ( z, z, bAngle, eAngle, begin);
          gp = GeoPattern::create (*prim, *attr);
          pat->insert(*gp);
          break;

        case 3:
        case 10:                     // Rectangle 2 vectors
          tok.nextToken (*file);  x = atof (tok());
          tok.nextToken (*file);  y = atof (tok());
          tok.nextToken (*file);  z = atof (tok());
          begin = Vec3D (x, y, z);

          tok.nextToken (*file);  x = atof (tok());
          tok.nextToken (*file);  y = atof (tok());
          tok.nextToken (*file);  z = atof (tok());
          end = Vec3D (x, y, z);

          if (begin == end) {
            Msg.Warning ("TGBPattern::readGeometry (...)",
                         "Primitive Rect with null-size %d:%d", 
                         sentenceOffset + tgbLib.SegOffset (), i + 1);
            break;
          }
          gp = GeoPattern::create (*PlaneQuad::create (begin, end), *attr);
          pat->insert (*gp);
          break;

        case 11:                     // Rectangle 4 vectors
          tok.nextToken (*file);  x = atof (tok());
          tok.nextToken (*file);  y = atof (tok());
          tok.nextToken (*file);  z = atof (tok());
          begin = Vec3D (x, y, z);

          tok.nextToken (*file);  x = atof (tok());
          tok.nextToken (*file);  y = atof (tok());
          tok.nextToken (*file);  z = atof (tok());
          v1 = Vec3D (x, y, z);

          tok.nextToken (*file);  x = atof (tok());
          tok.nextToken (*file);  y = atof (tok());
          tok.nextToken (*file);  z = atof (tok());
          end = Vec3D (x, y, z);

          tok.nextToken (*file);  x = atof (tok());
          tok.nextToken (*file);  y = atof (tok());
          tok.nextToken (*file);  z = atof (tok());
          v2 = Vec3D (x, y, z);

          prim = PlaneQuad::create (begin, v1, end, v2);
          gp = GeoPattern::create (*prim, *attr);
          pat->insert (*gp);
          break;

        case 13:                     // Triangle
          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          begin = Vec3D (x, y, z);

          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          end = Vec3D (x, y, z);

          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          v1 = Vec3D (x, y, z);

          prim = Triangle::create (begin, end, v1);
          gp = GeoPattern::create (*prim, *attr);
          pat->insert (*gp);
          break;

        case 15:                     // PlaneArcSegment
          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          begin = Vec3D (x, y, z);

          tok.nextToken (*file); z = atof (tok()); // now z is the radius!!
          tok.nextToken (*file); y = atof (tok()); // now y is the distance!!

          tok.nextToken (*file); bAngle = Angle (atof (tok()));
          tok.nextToken (*file); eAngle = Angle (atof (tok()));

          if (!z) {
            Msg.Warning ("TGBPattern::readGeometry (...)",
                         "Primitive Disc with null-radius %d:%d", 
                         sentenceOffset + tgbLib.SegOffset (), i + 1);
            break;
          }
          prim = PlaneArc::create ( z, z, y, bAngle, eAngle, begin);
          gp = GeoPattern::create (*prim, *attr);
          pat->insert(*gp);
          break;

        case 17:                     // Text
          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          begin = Vec3D (x, y, z);

          tok.nextToken (*file); objName = tok (); // text
          tok.nextToken (*file); x = atof (tok()); // size
          tok.nextToken (*file); y = atof (tok()); // thickness

          gp = GeoPattern::create (*Text::create (objName.str (), x, y, begin), *attr);
          pat->insert (*gp);
          break;

        case 20:                     // Cube
          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          begin = Vec3D (x, y, z);

          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          end = Vec3D (x, y, z);

          if (begin == end) {
            Msg.Warning ("TGBPattern::readGeometry (...)",
                         "Primitive Cube with null-size %d:%d",
                         sentenceOffset + tgbLib.SegOffset (), i + 1);
            break;
          }
          gp = GeoPattern::create (*Cube::create (begin, end), *attr);
          pat->insert (*gp);
          break;

        case 21:                     // Cube with UpDirection
          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          begin = Vec3D (x, y, z);

          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          end = Vec3D (x, y, z);

          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          v1 = Vec3D (x, y, z);

          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          v2 = Vec3D (x, y, z);

          v3 = v2.cross (EX);
          if (!v3) v3 = EY;
          v3 = EX * rotHMatrx3D (v3, v2.angle (EX) - Angle (90.0));

          gp = GeoPattern::create (*Cube::create (begin, end), *attr, Location(v1, v3, v2));
          pat->insert (*gp);
          break;

        case 25:                     // Cylinder
          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          begin = Vec3D (x, y, z);

          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          end = Vec3D (x, y, z); // for the up-vec

          tok.nextToken (*file); y = atof (tok()); // now y is the radius!!
          tok.nextToken (*file); z = atof (tok()); // now z is the height!!

          if (!z || !y) {
            Msg.Warning ("TGBPattern::readGeometry (...)",
                         "Primitive Cylinder with null-size %d:%d", 
                         sentenceOffset + tgbLib.SegOffset (), i + 1);
            break;
          }
          v1 = end.cross (EX);
          if (!v1) v1 = EY;
          v2 = EX * rotHMatrx3D (v1, end.angle (EX) - Angle (90.0));
          gp = GeoPattern::create (*Cylinder::create (y, z), *attr,
                                   Location (begin, v2, end));
          pat->insert(*gp);
          break;

        case 26:                     // Tube
          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          begin = Vec3D (x, y, z);

          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          end = Vec3D (x, y, z);

          tok.nextToken (*file); x = atof (tok()); // now x is the radius!!
          tok.nextToken (*file); y = atof (tok()); // now y is the height!!
          tok.nextToken (*file); z = atof (tok()); // now z is the distance!!

          tok.nextToken (*file); bAngle = Angle (atof (tok()));
          tok.nextToken (*file); eAngle = Angle (atof (tok()));

	  if (!x || !y) {
            Msg.Warning ("TGBPattern::readGeometry (...)",
                         "Primitive Tube with null-size %d:%d",
                         sentenceOffset + tgbLib.SegOffset (), i + 1);
            break;
          }
          v1 = end.cross (EX);
          if (!v1) v1 = EY;
          v2 = EX * rotHMatrx3D (v1, end.angle (EX) - Angle (90.0));
          gp = GeoPattern::create (*Tube::create (x, x, y, z, bAngle, eAngle), *attr,
                                   Location (begin, v2, end));
          pat->insert(*gp);
          break;

        case 27:                     // Cone
          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          begin = Vec3D (x, y, z);

          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          end = Vec3D (x, y, z);

          tok.nextToken (*file); x = atof (tok()); // now x is the radius!!
          tok.nextToken (*file); y = atof (tok()); // now y is the height!!
          tok.nextToken (*file); z = atof (tok()); // now z is the dist!!

          if (!x || !y) {
            Msg.Warning ("TGBPattern::readGeometry (...)",
                         "Primitive Cone with null-size %d:%d", 
                         sentenceOffset + tgbLib.SegOffset (), i + 1);
            break;
          }
          v1 = end.cross (EX);
          if (!v1) v1 = EY;
          v2 = EX * rotHMatrx3D (v1, end.angle (EX) - Angle (90.0));
          gp = GeoPattern::create (*Cone::create (x, y, z), *attr,
                                   Location (begin, v2, end));
          pat->insert (*gp);
          break;

        case 28:                     // Sphere
          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
          tok.nextToken (*file); z = atof (tok());
          begin = Vec3D (x, y, z);

          tok.nextToken (*file); z = atof (tok()); // now z is the radius!!

          if (!z) {
            Msg.Warning ("TGBPattern::readGeometry (...)",
                         "Primitive Sphere with null-radius %d:%d", 
                         sentenceOffset + tgbLib.SegOffset (), i + 1);
            break;
          }
          gp = GeoPattern::create (*Sphere::create (z), *attr,
                                   Location (begin, EX, EZ));
          pat->insert(*gp);
          break;

        case 30:                     // SubPattern
          obj = new GeoObject ();
          ObjGeometries.append (*obj);
          pat = Pattern::create ();
          obj->insert (*pat);
          attr = (forWhom ? ClassPermAttribute : ClassTempAttribute);
          break;

        case 4:  // RGB-color-values
        case 40:
          tok.nextToken (*file);
          if (tok.isDouble ()) {
            x = atof (tok());
            tok.nextToken (*file); y = atof (tok());
            tok.nextToken (*file); z = atof (tok());
            attr = ColorAttribute::create (RGBAColor (x, y, z));
          }
          else
            attr = ColorAttribute::create (tok ());
          break;

        case 41: // material (only by name!!)
          tok.nextToken (*file);
          attr = MaterialAttribute::create (tok ());
          break;

        case 42: // texture (by file name!!)
          tok.nextToken (*file);
          objName = tgbLib.TexturesPath ();
	  
          objName += tok ();
          tok.nextToken (*file); x = atof (tok());
          tok.nextToken (*file); y = atof (tok());
	  cout << objName << endl;
          attr = TexAttribute::create (objName.str (), Vec2D (x, y), RGBAColor (0.8, 0.8, 0.8));
          break;

        case 50: // VRML-File
          tok.nextToken (*file);
          objName = tgbLib.VrmlPath ();
          objName += tok ();
          cout << objName << endl;
          p = new VrmlParser (objName);
          p->parse (*obj);
          break;

        default:
          break;
      }
    }
  }
  else
    Msg.Warning ("TGBPattern::readGeometry (...)", "Can't find GeometrySentence!!!");
}

void TGBPattern::readPositions (TGBLib& tgbLib, int sentenceOffset) {
  double x, y, z;

  InputFile *file (tgbLib.TGBFile ());
  SFXToken tok;

  if (tok.findSentence (sentenceOffset + tgbLib.NumPosOffset (), *file)) {
    tok.nextToken (*file);
    ObjNumberHeight = atof (tok ());

    tok.nextToken (*file);
    x = atof (tok());
    tok.nextToken (*file);
    y = atof (tok());
    z = 0.02;
    ObjNumberPos = Vec3D (x, y, z);
  }
  else
    Msg.Warning ("TGBPattern::readPositions (...)", "Can't find NumberSentence!!!");

  if (tok.findSentence (sentenceOffset + tgbLib.SymPosOffset (), *file)) {
    tok.nextToken (*file);
    ObjSymbolHeight = atof (tok ());

    tok.nextToken (*file);
    x = atof (tok());
    tok.nextToken (*file);
    y = atof (tok());
    z = 0.0;
    ObjSymbolPos = Vec3D (x, y, z);
  }
  else
    Msg.Warning ("TGBPattern::readPositions (...)", "Can't find SymbolSentence!!!");
}

void TGBPattern::readText     (TGBLib& /*tgbLib*/, int /*sentenceOffset*/) {
}

//==================================================================
//              Implementation
//              for class TGBPermPattern
//==================================================================

// constructor
TGBPermPattern::TGBPermPattern (TGBLib& tgbLib, unsigned typ, unsigned variant)
  : TGBPattern (typ, variant),
    ObjPalPositions (1),   ObjEntryPositions (1),
    ObjExitPositions (1) {
  read (tgbLib);
}

// destructor
TGBPermPattern::~TGBPermPattern() {
  while (ObjPalPositions.Count ())
    delete (ObjPalPositions.removeLast());
  while (ObjEntryPositions.Last ())
    delete (ObjEntryPositions.removeLast());
  while (ObjExitPositions.Last ())
    delete (ObjExitPositions.removeLast());
}

const DynArray<Vec3D>& TGBPermPattern::PalPositions   () const {
  return ObjPalPositions;
}

const DynArray<Vec3D>& TGBPermPattern::EntryPositions () const {
  return ObjEntryPositions;
}

const DynArray<Vec3D>& TGBPermPattern::ExitPositions  () const {
  return ObjExitPositions;
}

void TGBPermPattern::read (TGBLib& tgbLib) {
  int sentence = (ObjId.Typ     () * tgbLib.TypMulti ()) +
                 (ObjId.Variant () * tgbLib.VarMulti ()) + tgbLib.TypOffset();
  InputFile *file (tgbLib.TGBFile ());
  if (!file) {
    Msg.Warning ("TGBPermPattern::read (...)", "No valid tgb-file!!!");
    return;
  }
  SFXToken tok;

  if (tok.findSentence (sentence, *file)) {
    tok.nextToken (*file); // variant
    tok.nextToken (*file); // 0
    tok.nextToken (*file); // 0
    tok.nextToken (*file); // 0.000
    tok.nextToken (*file); // name

    GeoObject* obj = new GeoObject ();
//    obj->setName (tok());
    ObjGeometries.append (*obj);

    file->jump (100); // EOL

    readGeometry  (tgbLib, sentence, 1);
    readPositions (tgbLib, sentence);
    readIOPositions (tgbLib, sentence);
//    readText      (tgbLib, sentence);
  }
  else
    Msg.Warning ("TGBPermPattern::read (...)", "Can't find NameSentence!!!");
}

void TGBPermPattern::readIOPositions (TGBLib& tgbLib, int sentenceOffset) {
  double x, y, z;
  unsigned number;

  InputFile *file (tgbLib.TGBFile ());
  SFXToken tok;

  if (tok.findSentence (sentenceOffset + tgbLib.Info1Offset (), *file)) {
    tok.nextToken (*file);
    number = atoi (tok ());
    file->jump (100);
    if (number) {
      unsigned pack = (number / 4);
      tok.nextToken (*file);
      for (unsigned j = 0; j <= pack; j++) {
        unsigned i = 0;
        unsigned stop = (number < 4) ? number : 4;
        for (; i < stop; i++) {
          tok.nextToken (*file);
          x = atof (tok ());
          tok.nextToken (*file);
          y = atof (tok ());
          tok.nextToken (*file);
          z = atof (tok ());
          ObjPalPositions.append (*(new Vec3D (x, y, z)));
        }
        number -= 4;
        file->jump (100);
      }
    }
  }
  else
    Msg.Warning ("TGBPermPattern::readIOPositions (...)", "Can't find PalSentence!!!");

  if (tok.findSentence (sentenceOffset + tgbLib.Info2Offset (), *file)) {
    tok.nextToken (*file);
    number = atoi (tok ());
    file->jump (100);
    if (number) tok.nextToken (*file);
    for (unsigned i = 0; i < number; i++) {
      tok.nextToken (*file);
      x = atof (tok());
      tok.nextToken (*file);
      y = atof (tok());
      z = 0.0;
      ObjEntryPositions.append (*(new Vec3D (x, y, z)));
    }
  }
  else
    Msg.Warning ("TGBPermPattern::readPositions (...)", "Can't find EntrySentence!!!");

  if (tok.findSentence (sentenceOffset + tgbLib.Info3Offset (), *file)) {
    tok.nextToken (*file);
    number = atoi (tok ());
    file->jump (100);
    if (number) tok.nextToken (*file);
    for (unsigned i = 0; i < number; i++) {
      tok.nextToken (*file);
      x = atof (tok());
      tok.nextToken (*file);
      y = atof (tok());
      z = 0.0;
      ObjExitPositions.append (*(new Vec3D (x, y, z)));
    }
  }
  else
    Msg.Warning ("TGBPermPattern::readPositions (...)", "Can't find ExitSentence!!!");
}

//==================================================================
//              Implementation
//              for class TGBTempPattern
//==================================================================

// constructor
TGBTempPattern::TGBTempPattern (TGBLib& tgbLib, unsigned typ, unsigned variant)
  : TGBPattern (typ, variant) {
  read (tgbLib);
}

// destructor
TGBTempPattern::~TGBTempPattern()
 { }

void TGBTempPattern::read (TGBLib& tgbLib) {
  int sentence = (ObjId.Typ     () * tgbLib.TypMulti ()) +
                 (ObjId.Variant () * tgbLib.VarMulti ()) + tgbLib.TypOffset();
  InputFile *file (tgbLib.TGBFile ());
  if (!file) {
    Msg.Warning ("TGBTempPattern::read (...)", "No valid tgb-file!!!");
    return;
  }
  SFXToken tok;

  if (tok.findSentence (sentence, *file)) {
    tok.nextToken (*file); // variant
    tok.nextToken (*file); // 0
    tok.nextToken (*file); // 0
    tok.nextToken (*file); // 0.000
    tok.nextToken (*file); // name

    GeoObject* obj = new GeoObject ();
//    obj->setName (tok());
    ObjGeometries.append (*obj);

    file->jump (100); // EOL

    readGeometry  (tgbLib, sentence, 0);
    readPositions (tgbLib, sentence);
    readLogicGeometry (tgbLib, sentence);
//    readText      (tgbLib, sentence);
  }
  else
    Msg.Warning ("TGBTempPattern::read (...)", "Can't find NameSentence!!!");
}

void TGBTempPattern::readLogicGeometry (TGBLib& tgbLib, int sentenceOffset) {
  double x, y, z;
  Primitive     *prim;
  GeoPattern    *gp;

  InputFile *file (tgbLib.TGBFile ());
  SFXToken tok;

  if (tok.findSentence (sentenceOffset + tgbLib.Info2Offset (), *file)) {
    tok.nextToken (*file);
    x = atof (tok());
    tok.nextToken (*file);
    y = atof (tok());
    tok.nextToken (*file);
    z = atof (tok());
    file->jump (100);
    Vec3D vec (x, y, z);

    if (vec) {
      vec *= 0.5;
      prim = LogicWrap::create (-vec, vec);
      gp = GeoPattern::create (*prim, *ClassTempAttribute);
      ObjGeometries.First ()->PattArray ().First ()->insert (*gp);
    }
  }
  else
    Msg.Warning ("TGBTempPattern::readLogicGeometry (...)", "Can't find LogicGeometrySentence!!!");
}

//==================================================================
//              Implementation
//              for class TGBLib
//==================================================================

TGBLib::TGBLib ()
  : ObjIsPreparedForPerms (false), ObjIsPreparedForTemps (false),
    ObjHasToBuildNumbers  (true),
    ObjTypOffset    (20), ObjTypMulti     (1000), ObjVarMulti (20),
    ObjSegOffset    (2),  ObjNumPosOffset (4),    ObjSymPosOffset (5),
    ObjTextOffset   (16), ObjInfo1Offset  (7),    ObjInfo2Offset (10),
    ObjInfo3Offset  (12), ObjInfo4Offset  (10),
    ObjPermFileName (),   ObjTempFileName (),
    ObjDefaultPermFileName (),  ObjDefaultTempFileName (),
    ObjTexturesPath (),   ObjVrmlPath     (),     
    ObjDefaultTexturesPath (), ObjDefaultVrmlPath (),     
    ObjFile (NULL),   ObjPermPattern  (30), ObjTempPattern  (3) {

  Ustring exePath (FileSystem::ExePath ());
  const char separator = FileSystem::PathSeparator ();
  //---rudi---20.03.2002
  // Dem exePath wird das Verzeichnis zugewiesen, das in der 
  // Systemvariable SFX3D zugewiesen ist
  char* p = getenv ("SFX3D");  
  if (p != NULL) {
  	exePath = Ustring (p) + separator;
  	dprintf("Sfx3D-Verzeichnis: %s\n",exePath.str());
  }
  //---rudi---20.03.2002
  	
  
  ObjDefaultPermFileName = (exePath + ".." + separator + \
  	"tgb" + separator + "tgb_tgb.3bb").str ();
  ObjDefaultTempFileName = (exePath + ".." + separator + \
  	"tgb" + separator + "tgb_tgb.3pp").str ();
  ObjDefaultTexturesPath = (exePath + ".." + separator + \
  	"Textures" + separator).str();   
  ObjDefaultVrmlPath     = (exePath + separator + ".." + separator + \
  	"tgb" + separator + "vrml" + separator ).str();
  
  /**< Folgende Zeilen sind dazu da, um die Pfadangabe ohne zwei Punkte zu speichern*/
  ObjDefaultPermFileName = FileSystem::FullPathName (ObjDefaultPermFileName.str());
  ObjDefaultTempFileName = FileSystem::FullPathName (ObjDefaultTempFileName.str());
  ObjDefaultTexturesPath = FileSystem::FullPathName (ObjDefaultTexturesPath.str());
  ObjDefaultVrmlPath = FileSystem::FullPathName (ObjDefaultVrmlPath.str());

  ObjPermFileName = IniFile::DefIniFile.readString ("TGB", "PermTGBFile",ObjDefaultPermFileName.str());
  ObjTempFileName = IniFile::DefIniFile.readString ("TGB", "TempTGBFile",ObjDefaultTempFileName.str());
  ObjTexturesPath = IniFile::DefIniFile.readString ("TGB", "TexturePath",ObjDefaultTexturesPath.str());
  ObjVrmlPath = IniFile::DefIniFile.readString ("TGB", "VRMLPath",ObjDefaultVrmlPath.str());
  ObjHasToBuildNumbers = IniFile::DefIniFile.readBool ("TGB", "ShowNumbers",true);
  
  FileSystem::switchPathForOS (ObjPermFileName.str ());
  FileSystem::switchPathForOS (ObjTempFileName.str ());
  FileSystem::switchPathForOS (ObjTexturesPath.str ());
  FileSystem::switchPathForOS (ObjVrmlPath.str ());


  if ((ObjTexturesPath.str ()) [(ObjTexturesPath.len () - 1)] !=
      FileSystem::PathSeparator ())
    ObjTexturesPath += FileSystem::PathSeparator ();
  if ((ObjTexturesPath.str ()) [0] != FileSystem::PathSeparator ()
      && (ObjTexturesPath.str ()) [1] != ':')
    ObjTexturesPath = MySFXModel->ModelPath () + ObjTexturesPath;

  if ((ObjVrmlPath.str ()) [(ObjVrmlPath.len () - 1)] !=
      FileSystem::PathSeparator ())
    ObjVrmlPath += FileSystem::PathSeparator ();
  if ((ObjVrmlPath.str ()) [0] != FileSystem::PathSeparator ()
      && (ObjVrmlPath.str ()) [1] != ':')
    ObjVrmlPath = MySFXModel->ModelPath () + ObjVrmlPath;

  if ((ObjPermFileName.str ()) [0] != FileSystem::PathSeparator ()
      && (ObjPermFileName.str ()) [1] != ':')
    ObjPermFileName = MySFXModel->ModelPath () + ObjPermFileName;
  if ((ObjTempFileName.str ()) [0] != FileSystem::PathSeparator ()
      && (ObjTempFileName.str ()) [1] != ':')
    ObjTempFileName = MySFXModel->ModelPath () + ObjTempFileName;

  /**< Hier wird abgefragt, ob Dateien und Verzeichnisse vorhanden sind. Sonst wird Default genommen! */
  if (!FileSystem::FileExists (ObjPermFileName.str()))
      ObjPermFileName = ObjDefaultPermFileName.str();
  if (!FileSystem::FileExists (ObjTempFileName.str()))
    ObjTempFileName = ObjDefaultTempFileName.str();
  if (!FileSystem::DirExists (ObjTexturesPath.str()))
    ObjTexturesPath = ObjDefaultTexturesPath.str();
  if (!FileSystem::DirExists (ObjVrmlPath.str()))
    ObjVrmlPath = ObjDefaultVrmlPath.str();  

  FileSystem::switchPathForOS (ObjPermFileName.str ());
  FileSystem::switchPathForOS (ObjTempFileName.str ());
  FileSystem::switchPathForOS (ObjTexturesPath.str ());
  FileSystem::switchPathForOS (ObjVrmlPath.str ());

  if ((ObjTexturesPath.str ()) [(ObjTexturesPath.len () - 1)] !=
      FileSystem::PathSeparator ())
    ObjTexturesPath += FileSystem::PathSeparator ();
  if ((ObjTexturesPath.str ()) [0] != FileSystem::PathSeparator ()
      && (ObjTexturesPath.str ()) [1] != ':')
    ObjTexturesPath = MySFXModel->ModelPath () + ObjTexturesPath;
  if ((ObjVrmlPath.str ()) [(ObjVrmlPath.len () - 1)] !=
      FileSystem::PathSeparator ())
    ObjVrmlPath += FileSystem::PathSeparator ();
  if ((ObjVrmlPath.str ()) [0] != FileSystem::PathSeparator ()
      && (ObjVrmlPath.str ()) [1] != ':')
    ObjVrmlPath = MySFXModel->ModelPath () + ObjVrmlPath;

  if ((ObjPermFileName.str ()) [0] != FileSystem::PathSeparator ()
      && (ObjPermFileName.str ()) [1] != ':')
    ObjPermFileName = MySFXModel->ModelPath () + ObjPermFileName;
  if ((ObjTempFileName.str ()) [0] != FileSystem::PathSeparator ()
      && (ObjTempFileName.str ()) [1] != ':')
    ObjTempFileName = MySFXModel->ModelPath () + ObjTempFileName;

  cout << ObjPermFileName.str() << endl;
  cout << ObjTempFileName.str() << endl;
  cout << ObjTexturesPath.str() << endl;
  cout << ObjVrmlPath.str() << endl;
}

TGBLib::~TGBLib () {
  if (ObjFile) delete ObjFile;
  while (ObjPermPattern.Last ())
    delete ObjPermPattern.removeLast ();
  while (ObjTempPattern.Last ())
    delete ObjTempPattern.removeLast ();
// Rudi: 21-06-03: Warum sind folgende Zeilen auskommentiert?
// Wer hat das gemacht? Hat es damit zu tun, dass die Patterns
// oben schon geloescht worden sind?
  //ObjTempPattern.removeAll ();
  //Pattern::clean ();
}

TGBPermPattern *TGBLib::findPerm (unsigned typ, unsigned variant) {
  TGBIdentity id (typ, variant);
  for (ObjPermPattern.First (); ObjPermPattern (); ObjPermPattern++)
    if (id == ObjPermPattern()->Id())
      return ObjPermPattern ();

  if (!ObjIsPreparedForPerms) prepareForPerms ();
  return &(ObjPermPattern.append (*(new TGBPermPattern (*this, typ, variant))));
}

TGBTempPattern *TGBLib::findTemp (unsigned typ, unsigned variant) {
  TGBIdentity id (typ, variant);
  for (ObjTempPattern.First (); ObjTempPattern (); ObjTempPattern++)
    if (id == ObjTempPattern()->Id())
      return ObjTempPattern ();

  if (!ObjIsPreparedForTemps) prepareForTemps ();
  return &(ObjTempPattern.append (*(new TGBTempPattern (*this, typ, variant))));
}

void TGBLib::BuildNumbers () {
  ObjHasToBuildNumbers = true;
}

void TGBLib::DontBuildNumbers () {
  ObjHasToBuildNumbers = false;
}

bool TGBLib::hasToBuildNumbers () const {
  return ObjHasToBuildNumbers;
}

unsigned TGBLib::TypOffset    () const {
  return ObjTypOffset;
}

unsigned TGBLib::TypMulti     () const {
  return ObjTypMulti;
}

unsigned TGBLib::VarMulti     () const {
  return ObjVarMulti;
}

unsigned TGBLib::SegOffset    () const {
  return ObjSegOffset;
}

unsigned TGBLib::NumPosOffset () const {
  return ObjNumPosOffset;
}

unsigned TGBLib::SymPosOffset () const {
  return ObjSymPosOffset;
}

unsigned TGBLib::TextOffset   () const {
  return ObjTextOffset;
}

unsigned TGBLib::Info1Offset () const {
  return ObjInfo1Offset;
}

unsigned TGBLib::Info2Offset () const {
  return ObjInfo2Offset;
}

unsigned TGBLib::Info3Offset () const {
  return ObjInfo3Offset;
}

unsigned TGBLib::Info4Offset () const {
  return ObjInfo4Offset;
}

const Ustring& TGBLib::TexturesPath () const {
  return ObjTexturesPath;
}

const Ustring& TGBLib::VrmlPath () const {
  return ObjVrmlPath;
}

InputFile *TGBLib::TGBFile     () const {
  return ObjFile;
}

void TGBLib::prepareForPerms () {
  if (ObjFile) {
    delete ObjFile;
    ObjFile = NULL;
  }

  ObjFile = new InputFile (ObjPermFileName.str ());
  if (!(*ObjFile)) {
   ObjPermFileName = (ObjDefaultPermFileName.str());
   ObjFile = new InputFile (ObjPermFileName.str ());
  if (!(*ObjFile))
    Msg.Error ("TGBLib::prepareForPerms (...)", "Could't find tgb-file \"%s\"!!", ObjPermFileName.str ());
  }

  readPermOffsets ();
  ObjIsPreparedForPerms = true;
  ObjIsPreparedForTemps = false;
}

void TGBLib::prepareForTemps () {
  if (ObjFile) {
    delete ObjFile;
    ObjFile = NULL;
  }

  ObjFile = new InputFile (ObjTempFileName.str ());
  if (!(*ObjFile)) {
   ObjTempFileName = (ObjDefaultTempFileName.str());
   ObjFile = new InputFile (ObjTempFileName.str ());
  if (!(*ObjFile))
    Msg.Error ("TGBLib::prepareForTemps (...)", "Could't find tgb-file \"%s\"!!", ObjTempFileName.str ());
  }

  readTempOffsets ();
  ObjIsPreparedForTemps = true;
  ObjIsPreparedForPerms = false;
}

void TGBLib::readPermOffsets () {
  SFXToken tok;
  if (tok.findSentence (6, *ObjFile)) {
    tok.nextToken (*ObjFile);
    ObjTypOffset = atoi (tok());
    tok.nextToken (*ObjFile);
    ObjTypMulti = atoi (tok());
    tok.nextToken (*ObjFile);
    ObjVarMulti = atoi (tok());
    tok.nextToken (*ObjFile);
    ObjSegOffset = atoi (tok());
    tok.nextToken (*ObjFile);
    ObjNumPosOffset = atoi (tok());
    tok.nextToken (*ObjFile);
    ObjSymPosOffset = atoi (tok());
    tok.nextToken (*ObjFile);
    ObjInfo1Offset = atoi (tok ());
    tok.nextToken (*ObjFile);
    ObjInfo2Offset = atoi (tok());
    tok.nextToken (*ObjFile);
    ObjInfo3Offset = atoi (tok());
    tok.nextToken (*ObjFile);
    ObjTextOffset = atoi (tok());
  }
  else
    Msg.Warning ("TGBLib::readPermOffsets ()", "Can't find sentence 6 for Offsets!!!");
}

void TGBLib::readTempOffsets () {
  SFXToken tok;
  if (tok.findSentence (6, *ObjFile)) {
    tok.nextToken (*ObjFile);
    ObjTypOffset = atoi (tok());
    tok.nextToken (*ObjFile);
    ObjTypMulti = atoi (tok());
    tok.nextToken (*ObjFile);
    ObjVarMulti = atoi (tok());
    tok.nextToken (*ObjFile);
    ObjSegOffset = atoi (tok());
    tok.nextToken (*ObjFile);
    ObjNumPosOffset = atoi (tok());
    tok.nextToken (*ObjFile);
    ObjSymPosOffset = atoi (tok());
    tok.nextToken (*ObjFile);
    ObjTextOffset = atoi (tok());
    tok.nextToken (*ObjFile);
    ObjInfo1Offset = atoi (tok ());
    tok.nextToken (*ObjFile);
    ObjInfo2Offset = atoi (tok());
    tok.nextToken (*ObjFile);
    ObjInfo3Offset = atoi (tok());
    tok.nextToken (*ObjFile);
    ObjInfo4Offset = atoi (tok());
  }
  else
    Msg.Warning ("TGBLib::readTempOffsets ()", "Can't find sentence 6 for Offsets!!!");
}
