/*------------------------------------------------------------\
|                                                             |
| Tool    :                     RDS                           |
|                                                             |
| File    :                  Rds window                       |
|                                                             |
| Authors :                Jacomme Ludovic                    |
|                                                             |
| Date    :                   01.08.93                        |
|                                                             |
\------------------------------------------------------------*/
/*------------------------------------------------------------\
|                                                             |
|                         MODIFICTIONS                        |
|                                                             |
\------------------------------------------------------------*/
/*------------------------------------------------------------\
|   PATRICK le 26-10-93 ligne 204                             |
|                                                             |
|  remplacer delchain( HEAD_RWICHAIN ); par                   |
|            freechain( HEAD_RWICHAIN );                      |
|   delchain detruit un seul element de la chaine et demande 2|
|   parametres ici on veut creer la chaine des fenetres donc  |
|   detruire la precedente si elle existait; de plus il       |
|   fallait 2 parametres                                      |  
\------------------------------------------------------------*/

/*------------------------------------------------------------\
|                                                             |
|                         Include Files                       |
|                                                             |
\------------------------------------------------------------*/

# include MUT_H
# include MPH_H
# include RDS_H
# include RWI_H

# include <stdio.h>
# include <string.h>
# include <math.h>
# include "rwierror.h"

/*------------------------------------------------------------\
|                                                             |
|                           Constants                         |
|                                                             |
\------------------------------------------------------------*/
/*------------------------------------------------------------\
|                                                             |
|                            Types                            |
|                                                             |
\------------------------------------------------------------*/
/*------------------------------------------------------------\
|                                                             |
|                          Variables                          |
|                                                             |
\------------------------------------------------------------*/

  static chain_list *HEAD_RWICHAIN = (chain_list *)NULL;

/*------------------------------------------------------------\
|                                                             |
|                          Functions                          |
|                                                             |
\------------------------------------------------------------*/
/*------------------------------------------------------------\
|                                                             |
|                          Functions                          |
|                                                             |
\------------------------------------------------------------*/
/*------------------------------------------------------------\
|                                                             |
|                        Alloc Functions                      |
|                                                             |
\------------------------------------------------------------*/
/*------------------------------------------------------------\
|                                                             |
|                      Alloc Rds Win Rec                      |
|                                                             |
\------------------------------------------------------------*/

  rdswinrec_list *allocrdswinrec()
 
  {
    return((rdswinrec_list *)(rdsalloc(sizeof(rdswinrec_list), 1 )));
  }

/*------------------------------------------------------------\
|                                                             |
|                      Alloc Rds Rec Win                      |
|                                                             |
\------------------------------------------------------------*/

  rdsrecwin_list *allocrdsrecwin()
 
  {
    return((rdsrecwin_list *)(rdsalloc(sizeof(rdsrecwin_list), 1 )));
  }

/*------------------------------------------------------------\
|                                                             |
|                        Alloc Rds Window                     |
|                                                             |
\------------------------------------------------------------*/

  rdswin_list *allocrdswin( Number )

    unsigned int Number;
  {
    return((rdswin_list *)(rdsalloc(sizeof(rdswin_list) * Number, 0)));
  }

/*------------------------------------------------------------\
|                                                             |
|                       Alloc Rds Window                      |
|                                                             |
\------------------------------------------------------------*/

  rdswindow *allocrdswindow() 

  {
    return((rdswindow *)(rdsalloc(sizeof(rdswindow), 0 )));
  }

/*------------------------------------------------------------\
|                                                             |
|                        Free Functions                       |
|                                                             |
\------------------------------------------------------------*/
/*------------------------------------------------------------\
|                                                             |
|                        Free Rds Rec Win                     |
|                                                             |
\------------------------------------------------------------*/

  void freerdsrecwin( RecWin )

    rdsrecwin_list *RecWin;
  {
    rdsfree( (char *)RecWin, sizeof(rdsrecwin_list) );
  }

/*------------------------------------------------------------\
|                                                             |
|                        Free Rds Win Rec                     |
|                                                             |
\------------------------------------------------------------*/

  void freerdswinrec( WinRec )

    rdswinrec_list *WinRec;
  {
    rdsfree( (char *)WinRec, sizeof(rdswinrec_list) );
  }

