/*------------------------------------------------------------\
|                                                             |
| Tool    :                    RDSCIF                         |
|                                                             |
| File    :                 cif_drive.c                       |
|                                                             |
| Authors :       Petrot Frederic & Jacomme Ludovic           |
|                   ---------          ---------              |
| Date    :    The king ^     04/07/93     ^ The slave        |
|                                                             |
\------------------------------------------------------------*/
/*------------------------------------------------------------\
|                                                             |
|                         Include Files                       |
|                                                             |
\------------------------------------------------------------*/

# include <values.h>

# include MUT_H
# include MPH_H
# include RDS_H
# include RPR_H
# include RFM_H
# include RUT_H
# include RTL_H

# include "cif.h"
# include "cif_error.h"
# include "cif_drive.h"

/*------------------------------------------------------------\
|                                                             |
|                           Constants                         |
|                                                             |
\------------------------------------------------------------*/

 static  char  CifBuffer[ 256 ];

 static  long  CIF_DS_A = 0;
 static  long  CIF_DS_B = 0;

 static  ptype_list *HEAD_CIF_MODEL = (ptype_list *)NULL;
 static  long        CifModelIndex  = 0;


/*------------------------------------------------------------\
|                                                             |
|                            Types                            |
|                                                             |
\------------------------------------------------------------*/
/*------------------------------------------------------------\
|                                                             |
|                          Variables                          |
|                                                             |
\------------------------------------------------------------*/
/*------------------------------------------------------------\
|                                                             |
|                          Functions                          |
|                                                             |
\------------------------------------------------------------*/
/*------------------------------------------------------------\
|                                                             |
|                          rdstocifname                       |
|                                                             |
\------------------------------------------------------------*/

  char *rdstocifname( Name )

   char *Name;
 {
   char *Source;
   char *Target;
   char  One;

   if ( Name == (char *)NULL ) 
   {
     return( (char *)NULL );
   }

   One = 1;

   Source = Name;
   Target = CifBuffer;

   while (  *Source != '\0' ) 
   {
     if ( *Source == ' ' )
     {
       if ( One ) 
       {
         *Target++ = '[';
         Source++;

         One = 0;
       } 
       else 
       {
         *Target++ = ']';
         *Target++ = '[';
          Source++;
       }
     }

     if ( ( *Source == SEPAR ) && ( ! One ) )
     {
       *Target++ = ']';
       One       = 1;
     }

     *Target++ = *Source++;
   }

   if ( ! One )
   {
     *Target++ = ']';
   }

   *Target = '\0';

   return ( CifBuffer );
 }

/*------------------------------------------------------------\
|                                                             |
|                       r_cif_model_list                      |
|                                                             |
\------------------------------------------------------------*/

  static ptype_list *r_cif_model_list( Figure )
  
     rdsfig_list *Figure;
  {
    rdsins_list *Instance;
    rdsfig_list *Model;
    ptype_list  *List;
  
    for ( Instance  = Figure->INSTANCE;
          Instance != (rdsins_list *)NULL;
          Instance  = Instance->NEXT )
    {
      for ( List  = HEAD_CIF_MODEL;
            List != (ptype_list *)NULL;
            List  = List->NEXT )
      {
        if (((rdsfig_list *)List->DATA)->NAME == Instance->FIGNAME )
        {
          break;
        }
      }

      if ( List == (ptype_list *)NULL )
      {
        for ( Model  = HEAD_RDSFIG;
              Model != (rdsfig_list *)NULL;
              Model  = Model->NEXT )
        {
          if ( Model->NAME == Instance->FIGNAME ) break;
        }
  
        if ( Model == (rdsfig_list *)NULL )
        {
          ciferror( CIF_ERROR_MODEL,  Instance->FIGNAME );
        }

        (void)r_cif_model_list( Model );
      }
   
    }

    HEAD_CIF_MODEL = addptype( HEAD_CIF_MODEL,
                               ++CifModelIndex, (char *)Figure );
    return( HEAD_CIF_MODEL );
  }

