/*************************************************************************************

   Extended WPF Toolkit

   Copyright (C) 2007-2013 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license 

   For more features, controls, and fast professional support,
   pick up the Plus Edition at http://xceed.com/wpf_toolkit

   Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids

  ***********************************************************************************/

using System;
using System.Runtime.InteropServices;
using System.Windows;

namespace Xceed.Wpf.Toolkit.Core.Utilities
{
  internal static class DoubleHelper
  {
    public static bool AreVirtuallyEqual( double d1, double d2 )
    {
      if( double.IsPositiveInfinity( d1 ) )
        return double.IsPositiveInfinity( d2 );

      if( double.IsNegativeInfinity( d1 ) )
        return double.IsNegativeInfinity( d2 );

      if( IsNaN( d1 ) )
        return IsNaN( d2 );

      double n = d1 - d2;
      double d = ( Math.Abs( d1 ) + Math.Abs( d2 ) + 10 ) * 1.0e-15;
      return ( -d < n ) && ( d > n );
    }

    public static bool AreVirtuallyEqual( Size s1, Size s2 )
    {
      return ( AreVirtuallyEqual( s1.Width, s2.Width )
          && AreVirtuallyEqual( s1.Height, s2.Height ) );
    }

    public static bool AreVirtuallyEqual( Point p1, Point p2 )
    {
      return ( AreVirtuallyEqual( p1.X, p2.X )
          && AreVirtuallyEqual( p1.Y, p2.Y ) );
    }

    public static bool AreVirtuallyEqual( Rect r1, Rect r2 )
    {
      return ( AreVirtuallyEqual( r1.TopLeft, r2.TopLeft )
          && AreVirtuallyEqual( r1.BottomRight, r2.BottomRight ) );
    }

    public static bool AreVirtuallyEqual( Vector v1, Vector v2 )
    {
      return ( AreVirtuallyEqual( v1.X, v2.X )
          && AreVirtuallyEqual( v1.Y, v2.Y ) );
    }

    public static bool AreVirtuallyEqual( Segment s1, Segment s2 )
    {
      // note: Segment struct already uses "virtually equal" approach
      return ( s1 == s2 );
    }

    public static bool IsNaN( double value )
    {
      // used reflector to borrow the high performance IsNan function 
      // from the WPF MS.Internal namespace
      NanUnion t = new NanUnion();
      t.DoubleValue = value;

      UInt64 exp = t.UintValue & 0xfff0000000000000;
      UInt64 man = t.UintValue & 0x000fffffffffffff;

      return ( exp == 0x7ff0000000000000 || exp == 0xfff0000000000000 ) && ( man != 0 );
    }

    #region NanUnion Nested Types

    [StructLayout( LayoutKind.Explicit )]
    private struct NanUnion
    {
      [FieldOffset( 0 )]
      internal double DoubleValue;
      [FieldOffset( 0 )]
      internal UInt64 UintValue;
    }

    #endregion
  }
}