/*------------------------------------------------------------\
|                                                             |
|                          Free Rds Win                       |
|                                                             |
\------------------------------------------------------------*/

  void freerdswin( Win )

    rdswin_list *Win;
  {
    rdsfree( (char *)Win, 0);
  }
/*------------------------------------------------------------\
|                                                             |
|                          Free Rds Window                    |
|                                                             |
\------------------------------------------------------------*/

  void freerdswindow( RdsWindow )

    rdswindow *RdsWindow;
  {
    rdsfree( (char *)RdsWindow, 0);
  }

/*------------------------------------------------------------\
|                                                             |
|                         getrdswindow                        |
|                                                             |
\------------------------------------------------------------*/

  chain_list *getrdswindow( X, Y, Dx, Dy, RdsWindow )

     long       X;
     long       Y;
     long       Dx;
     long       Dy;
     rdswindow *RdsWindow;
  {
    rdswin_list    *WinList;
    long            X1;
    long            X2;
    long            Y1;
    long            Y2;

    if ( HEAD_RWICHAIN != (chain_list *)NULL )
    {
      freechain ( HEAD_RWICHAIN );
      HEAD_RWICHAIN = (chain_list *)NULL;
    }
 
    if ( Y > RdsWindow->YMIN )
    {
      Y1 = ( Y - RdsWindow->YMIN - 1 ) / RdsWindow->SIDE;
    }
    else
    {
      Y1 = ( Y - RdsWindow->YMIN ) / RdsWindow->SIDE;
    }

    Y2 = ( Y + Dy - RdsWindow->YMIN ) / RdsWindow->SIDE;

    while ( Y1 <= Y2 )
    {
      WinList = RdsWindow->WINTAB + ( Y1 * RdsWindow->DX );

      if ( X > RdsWindow->XMIN )
      {
        X1 = ( X - RdsWindow->XMIN - 1 ) / RdsWindow->SIDE;
      }
      else
      {
        X1 = ( X - RdsWindow->XMIN ) / RdsWindow->SIDE;
      }

      X2 = ( X + Dx - RdsWindow->XMIN ) / RdsWindow->SIDE;

      while ( X1 <= X2 )
      {
        HEAD_RWICHAIN = addchain( HEAD_RWICHAIN, 
                                  (void *)(WinList + X1) );
        X1 = X1 + 1;
      }

      Y1  = Y1 + 1;
    }

    return( HEAD_RWICHAIN );
  }

