// SERVER-2386, general geo-indexing using very large and very small bounds

load( "jstests/libs/geo_near_random.js" );

// Do some random tests (for near queries) with very large and small ranges

var test = new GeoNearRandomTest( "geo_small_large" );

bounds = { min : -Math.pow( 2, 34 ), max : Math.pow( 2, 34 ) };

test.insertPts( 50, bounds );

printjson( db["geo_small_large"].find().limit( 10 ).toArray() )

test.testPt( [ 0, 0 ] );
test.testPt( test.mkPt( undefined, bounds ) );
test.testPt( test.mkPt( undefined, bounds ) );
test.testPt( test.mkPt( undefined, bounds ) );
test.testPt( test.mkPt( undefined, bounds ) );

test = new GeoNearRandomTest( "geo_small_large" );

bounds = { min : -Math.pow( 2, -34 ), max : Math.pow( 2, -34 ) };

test.insertPts( 50, bounds );

printjson( db["geo_small_large"].find().limit( 10 ).toArray() )

test.testPt( [ 0, 0 ] );
test.testPt( test.mkPt( undefined, bounds ) );
test.testPt( test.mkPt( undefined, bounds ) );
test.testPt( test.mkPt( undefined, bounds ) );
test.testPt( test.mkPt( undefined, bounds ) );


// Check that our box and circle queries also work
var scales = [ Math.pow( 2, 40 ), Math.pow( 2, -40 ), Math.pow(2, 2), Math.pow(3, -15), Math.pow(3, 15) ]

for ( var i = 0; i < scales.length; i++ ) {

	scale = scales[i];

	var eps = Math.pow( 2, -7 ) * scale;
	var radius = 5 * scale;
	var max = 10 * scale;
	var min = -max;
	var range = max - min;
	var bits = 2 + Math.random() * 30
	
	var t = db["geo_small_large"]
	t.drop();
	t.ensureIndex( { p : "2d" }, { min : min, max : max, bits : bits })

	var outPoints = 0;
	var inPoints = 0;
	
	printjson({ eps : eps, radius : radius, max : max, min : min, range : range, bits : bits })
	
	// Put a point slightly inside and outside our range
	for ( var j = 0; j < 2; j++ ) {
		var currRad = ( j % 2 == 0 ? radius + eps : radius - eps );
		t.insert( { p : { x : currRad, y : 0 } } );
		print( db.getLastError() )
	}
	
	printjson( t.find().toArray() );

	assert.eq( t.count( { p : { $within : { $center : [[0, 0], radius ] } } } ), 1, "Incorrect center points found!" )
	assert.eq( t.count( { p : { $within : { $box : [ [ -radius, -radius ], [ radius, radius ] ] } } } ), 1,
			"Incorrect box points found!" )
			
	shouldFind = []
	randoms = []
		
	for ( var j = 0; j < 2; j++ ) {
		
		var randX = Math.random(); // randoms[j].randX
		var randY = Math.random(); // randoms[j].randY
		
		randoms.push({ randX : randX, randY : randY })
		
		var x = randX * ( range - eps ) + eps + min;
		var y = randY * ( range - eps ) + eps + min;

		t.insert( { p : [ x, y ] } );

		if ( x * x + y * y > radius * radius ){
			// print( "out point ");
			// printjson({ x : x, y : y })
			outPoints++
		}
		else{
			// print( "in point ");
			// printjson({ x : x, y : y })
			inPoints++
			shouldFind.push({ x : x, y : y, radius : Math.sqrt( x * x + y * y ) })
		}
	}
	
	/*
	function printDiff( didFind, shouldFind ){
		
		for( var i = 0; i < shouldFind.length; i++ ){
			var beenFound = false;			
			for( var j = 0; j < didFind.length && !beenFound ; j++ ){
				beenFound = shouldFind[i].x == didFind[j].x &&
							shouldFind[i].y == didFind[j].y
			}
			
			if( !beenFound ){
				print( "Could not find: " )
				shouldFind[i].inRadius = ( radius - shouldFind[i].radius >= 0 )
				printjson( shouldFind[i] )
			}
		}
	}
		
	print( "Finding random pts... ")
	var found = t.find( { p : { $within : { $center : [[0, 0], radius ] } } } ).toArray()
	var didFind = []
	for( var f = 0; f < found.length; f++ ){
		//printjson( found[f] )
		var x = found[f].p.x != undefined ? found[f].p.x : found[f].p[0]
		var y = found[f].p.y != undefined ? found[f].p.y : found[f].p[1]
		didFind.push({ x : x, y : y, radius : Math.sqrt( x * x + y * y ) })
	}
	
	print( "Did not find but should: ")
	printDiff( didFind, shouldFind )
	print( "Found but should not have: ")
	printDiff( shouldFind, didFind )
	*/
	
	assert.eq( t.count( { p : { $within : { $center : [[0, 0], radius ] } } } ), 1 + inPoints,
			"Incorrect random center points found!\n" + tojson( randoms ) )
			
	print("Found " + inPoints + " points in and " + outPoints + " points out.");
	
	var found = t.find( { p : { $near : [0, 0], $maxDistance : radius } } ).toArray()
	var dist = 0;
	for( var f = 0; f < found.length; f++ ){
		var x = found[f].p.x != undefined ? found[f].p.x : found[f].p[0]
		var y = found[f].p.y != undefined ? found[f].p.y : found[f].p[1]
		print( "Dist: x : " + x + " y : " + y + " dist : " + Math.sqrt( x * x + y * y) + " radius : " + radius )
	}	
	
	assert.eq( t.count( { p : { $near : [0, 0], $maxDistance : radius } } ), 1 + inPoints,
			   "Incorrect random center points found near!\n" + tojson( randoms ) )

}

