// Vorosweep - Copyright (C) 2010-2014 T. Mouton
//
// See the LICENSE.txt file for license information. Please report all
// bugs and problems to <thibaud.mouton@gmail.com>.

#include "vorosweep.h"

using namespace vorosweep;

void Graph::handle_edge_facetcrash ( Event *ev )
{
  SweepEdge *se = ev->get_sweepedge ( 0 );

  if ( se->is_stopped() )
    return;

  SweepFacet *msf = ev->get_sweepfacet ( 1 );
  FrontLine *mfl = msf->get_frontline();

  se->print();
  msf->print();

  double *pos = ev->get_coord();
  double time = ev->get_time();

  Front *mfr = mfl->get_including_front ( pos, time );

  if ( !mfr ) // check if point is not included into a front of frontline
  {
//     Event *ne = se->get_earliest_event();
//     if ( ne )
//       add_event ( ne );
    add_earliest_event(se);
    return;
  }

  dbgprintf ( 5, "sweepedge : %p; sweepfacet %p\n", se, msf );
  dbgprintf ( 5, "sweepedge dir --> %lf %lf\n",  se->get_dir2d() [0], se->get_dir2d() [1] );
  dbgprintf ( 5, "sweepfacet dir --> %lf %lf\n",  msf->get_dir2d() [0], msf->get_dir2d() [1] );

  dbgprintf ( 2, "sweepedge %p --> is init : %d\n",  se, se->is_init() );
  
  if ( !se->is_init() )
    return;

  int gid = ev->get_gid();

  // update sweepedges
  SweepEdge *sefr[2];
  sefr[0] = mfr->get_sweepedge ( 0 );
  sefr[1] = mfr->get_sweepedge ( 1 );

  se->update_current ( time );
  sefr[0]->update_current ( time );
  sefr[1]->update_current ( time );

  SweepFacet *esf[2];
  // cas general
  esf[0] = msf;
  esf[1] = msf;

#if defined (DURTY)
//   special cases
  if ( geom::sqrtdistance2d ( sefr[0]->get_current()->p, se->get_current()->p ) < Graph::epsilon )
  {
    dbgprintf (1, "/!\\ --> edge_facetcrash special case 0\n" );
    esf[0] = sefr[0]->get_front ( 0 )->get_owner();
  }
  else if ( geom::sqrtdistance2d ( sefr[1]->get_current()->p, se->get_current()->p ) < Graph::epsilon )
  {
    dbgprintf (1,  "/!\\ --> edge_facetcrash special case 1\n" );
    esf[1] = sefr[1]->get_front ( 1 )->get_owner();
  }
#endif


  double ndir[2][3];

  for ( int i = 0; i < 2; i++ )
  {
    SweepFacet *sf = se->get_sweepfacet ( i );
    if ( sf )
    {
      dbgprintf ( 5, "sf --> %p\n", sf );
      // compute new directions
      if ( i == 0 )
        geom::cross_product3d ( sf->get_plane(), esf[0]->get_plane(), ndir[i] );
      else
        geom::cross_product3d ( esf[1]->get_plane(), sf->get_plane(), ndir[i] );

      geom::normalize3d ( ndir[i] );
      // check
      if ( ndir[i][2] < 0.0 )
      {
        dbgprintf ( 2, "ndir[2] < 0.0 --> return\n" );
        return;
      }
    }
  }

  se->set_stopped();

  // create new edges
  SweepEdge *elist[2];
  int nbedge = 0;
  for ( int i = 0; i < 2; i++ )
  {
    SweepFacet *sf = se->get_sweepfacet ( i );
    if ( sf )
    {
      dbgprintf ( 2, "sf --> %p\n", sf );
      dbgprintf ( 5, "dot product --> %lf\n", geom::scalar_product2d ( sf->get_dir2d(), ndir[i] ) );
      dbgprintf ( 5, "plane dir --> %lf %lf\n",  sf->get_dir2d() [0], sf->get_dir2d() [1] );
      dbgprintf ( 2, "new dir --> %.20lf %.20lf %.20lf\n", ndir[i][0], ndir[i][1], ndir[i][2] );

      if ( ndir[i][2] >= Graph::epsilon || fabs ( ndir[i][2] ) < Graph::epsilon )
      {
        if ( fabs ( ndir[i][2] ) < Graph::epsilon )
        {
          dbgprintf ( 2, "--> horizontal dir\n" );
          ndir[i][2] = 0.0;
#if defined(DURTY)
          // we check if the opposite edge is sharing sf and msf
          SweepEdge *cse = mfr->get_sweepedge ( ( i+1 ) %2 );
          if (cse->get_sweepfacet(i) == msf && cse->get_sweepfacet((i+1)%2) == sf)
          {
            printf("continuing ...\n");
            continue;
          }
#endif
        }

        SweepEdge *nse = new SweepEdge ( se->get_current(), ndir[i], time );

        nse->update_speeds ( sf );
        FrontLine *fl = sf->get_frontline();
        fl->update_sweepedge ( se, nse );

        // add switch event
        Event *nes = econtainer->get();
        nes->init ( nse, nse->get_start()->p, time, Event::NEWEDGESWITCH, gid );
        add_priority_event ( nes );
        elist[nbedge++] = nse;
        
//         if ( fabs ( nse->get_dir3d() [2] ) < Graph::epsilon )
//         {
//           dbgprintf ( 2, "--> horizontal dir\n" );
//           // we disable the next event edge/facet of both edge and facet
//           SweepEdge *cse = mfr->get_sweepedge ( ( i+1 ) %2 );
//           cse->disable_futur_event ( cse, sf );          
//         }
      }
    }
  }
  dbgprintf ( 5, "nbedge --> %d\n", nbedge );
  if ( esf[0] == esf[1] )
  {
    FrontLine *fl = msf->get_frontline();
    fl->insert_edges ( elist[1], elist[0], pos, time ); // note the change in orientation
  }
  else if ( esf[0] == msf )
  {
    esf[1]->get_frontline()->update_sweepedge ( se, elist[0] );
  }
  else if ( esf[1] == msf )
  {
    esf[0]->get_frontline()->update_sweepedge ( se, elist[1] );
  }
}