/*------------------------------------------------------------\
|                                                             |
|                     Add Rectangle In Window                 |
|                                                             |
\------------------------------------------------------------*/

  void addrdsrecwindow( Rectangle, RdsWindow )

       rdsrec_list *Rectangle;
       rdswindow   *RdsWindow;
  {
    rdswin_list    *LinkWinList;
    rdswin_list    *WinList;
    rdsrecwin_list *RecWin;
    rdswinrec_list *WinRec;
    char            Layer;

    long            X1;
    long            X2;
    long            Y1;
    long            Y2;
 
    long            Counter;

    if ( Rectangle->Y > RdsWindow->YMIN )
    {
      Y1 = ( Rectangle->Y - RdsWindow->YMIN - 1 ) / RdsWindow->SIDE;
    }
    else
    {
      Y1 = ( Rectangle->Y - RdsWindow->YMIN ) / RdsWindow->SIDE;
    }

    Y2 = ( Rectangle->Y + Rectangle->DY - RdsWindow->YMIN ) / RdsWindow->SIDE;

    while ( Y1 <= Y2 )
    {
      WinList = RdsWindow->WINTAB + ( Y1 * RdsWindow->DX );

      if ( Rectangle->X > RdsWindow->XMIN )
      {
        X1 = ( Rectangle->X - RdsWindow->XMIN - 1 ) / RdsWindow->SIDE;
      }
      else
      {
        X1 = ( Rectangle->X - RdsWindow->XMIN ) / RdsWindow->SIDE;
      }

      X2 = ( Rectangle->X + Rectangle->DX - RdsWindow->XMIN ) / RdsWindow->SIDE;

      while ( X1 <= X2 )
      {
        LinkWinList = WinList + X1;

        if ( Rectangle->USER == (void *)NULL )
        {
          Rectangle->USER = (void *)LinkWinList;
          SetRdsOneWindow( Rectangle );
        }
        else
        {
          if ( IsRdsOneWindow( Rectangle ) )
          {
            ClearRdsOneWindow( Rectangle );

            RecWin          = allocrdsrecwin();
            RecWin->WINDOW  = (rdswin_list *)Rectangle->USER;
            Rectangle->USER = (void *)RecWin;
          }

          RecWin          = allocrdsrecwin();
          RecWin->WINDOW  = LinkWinList;
          RecWin->NEXT    = (rdsrecwin_list *)Rectangle->USER;
          Rectangle->USER = (void *)RecWin;
        }

        Layer = GetRdsLayer( Rectangle );

        WinRec = LinkWinList->LAYERTAB[ Layer ];

        if ( WinRec == (rdswinrec_list *)NULL )
        {
          WinRec                         = allocrdswinrec();
          LinkWinList->LAYERTAB[ Layer ] = WinRec;
          WinRec->RECTAB[ 0 ]            = Rectangle;
        }
        else
        {
          for ( Counter = 0; Counter < RWI_MAX_REC; Counter++ )
          {
            if ( WinRec->RECTAB[ Counter ] == (rdsrec_list *)NULL ) break;
          }

          if ( Counter == RWI_MAX_REC )
          {
            WinRec                         = allocrdswinrec();
            WinRec->NEXT                   = LinkWinList->LAYERTAB[ Layer ];
            LinkWinList->LAYERTAB[ Layer ] = WinRec;
            WinRec->RECTAB[ 0 ]            = Rectangle;
          }
          else
          {
            WinRec->RECTAB[ Counter ] = Rectangle;
          }
        }

        X1 = X1 + 1;
      }   

      Y1  = Y1 + 1;
    }
  }

/*------------------------------------------------------------\
|                                                             |
|                     Del Rectangle In Window                 |
|                                                             |
\------------------------------------------------------------*/

  void delrdsrecwindow( Rectangle, RdsWindow )

       rdsrec_list *Rectangle;
       rdswindow   *RdsWindow;
  {
    rdsrecwin_list  StaticRecWin;
    rdsrecwin_list *ScanRecWin;
    rdsrecwin_list *DelRecWin;
    rdswinrec_list *ScanWinRec;
    rdswinrec_list *FirstWinRec;
    rdswin_list    *ScanWin;

    char            Layer;
    char            Index;
    char            Found;

    Layer = GetRdsLayer( Rectangle );

    if ( IsRdsOneWindow( Rectangle ) )
    {
      StaticRecWin.NEXT   = (rdsrecwin_list *)NULL;
      StaticRecWin.WINDOW = (rdswin_list *)Rectangle->USER;
      ScanRecWin          = &StaticRecWin;
    }
    else
    {
      ScanRecWin = (rdsrecwin_list *)(Rectangle->USER);
    }

    Rectangle->USER = (void *)NULL;
    ClearRdsOneWindow( Rectangle );

    while ( ScanRecWin != (rdsrecwin_list *)NULL )
    {
      DelRecWin  = ScanRecWin;
      ScanRecWin = ScanRecWin->NEXT;

      ScanWin = DelRecWin->WINDOW;
      Found   = RWI_MAX_REC;

      FirstWinRec = ScanWin->LAYERTAB[ Layer ];

      for ( ScanWinRec  = FirstWinRec;
            ScanWinRec != (rdswinrec_list *)NULL;
            ScanWinRec  = ScanWinRec->NEXT )
      {
        for ( Index = 0; Index < RWI_MAX_REC; Index++ )
        {
          if ( ScanWinRec->RECTAB[ Index ] == Rectangle )
          {
            Found = Index; break;
          }
        }

        if ( Found != RWI_MAX_REC ) break;
      }

      if ( ScanWinRec == FirstWinRec )
      {
        ScanWinRec->RECTAB[ Found ] = (rdsrec_list *)NULL;
      }
      else
      {
        for ( Index = 0; Index < RWI_MAX_REC; Index++ )
        {
          if ( FirstWinRec->RECTAB[ Index ] != (rdsrec_list *)NULL ) break;
        }

        ScanWinRec->RECTAB[ Found ]  = FirstWinRec->RECTAB[ Index ];
        FirstWinRec->RECTAB[ Index ] = (rdsrec_list *)NULL;
      }

      for ( Index = 0; Index < RWI_MAX_REC; Index++ )
      {
        if ( FirstWinRec->RECTAB[ Index ] != (rdsrec_list *)NULL ) break;
      }

      if ( Index == RWI_MAX_REC )
      {
        ScanWin->LAYERTAB[ Layer ] = FirstWinRec->NEXT;

        freerdswinrec( FirstWinRec );
      }

      if ( DelRecWin != &StaticRecWin )
      {
        freerdsrecwin( DelRecWin );
      }
    }
  }

