/* $NoKeywords: $ */
/*
//
// Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
// McNeel & Associates.
//
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
//				
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
//
////////////////////////////////////////////////////////////////
*/

#include "opennurbs.h"

#if !defined(ON_COMPILING_OPENNURBS)
// This check is included in all opennurbs source .c and .cpp files to insure
// ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled.
// When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined 
// and the opennurbs .h files alter what is declared and how it is declared.
#error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs
#endif


bool ON_Brep::IsValidForV2( const ON_BrepTrim& trim ) const
{
  int ti = trim.m_trim_index;
  if ( ti < 0 || ti >= m_T.Count() )
    return false;
  if ( &trim != &m_T[ti] )
    return false;
  if ( trim.ProxyCurveIsReversed() )
    return false;
  if ( trim.Domain() != trim.ProxyCurveDomain() )
    return false;
  const ON_Curve * curve = trim.TrimCurveOf();
  if ( curve != trim.ProxyCurve() )
    return false;
  const ON_NurbsCurve* nurbs_curve = ON_NurbsCurve::Cast(curve);
  if ( 0 == nurbs_curve )
    return false;
  if ( !nurbs_curve->IsClamped(2) )
    return false;
  if ( nurbs_curve->m_dim != 2 )
    return false;
  if ( nurbs_curve->m_is_rat )
  {
    // 2 June 2003 Dale Lear - RR 8809 fix
    //    V2 likes end weights to be 1.0
    if ( nurbs_curve->m_cv[2] != 1.0 || nurbs_curve->CV(nurbs_curve->m_cv_count-1)[2] != 1.0 )
    {
      return false;
    }
  }

  if (    nurbs_curve->m_cv_count >= 4 
       && 0 == ON_ComparePoint( nurbs_curve->m_dim, nurbs_curve->m_is_rat, nurbs_curve->m_cv, nurbs_curve->CV(nurbs_curve->m_cv_count-1) ) 
       )
  {
    // 14 April 2003 Dale Lear
    //     RR 8843 - V2 wants ends of this trim farther apart
    if ( trim.m_vi[0] != trim.m_vi[1] )
    {
      const ON_BrepLoop* loop = Loop(trim.m_li);
      if ( 0 != loop && loop->m_ti.Count() > 1 )
        return false;
    }
  }
  
  if ( curve->Domain() != trim.Domain() )
    return false;


  return true;
}

bool ON_Brep::IsValidForV2( const ON_BrepEdge& edge ) const
{
  int ei = edge.m_edge_index;
  if ( ei < 0 || ei >= m_E.Count() )
    return false;
  if ( &edge != &m_E[ei] )
    return false;
  if ( edge.ProxyCurveIsReversed() )
    return false;
  if ( edge.Domain() != edge.ProxyCurveDomain() )
    return false;
  const ON_Curve * curve = edge.EdgeCurveOf();
  if ( curve != edge.ProxyCurve() )
    return false;
  const ON_NurbsCurve* nurbs_curve = ON_NurbsCurve::Cast(curve);
  if ( 0 == nurbs_curve )
    return false;
  if ( !nurbs_curve->IsClamped(2) )
    return false;
  if ( nurbs_curve->m_dim != 3 )
    return false;
  if ( nurbs_curve->m_is_rat )
  {
    // 2 June 2003 Dale Lear - RR 8809 fix
    //    V2 likes end weights to be 1.0
    if ( nurbs_curve->m_cv[3] != 1.0 || nurbs_curve->CV(nurbs_curve->m_cv_count-1)[3] != 1.0 )
    {
      return false;
    }
  }

  if ( curve->Domain() != edge.Domain() )
    return false;

  // 14 April 2003 Dale Lear
  //     RR 8808 - V2 requires edges to be strictly closed/open
  if (    nurbs_curve->m_cv_count >= 4 
       && 0 == ON_ComparePoint( nurbs_curve->m_dim, nurbs_curve->m_is_rat, nurbs_curve->m_cv, nurbs_curve->CV(nurbs_curve->m_cv_count-1) ) 
       )
  {
    if ( edge.m_vi[0] != edge.m_vi[1] )
      return false;
  }
  else if (edge.m_vi[0] == edge.m_vi[1] )
  {
    return false;
  }


  return true;
}

bool ON_Brep::IsValidForV2() const
{
  bool rc = IsValidTopology()?true:false;
  if ( rc )
  {
    int c2i, c3i, si, ti, li, ei, vi, fi, next_ti, lti, next_lti, loop_trim_count;
    ON_3dPoint P0, P1;

    const int c2_count = m_C2.Count();
    const int c3_count = m_C3.Count();
    const int s_count  = m_S.Count();
    const int vertex_count = m_V.Count();
    const int edge_count = m_E.Count();
    const int face_count = m_F.Count();
    const int loop_count = m_L.Count();
    const int trim_count = m_T.Count();

    for ( c2i = 0; c2i < c2_count; c2i++ )
    {
      // v2 3dm files expect NURBS curves
      if ( !ON_NurbsCurve::Cast(m_C2[c2i]) )
        return false;
    }

    for ( c3i = 0; c3i < c3_count; c3i++ )
    {
      // v2 3dm files expect NURBS curves
      if ( !ON_NurbsCurve::Cast(m_C3[c3i]) )
        return false;
    }

    for ( si = 0; si < s_count; si++ )
    {
      // v2 3dm files expect NURBS surfaces
      if ( !ON_NurbsSurface::Cast(m_S[si]) )
        return false;
    }

    for ( vi = 0; vi < vertex_count; vi++ )
    {
      const ON_BrepVertex& vertex = m_V[vi];
      if ( vertex.m_vertex_index != vi )
        return false;
    }

    for ( fi = 0; fi < face_count; fi++ )
    {
      const ON_BrepFace& face = m_F[fi];
      if ( face.m_face_index != fi )
        return false;
    }

    for ( ti = 0; ti < trim_count; ti++ )
    {
      if ( !IsValidForV2( m_T[ti] ) )
        return false;
    }

    for ( ei = 0; ei < edge_count; ei++ )
    {
      if ( !IsValidForV2(m_E[ei]) )
        return false;
    }

    for ( li = 0; li < loop_count; li++ )
    {
      const ON_BrepLoop& loop = m_L[li];
      if ( loop.m_loop_index == -1 )
        return false;
      loop_trim_count = loop.m_ti.Count();
      for ( lti = 0; lti < loop_trim_count; lti++ )
      {
        next_lti = (lti+1)%loop_trim_count;
        ti = loop.m_ti[lti];
        next_ti = loop.m_ti[next_lti];
        if ( ti < 0 || ti >= trim_count )
          return false;
        if ( next_ti < 0 || next_ti >= trim_count )
          return false;
        P0 = m_T[ti].PointAtEnd();
        P1 = m_T[next_ti].PointAtStart();
        if ( P0.DistanceTo(P1) > ON_ZERO_TOLERANCE )
          return false;
      }
    }
  }

  return rc;
}