/*------------------------------------------------------------\
|                                                             |
|                          cif_model_list                     |
|                                                             |
\------------------------------------------------------------*/

  ptype_list *cif_model_list( Figure )

    rdsfig_list *Figure;
  {
    CifModelIndex = 0;

    if ( HEAD_CIF_MODEL != (ptype_list *)NULL )
    {
      freeptype( HEAD_CIF_MODEL);
    }

    HEAD_CIF_MODEL = NULL;

    return( r_cif_model_list( Figure ) );
  }

/*------------------------------------------------------------\
|                                                             |
|                          write_figure                       |
|                                                             |
\------------------------------------------------------------*/

  void write_figure( File, Model )

    FILE *File;
    long  Model;
  {
    (void)fprintf( File, "C%ld;\n", Model );
  }

/*------------------------------------------------------------\
|                                                             |
|                          write_instance                     |
|                                                             |
\------------------------------------------------------------*/

  void write_instance( File, Name, Model, X, Y, Trans )

    FILE *File;
    char *Name;
    long  Model;
    long  X;
    long  Y;
    long  Trans;
  {
    char Buffer[ 100 ];

    long Xcif;
    long Ycif;

    Xcif = RDS_TO_CIF_UNIT( X );
    Ycif = RDS_TO_CIF_UNIT( Y );

    switch ( Trans ) 
    {
      case RDS_NOSYM :
         (void)sprintf( Buffer, "T%ld, %ld", Xcif, Ycif );
         break;
      case RDS_SYM_X :
         (void)sprintf( Buffer, "MX T%ld, %ld", Xcif, Ycif );
         break;
      case RDS_SYM_Y :
         (void)sprintf( Buffer, "MY T%ld, %ld", Xcif, Ycif );
         break;
      case RDS_SYMXY :
         (void)sprintf( Buffer, "R-1, 0 T%ld, %ld", Xcif, Ycif );
         break;
      case RDS_ROT_P :
         (void)sprintf( Buffer, "R0, 1 T%ld, %ld", Xcif, Ycif );
         break;
      case RDS_ROT_M :
         (void)sprintf( Buffer, "R0, -1 T%ld, %ld", Xcif, Ycif );
         break;
      case RDS_SY_RP :
         (void)sprintf( Buffer, "MX R0, -1 T%ld, %ld", Xcif, Ycif );
         break;
      case RDS_SY_RM :
         (void)sprintf( Buffer, "MX R0, 1 T%ld, %ld", Xcif, Ycif );
         break;
      default :
         ciferror( CIF_ERROR_BAD_TRANS, Name, 0 );
   }

# ifdef VTI_DRIVER

   (void)fprintf( File, "4I %s;", Name);
# else
   (void)fprintf( File, "91 %s;", Name);

# endif

   (void)fprintf( File, "C%ld %s;\n", Model, Buffer );
}

/*------------------------------------------------------------\
|                                                             |
|                          write_connector                    |
|                                                             |
\------------------------------------------------------------*/

   void write_connector( File, Name, Index, Width, X, Y, Dx, Dy, Layer, WriteLayer )

    FILE *File;
    char *Name;
    long  Index;
    long  Width;
    long  X;
    long  Y;
    long  Dx;
    long  Dy;
    char *Layer;
    char  WriteLayer;
  {
    if ( Name == (char *)NULL )
    {
      ciferror( CIF_ERROR_CONNECTOR_NAME, (char *)X, Y );
    }

    if ( WriteLayer )
    {
      (void)fprintf( File, "L%s;\n", Layer );
    }

    Name = rdstocifname( Name );

# ifdef VTI_DRIVER
    
    (void)fprintf( File, "4X %s %ld %ld %ld %ld %s;\n",
                   Name, Index,
                   RDS_TO_CIF_UNIT(  X ) + RDS_TO_CIF_UNIT( Dx ) / 2,
                   RDS_TO_CIF_UNIT(  Y ) + RDS_TO_CIF_UNIT( Dy ) / 2,
                   RDS_TO_CIF_UNIT( Width ), Name );
# else
    (void)fprintf( File, "95 %s %ld %ld %ld %ld %s;\n",
                   Name, 
                   RDS_TO_CIF_UNIT( Dx ), RDS_TO_CIF_UNIT( Dy ),
                   RDS_TO_CIF_UNIT(  X ) + RDS_TO_CIF_UNIT( Dx ) / 2,
                   RDS_TO_CIF_UNIT(  Y ) + RDS_TO_CIF_UNIT( Dy ) / 2,
                   Layer );
# endif
  }