/*------------------------------------------------------------\
|                                                             |
|                        Build Functions                      |
|                                                             |
\------------------------------------------------------------*/
/*------------------------------------------------------------\
|                                                             |
|                        Build Rds Window                     |
|                                                             |
\------------------------------------------------------------*/

  rdswindow *buildrdswindow( Figure )

     rdsfig_list *Figure;
  {
    rdswindow   *RdsWindow;
    rdsrec_list *Rectangle;
    rdsins_list *Instance;
    char         Layer;
 
    long         X1;
    long         Y1;
    long         X2;
    long         Y2;

    long         Mask;
    long         Xmin;
    long         Ymin;
    long         Xmax;
    long         Ymax;

    RdsWindow = allocrdswindow();

    Mask = 0;

    for ( Layer = 0; Layer < RWI_MAX_LAYER; Layer++ )
    {
      for ( Rectangle  = Figure->LAYERTAB[ Layer ];
            Rectangle != (rdsrec_list *)NULL;
            Rectangle  = Rectangle->NEXT )
      {
        Rectangle->USER = (void *)NULL;

        ClearRdsOneWindow( Rectangle );

        X1 = Rectangle->X;
        X2 = X1 + Rectangle->DX;
        Y1 = Rectangle->Y;
        Y2 = Y1 + Rectangle->DY;

        if ( Mask == 0 )
        {
          Xmax = X2;
          Ymax = Y2;
          Xmin = X1;
          Ymin = Y1;
        }
        else
        {   
          if ( Xmax < X2 ) Xmax = X2;
          if ( Ymax < Y2 ) Ymax = Y2;
          if ( Xmin > X1 ) Xmin = X1;
          if ( Ymin > Y1 ) Ymin = Y1;
        }

        Mask = Mask + 1;
      }  
    }

    for ( Instance  = Figure->INSTANCE;
          Instance != (rdsins_list *)NULL;
          Instance  = Instance->NEXT )
    {
      for ( Layer = 0; Layer < RWI_MAX_LAYER; Layer++ )
      {
        for ( Rectangle  = Instance->LAYERTAB[ Layer ];
              Rectangle != (rdsrec_list *)NULL;
              Rectangle  = Rectangle->NEXT )
        {
          Rectangle->USER = (void *)NULL;
  
          ClearRdsOneWindow( Rectangle );
  
          X1 = Rectangle->X;
          X2 = X1 + Rectangle->DX;
          Y1 = Rectangle->Y;
          Y2 = Y1 + Rectangle->DY;
  
          if ( Mask == 0 )
          {
            Xmax = X2;
            Ymax = Y2;
            Xmin = X1;
            Ymin = Y1;
          }
          else
          {   
            if ( Xmax < X2 ) Xmax = X2;
            if ( Ymax < Y2 ) Ymax = Y2;
            if ( Xmin > X1 ) Xmin = X1;
            if ( Ymin > Y1 ) Ymin = Y1;
          }
  
          Mask = Mask + 1;
        }  
      }  
    }

    RdsWindow->XMIN = Xmin; 
    RdsWindow->XMAX = Xmax; 
    RdsWindow->YMIN = Ymin; 
    RdsWindow->YMAX = Ymax; 
    RdsWindow->MASK = Mask; 

    if ( Mask == 0 ) return( RdsWindow );

    RdsWindow->SIDE = ( long )(sqrt (( double )( Xmax - Xmin ) *
                                     ( double )( Ymax - Ymin )) /
                               sqrt ( sqrt ( ( double )Mask )));

    RdsWindow->DX   = 1 + ( Xmax - Xmin ) / RdsWindow->SIDE;
    RdsWindow->DY   = 1 + ( Ymax - Ymin ) / RdsWindow->SIDE;
    RdsWindow->SIZE = RdsWindow->DX * RdsWindow->DY;

    RdsWindow->WINTAB = allocrdswin( RdsWindow->SIZE );

    for ( Layer = 0; Layer < RWI_MAX_LAYER; Layer++ )
    {
      for ( Rectangle  = Figure->LAYERTAB[ Layer ];
            Rectangle != (rdsrec_list *)NULL;
            Rectangle  = Rectangle->NEXT )
      {
        addrdsrecwindow( Rectangle, RdsWindow );
      }
    }

    for ( Instance  = Figure->INSTANCE; 
          Instance != (rdsins_list *)NULL;
          Instance  = Instance->NEXT )
    {
      for ( Layer = 0; Layer < RWI_MAX_LAYER; Layer++ )
      {
        for ( Rectangle  = Instance->LAYERTAB[ Layer ];
              Rectangle != (rdsrec_list *)NULL;
              Rectangle  = Rectangle->NEXT )
        {
          addrdsrecwindow( Rectangle, RdsWindow );
        }
      }
    }

    return( RdsWindow );
  }

/*------------------------------------------------------------\
|                                                             |
|                      Destroy Rds Window                     |
|                                                             |
\------------------------------------------------------------*/

  void destroyrdswindow( Figure, RdsWindow )

     rdsfig_list *Figure;
     rdswindow   *RdsWindow;
  {
    rdsins_list    *Instance;
    rdsrec_list    *Rectangle;
    rdswin_list    *WinList;
    rdsrecwin_list *RecWin;
    rdsrecwin_list *DelRecWin;
    rdswinrec_list *WinRec;
    rdswinrec_list *DelWinRec;
    long            Counter;
    char            Layer;

    for ( Layer = 0; Layer < RWI_MAX_LAYER; Layer++ )
    {
      for ( Rectangle  = Figure->LAYERTAB[ Layer ];
            Rectangle != (rdsrec_list *)NULL;
            Rectangle  = Rectangle->NEXT )
      {
        if ( ! IsRdsOneWindow( Rectangle ) )
        {
          RecWin = (rdsrecwin_list *)Rectangle->USER;
 
          while ( RecWin != (rdsrecwin_list *)NULL )
          {
            DelRecWin = RecWin;
            RecWin    = RecWin->NEXT;

            freerdsrecwin( DelRecWin );
          }
        }

        Rectangle->USER = (void *)NULL;

        ClearRdsOneWindow( Rectangle );
      }
    }

    for ( Instance  = Figure->INSTANCE; 
          Instance != (rdsins_list *)NULL;
          Instance  = Instance->NEXT )
    {
      for ( Layer = 0; Layer < RWI_MAX_LAYER; Layer++ )
      {
        for ( Rectangle  = Instance->LAYERTAB[ Layer ];
              Rectangle != (rdsrec_list *)NULL;
              Rectangle  = Rectangle->NEXT )
        {
          if ( ! IsRdsOneWindow( Rectangle ) )
          {
            RecWin = (rdsrecwin_list *)Rectangle->USER;
   
            while ( RecWin != (rdsrecwin_list *)NULL )
            {
              DelRecWin = RecWin;
              RecWin    = RecWin->NEXT;
  
              freerdsrecwin( DelRecWin );
            }
          }
  
          Rectangle->USER = (void *)NULL;

          ClearRdsOneWindow( Rectangle );
        }
      }
    }

    WinList = RdsWindow->WINTAB;
    
    for ( Counter = 0; Counter < RdsWindow->SIZE; Counter++ )
    {
      for ( Layer = 0; Layer < RWI_MAX_LAYER; Layer++ )
      {
        WinRec = WinList->LAYERTAB[ Layer ];
        
        while ( WinRec != (rdswinrec_list *)NULL )
        {
          DelWinRec = WinRec;
          WinRec    = WinRec->NEXT;

          freerdswinrec( DelWinRec );
        }
      }

      WinList = WinList + 1;
    }

    freerdswin( RdsWindow->WINTAB );
    freerdswindow( RdsWindow );
  }