/*------------------------------------------------------------\
|                                                             |
|                          write_rectangle                    |
|                                                             |
\------------------------------------------------------------*/

  void write_rectangle( File, Name, X, Y, Dx, Dy, Layer, WriteLayer )

     FILE *File;
     char *Name;
     long  X;
     long  Y;
     long  Dx;
     long  Dy;
     char *Layer;
     char  WriteLayer;
  {
    if ( WriteLayer )
    {
      (void)fprintf( File, "L%s;\n", Layer );
    }

    if ( (  Name != (char *)NULL ) && 
         ( *Name != '*'          ) && 
         ( *Name != '\0'         ) )
    {
# ifdef VTI_DRIVER

      (void)fprintf( File, "4N %s %ld %ld;\n", rdstocifname( Name ),
                     RDS_TO_CIF_UNIT(  X ) + RDS_TO_CIF_UNIT( Dx ) / 2,
                     RDS_TO_CIF_UNIT(  Y ) + RDS_TO_CIF_UNIT( Dy ) / 2);

# else
      (void)fprintf( File, "94 %s %ld %ld %s;\n", rdstocifname( Name ),
                     RDS_TO_CIF_UNIT(  X ) + RDS_TO_CIF_UNIT( Dx ) / 2,
                     RDS_TO_CIF_UNIT(  Y ) + RDS_TO_CIF_UNIT( Dy ) / 2,
                     Layer );

# endif   
    }

    (void)fprintf( File, "B%ld %ld %ld %ld;\n",
                   RDS_TO_CIF_UNIT( ABSOLUTE( Dx ) ),
                   RDS_TO_CIF_UNIT( ABSOLUTE( Dy ) ),
                   RDS_TO_CIF_UNIT(  X ) + RDS_TO_CIF_UNIT( Dx ) / 2,
                   RDS_TO_CIF_UNIT(  Y ) + RDS_TO_CIF_UNIT( Dy ) / 2);
  }

/*------------------------------------------------------------\
|                                                             |
|                          write_header                       |
|                                                             |
\------------------------------------------------------------*/

  void write_header( File, Name )

    FILE *File;
    char *Name;
  {
    long Counter;

    (void)time( &Counter );
    (void)fprintf( File, "(rds to CIF driver version 1.03\n");
    (void)fprintf( File, "technology %s\n", RDS_TECHNO_NAME );
    (void)fprintf( File, "%s"  , ctime( &Counter )          );
    (void)fprintf( File, "%s\n", Name                       );
    (void)fprintf( File, "%s);\n\n", getenv("USER")         );
  }

/*------------------------------------------------------------\
|                                                             |
|                          write_header                       |
|                                                             |
\------------------------------------------------------------*/

  void write_tail( File, X, Y, Dx, Dy )

    FILE *File;
    long  X;
    long  Y;
    long  Dx;
    long  Dy;
  {
    (void)fprintf( File, "(AB : %.2f, %.2f %.2f, %.2f in micron); \n",
                   (float)X / RDS_UNIT, 
                   (float)Y / RDS_UNIT,
                   (float)(X + Dx) / RDS_UNIT,
                   (float)(Y + Dy) / RDS_UNIT );
  }

/*------------------------------------------------------------\
|                                                             |
|                        write_model_header                   |
|                                                             |
\------------------------------------------------------------*/

  void write_model_header( File, ModelName, ModelNum )

    FILE *File;
    char *ModelName;
    long  ModelNum;
  {
    (void)fprintf( File, "DS%ld %ld %ld;\n", ModelNum, CIF_DS_A, CIF_DS_B * 2 );
    (void)fprintf( File, "9 %s;\n", ModelName );
  }