/*------------------------------------------------------------\
|                                                             |
|                        View Rds Window                      |
|                                                             |
\------------------------------------------------------------*/

  void viewrdswindow( RdsWindow )

     rdswindow *RdsWindow;
  {
    rdswin_list    *ScanWin;
    rdswinrec_list *ScanWinRec;
    rdsrec_list    *Rectangle;
    long            X;
    long            Y;
    long            Xmin;
    long            Ymin;
    long            Xmax;
    long            Ymax;
    long            Counter;
    long            MaskCounter;
    char            Layer;
    char            ScanRec;

    fprintf( stdout, "\n\t--> Window\n" );
    fprintf( stdout, "\n\tXMIN : %d"  , RdsWindow->XMIN );
    fprintf( stdout, "\n\tXMAX : %d"  , RdsWindow->XMAX );
    fprintf( stdout, "\n\tYMIN : %d"  , RdsWindow->YMIN );
    fprintf( stdout, "\n\tYMAX : %d"  , RdsWindow->YMAX );
    fprintf( stdout, "\n\tMASK : %d"  , RdsWindow->MASK );
    fprintf( stdout, "\n\tDX   : %d"  , RdsWindow->DX   );
    fprintf( stdout, "\n\tDY   : %d"  , RdsWindow->DY   );
    fprintf( stdout, "\n\tSIDE : %d"  , RdsWindow->SIDE );
    fprintf( stdout, "\n\tSIZE : %d\n", RdsWindow->SIZE );

    fprintf( stdout, "\n\t--> Dump all windows\n" );

    if ( RdsWindow->SIZE != 0 )
    {
      Ymin = RdsWindow->YMIN;
      Ymax = RdsWindow->SIDE + Ymin;
      Y    = 0;

      MaskCounter = 0;
   
      while ( Y < RdsWindow->DY )
      {
        Xmin = RdsWindow->XMIN;
        Xmax = RdsWindow->SIDE + Xmin;
        X    = 0;

        ScanWin = RdsWindow->WINTAB + ( Y * RdsWindow->DX );

        while ( X < RdsWindow->DX )
        {
          fprintf( stdout, "\n\t--> Window[ %d, %d ]\n", X, Y );

          fprintf( stdout, "\n\tXMIN : %d"  , Xmin );
          fprintf( stdout, "\n\tYMIN : %d"  , Ymin );
          fprintf( stdout, "\n\tXMAX : %d"  , Xmax );
          fprintf( stdout, "\n\tYMAX : %d\n", Ymax );

          Counter = 0;

          for ( Layer = 0; Layer < RWI_MAX_LAYER; Layer++ )
          {
            for ( ScanWinRec  = ScanWin->LAYERTAB[ Layer ];
                  ScanWinRec != (rdswinrec_list *)NULL;
                  ScanWinRec  = ScanWinRec->NEXT )
            {
              for ( ScanRec = 0; ScanRec < RWI_MAX_REC ; ScanRec++ )
              {
                Rectangle = ScanWinRec->RECTAB[ ScanRec ];
 
                if ( Rectangle != (rdsrec_list *)NULL )
                {
                  if ( ( Rectangle->X < Xmax                 ) &&
                       ( Rectangle->Y < Ymax                 ) &&
                       ( Rectangle->X + Rectangle->DX > Xmin ) &&
                       ( Rectangle->Y + Rectangle->DY > Ymin ) )
                  {
                    Counter = Counter + 1;
                  }

                  viewrdsrec( Rectangle );
                }
              }
            }
          }

          MaskCounter = MaskCounter + Counter;

          fprintf( stdout, "\n\t<-- Total rectangles %d", Counter );
          
          Xmin = Xmax;
          Xmax = Xmax + RdsWindow->SIDE;
          X    = X + 1;

          ScanWin = ScanWin + 1;
        }

        Ymin = Ymax;
        Ymax = Ymax + RdsWindow->SIDE;
        Y    = Y + 1;
      }
    }

    fprintf( stdout, "\n<-- Total Rectangles %d\n", MaskCounter );
  }