/*------------------------------------------------------------\
|                                                             |
|                        write_model_abox                     |
|                                                             |
\------------------------------------------------------------*/

   void write_model_abox( File, X, Y, Dx, Dy )


    FILE *File;
    long  X;
    long  Y;
    long  Dx;
    long  Dy;
  {
    (void)fprintf( File, "(AB : %.2f, %.2f %.2f, %.2f in micron);\n",
                   (float)X / RDS_UNIT,
                   (float)Y / RDS_UNIT,
                   (float)(X + Dx) / RDS_UNIT,
                   (float)(Y + Dy) / RDS_UNIT);
# ifdef VTI_DRIVER

    (void)fprintf( File, "4A %ld %ld %ld %ld; \n",
                   RDS_TO_CIF_UNIT( X ), 
                   RDS_TO_CIF_UNIT( Y ),
                   RDS_TO_CIF_UNIT( X + Dx ),
                   RDS_TO_CIF_UNIT( Y + Dy ) );
# endif
  }

/*------------------------------------------------------------\
|                                                             |
|                        write_model_tail                     |
|                                                             |
\------------------------------------------------------------*/

  void write_model_tail( File )

    FILE *File;
  {
    (void)fprintf( File, "DF;\n\n" );
  }

/*------------------------------------------------------------\
|                                                             |
|                          getcifmodel                        |
|                                                             |
\------------------------------------------------------------*/

  long getcifmodel( Head, Name )

    ptype_list *Head;
    char       *Name;
  {
    ptype_list *Scan;

    for ( Scan  = Head; 
          Scan != (ptype_list *)NULL;
          Scan  = Scan->NEXT )
    {
      if (((rdsfig_list *)Scan->DATA)->NAME == Name )
      {
        return( Scan->TYPE );
      }
    }

    return( 0 );
  }

/*------------------------------------------------------------\
|                                                             |
|                      compute_cif_unit                       |
|                                                             |
\------------------------------------------------------------*/

 void compute_cif_unit()
 {
   /* why CIF_DS_A, CIF_DS_B ?
      the simple of driving CIF would be to take both as 1, and have on
      each coordinate a (x * CIF_UNIT)/rds_unit).
      The interest here is to shorten the lenght of the numbers in the
      CIF output, and to be able to express a precision better that a
      centh of a micron.
      CIF_DS_A and CIF_DS_B are defined as follow :
      (CIF_DS_A / CIF_DS_B) * rds_unit = CIF_UNIT
      see CIF documentation for details.
      the coodinates for CIF will be computed like
      (x * CIF_DS_B) / (CIF_DS_A * rds_unit).
      The computation algorithm is equivalent to the one given in the
      function RprComputeRdsUnit, so take a look there for details. 

      Friendly, The king ... */

   /* why 2 * CIF_UNIT ?
      because all the rectangles in the CIF file are written like
      BOXES, ie dx and dy must be even since we drive dx/2 dy/2
      and we don't want to lose any information! */
   int cif_unit = 2 * CIF_UNIT;

   if ( RDS_UNIT < cif_unit ) 
   {
     for ( CIF_DS_A = 1, CIF_DS_B = 1; 
           ( CIF_DS_A * RDS_UNIT ) != ( cif_unit * CIF_DS_B ); 
           CIF_DS_B++ ) 
     {
       for ( CIF_DS_A--; 
             ( CIF_DS_A * RDS_UNIT ) < ( cif_unit * CIF_DS_B ); 
             (CIF_DS_A)++ );

       if ( ( CIF_DS_A * RDS_UNIT ) == ( cif_unit * CIF_DS_B ) ) break;
     }
   } 
   else 
   {
     for ( CIF_DS_A = 1, CIF_DS_B = 1; 
           ( CIF_DS_A * RDS_UNIT ) != ( cif_unit * CIF_DS_B ); 
           CIF_DS_A++ ) 
     {
       for ( CIF_DS_B--; 
             ( CIF_DS_A * RDS_UNIT ) > ( cif_unit * CIF_DS_B ); 
             CIF_DS_B++ );

       if ( ( CIF_DS_A * RDS_UNIT ) == ( cif_unit * CIF_DS_B ) ) break;
     }
   }
 }

/*------------------------------------------------------------\
|                                                             |
|                         drive_model                         |
|                                                             |
\------------------------------------------------------------*/

  void drive_model( File, Model, Figure )

    FILE        *File;
    ptype_list  *Model;
    rdsfig_list *Figure;
  {
    rdsrec_list *Rectangle;
    rdsins_list *Instance;
    char         Layer;
    char         WriteLayer;
    long         Index;
    char        *CifLayer;

    Index = 0;

    for ( Layer = 0; Layer < RDS_MAX_LAYER; Layer++ ) 
    {
      if ( Layer == RDS_ABOX ) continue;

      CifLayer = GET_CIF_LAYER( Layer );

      if ( CifLayer == RDS_CIF_LAYER_EMPTY ) continue;

      WriteLayer = 1;

      for ( Rectangle  = Figure->LAYERTAB[ Layer ]; 
            Rectangle != (rdsrec_list *)NULL; 
            Rectangle  = Rectangle->NEXT ) 
      {
        /* drive connector :
           put the connector name in vti cif dialect.
           if the rds doesn't come from mbk, the type may be set but the
           mbk pointer may be null. */

        if ( IsRdsConExter( Rectangle ) )
        {
          write_connector( File, 
                           Rectangle->NAME, ++Index,
                           ( Rectangle->DX > Rectangle->DY ) ? 
                           Rectangle->DX : Rectangle->DY,
                           Rectangle->X  , Rectangle->Y, 
                           Rectangle->DX , Rectangle->DY,
                           CifLayer, WriteLayer );
        }  
        else 
        {
          write_rectangle( File, 
                           Rectangle->NAME, 
                           Rectangle->X , Rectangle->Y, 
                           Rectangle->DX, Rectangle->DY, 
                           CifLayer, WriteLayer );
        }

        /* layer choice :

           the layer is driven only once, since in cif when a layer is defined,
           all further objects are build with this layer. This is close of the
           rds representation, so the writting functions print a layer when the
           parameter is not NULL, nothing if it is. The king ... */

        WriteLayer = 0;
      }
    }

    for ( Instance  = Figure->INSTANCE; 
          Instance != (rdsins_list *)NULL; 
          Instance  = Instance->NEXT )
    {
      write_instance( File, Instance->INSNAME, 
                      getcifmodel( Model, Instance->FIGNAME ),
                      Instance->X, Instance->Y, 
                      (long)Instance->TRANSF ); 
    }
  }

/*------------------------------------------------------------\
|                                                             |
|                         cifsaverdsfig                       |
|                                                             |
\------------------------------------------------------------*/

 void cifsaverdsfig( Figure )

    rdsfig_list *Figure;
 {
   FILE        *File;
   ptype_list  *Model;
   ptype_list  *List;
   rdsrec_list *Abox;

   compute_cif_unit();

   List = Model = (ptype_list *)reverse((chain_list *)cif_model_list( Figure ) );

   if ( ( File = mbkfopen( Figure->NAME, "cif", "w" ) ) == NULL )
   {
     ciferror( CIF_ERROR_FILE_OPEN, Figure->NAME, 0 );
   }

   write_header( File, Figure->NAME );

   while ( Model != (ptype_list *)NULL ) 
   {
     write_model_header( File, ((rdsfig_list *)Model->DATA)->NAME, 
                         Model->TYPE );

     Abox = ((rdsfig_list *)Model->DATA)->LAYERTAB[ RDS_ABOX ];
 
     if ( Abox != (rdsrec_list *)NULL )
     {
       write_model_abox( File, Abox->X, Abox->Y, 
                         Abox->DX, Abox->DY );
     }

     drive_model( File, List, ((rdsfig_list *)Model->DATA) );
     write_model_tail( File );

     Model = Model->NEXT;
   }

   write_figure( File, getcifmodel( List, Figure->NAME ) );

   Abox = Figure->LAYERTAB[ RDS_ABOX ];

   if ( Abox != (rdsrec_list *)NULL )
   {
     write_tail( File, Abox->X, Abox->Y, Abox->DX, Abox->DY );
   }

   (void)fprintf( File, "E \n");

   if ( fclose( File ) )
   {
     ciferror( CIF_ERROR_FILE_CLOSE, Figure->NAME, 0 );
   }
 }
