// Test Suite for GeoLocation API
// Inspired in: http://code.google.com/p/gears/source/browse/trunk/gears/test/testcases/geolocation_tests.js
//
// Copyright 2008, Google Inc.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//  1. Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//  2. Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//  3. Neither the name of Google Inc. nor the names of its contributors may be
//     used to endorse or promote products derived from this software without
//     specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Global variables
var watchCount;
var watchId;
var watchStopped;
var watchWarningNumber;
var positionTimeout1 = 120000; // 2 minutes timeout
var positionTimeout2 = 600000; // 10 minutes timeout

// For Asynchronous calls (callback functions) ------------

function onPositionSuccess(position) {
	assertEqual(1, 1, "Async call finished OK");
	formatDebugMessage("Position found: longitude " + position.coords.longitude + ", latitude " + position.coords.latitude);
	endAsync();
}

// this function will handle each error in position updates
function onPositionError(error) {
	//rsd: assertEqual(1, 0, "Async call finished with errors: " + error.message);
	assertError(1, 0, "Async call finished with errors: " + error.message);
	endAsync();
}

function onWatchPositionSuccess(position) {
	watchCount++;
//	formatDebugMessage("Position found: longitude " + position.coords.longitude + ", latitude " + position.coords.latitude);
	checkWatch("Watch position success callback(longitude " + position.coords.longitude + ", latitude " + position.coords.latitude +"), result number "+watchCount);
	/*
	if(watchCount >= 2) {
		if (!watchStopped) {
			watchStopped = true;
			formatDebugMessage("Now clearing the watch...");
			clearWatch(watchId);
			endAsync();
		}
		else {
			if (!watchWarningRaised) {
				formatDebugMessage("ClearWatch didn't work - still receiving callbacks...");
				watchWarningRaised = true;
			}
		}
	}
	else {
		formatDebugMessage("Watch position success callback, result number "+watchCount);
	}*/
}

// this function will handle each error in position updates
function onWatchPositionError(error) {
	watchCount++;
	checkWatch("Watch position error callback, result number "+watchCount);
/*
	formatDebugMessage("Watch position error callback, result number "+watchCount);
	if(watchCount == 2) {
		formatDebugMessage("Now clearing the watch...");
		clearWatch(watchId);
		endAsync();
	}*/
}

function checkWatch(warnMessage) {
	if(watchCount >= 3) {
		if (!watchStopped) {
			formatDebugMessage(warnMessage);
			watchStopped = true;
			formatDebugMessage("Now clearing the watch - id is " + watchId);
			clearWatch(watchId);
			endAsync();
		}
		else {
			if (watchWarningNumber < 5) {
				formatDebugMessage("ClearWatch didn't work - still receiving callbacks...");
				watchWarningNumber ++;
			}
		}
	}
	else {
		formatDebugMessage(warnMessage);
	}
}

function dummyCallback(param) {
	endAsync();
}

function dummyCallback2(param) {
	assert(false, "This callback should not be called");
	endAsync();
}

function timeoutCallback(error) {
	assertEqual(error.TIMEOUT, error.code, 'Error callback should be called with code TIMEOUT.');
	endAsync();
}

// End Callbacks ------------------------------------------

//Test properties
function test0_Properties() {
	formatDebugMessage("<br/><br/>Geolocation positive tests");
	formatDebugMessage("<br/><br/>Geolocation test properties");
//	assertEqual(0, bondi.geolocation.UNKNOWN_ERROR, "Unknown error value differs from specification");
//	assertEqual(1, bondi.geolocation.PERMISSION_DENIED, "permission denied error value differs from specification");
//	assertEqual(2, bondi.geolocation.POSITION_UNAVAILABLE, "position unavailable value differs from specification");
//	assertEqual(3, bondi.geolocation.TIMEOUT , "timeout value differs from specification");
}

function test1_goodCalls_0()
{
	formatDebugMessage("<br/><br/>Testing: getCurrentPosition(dummyCallback)");
	beginAsync(positionTimeout1);
	bondi.geolocation.getCurrentPosition(dummyCallback);
//	endAsync();
}

function test1_goodCalls_1()
{
	formatDebugMessage("<br/><br/>Testing: getCurrentPosition(dummyCallback, dummyCallback)");
	beginAsync(positionTimeout1);
	bondi.geolocation.getCurrentPosition(dummyCallback, dummyCallback);
//	endAsync();
}

function test1_goodCalls_2()
{
	formatDebugMessage("<br/><br/>Testing: getCurrentPosition(dummyCallback, null)");
	beginAsync();
	bondi.geolocation.getCurrentPosition(dummyCallback, null);
//	endAsync();
}

function test1_goodCalls_3()
{
	formatDebugMessage("<br/><br/>Testing: getCurrentPosition(dummyCallback, null, {})");
	beginAsync();
	bondi.geolocation.getCurrentPosition(dummyCallback, null, {});
//	endAsync();
}

function test1_goodCalls_4()
{
	var goodOptions = {
		enableHighAccuracy: false,
		maximumAge: 0,
		timeout: 0
	};

	formatDebugMessage("<br/><br/>Testing: getCurrentPosition(dummyCallback, null, goodOptions)");
	beginAsync();
	bondi.geolocation.getCurrentPosition(dummyCallback, null, goodOptions);
//	endAsync();
}

function test1_goodCalls_5()
{
	formatDebugMessage("<br/><br/>Testing: getCurrentPosition(dummyCallback, dummyCallback, {})");
	beginAsync();
	bondi.geolocation.getCurrentPosition(dummyCallback, dummyCallback, {});
//	endAsync();
}

function test1_goodCalls_6()
{
	var goodOptions = {
		enableHighAccuracy: false,
		maximumAge: 0,
		timeout: 0
	};

	formatDebugMessage("<br/><br/>Testing: getCurrentPosition(dummyCallback, dummyCallback, goodOptions)");
	beginAsync();
	bondi.geolocation.getCurrentPosition(dummyCallback, dummyCallback, goodOptions);
//	endAsync();
}

function test2_forceRanges_0()
{
	// Test correct types.
	// Missing success callback.
	//assertError(function() {
	//	bondi.geolocation.getCurrentPosition();
	//});

	// Wrong type for success callback.
	formatDebugMessage("<br/><br/>Testing: getCurrentPosition (wrong type success callback)");
	assertError(function() {
		bondi.geolocation.getCurrentPosition(42);
	});
//	endAsync();
}

function test2_forceRanges_1()
{
	// Wrong type for error callback.
	formatDebugMessage("<br/><br/>Testing: getCurrentPosition (wrong type error callback)");
	assertError(function() {
//		beginAsync();
		bondi.geolocation.getCurrentPosition(dummyCallback2, 42);
	});
//	endAsync();
}

function test2_forceRanges_2()
{
	// Wrong type for options.
	formatDebugMessage("<br/><br/>Testing: getCurrentPosition (wrong type options)");
	assertError(function() {
//		beginAsync();
		bondi.geolocation.getCurrentPosition(dummyCallback2, dummyCallback2, 42);
	});
//	endAsync();
}

function test2_forceRanges_3()
{
	// Wrong type for enableHighAccuracy.
	formatDebugMessage("<br/><br/>Testing: getCurrentPosition (wrong enableHighAccuracy)");
	assertError(function() {
//		beginAsync();
		bondi.geolocation.getCurrentPosition(dummyCallback2,
								   dummyCallback2,
								   {enableHighAccuracy: 42});
	}, 'options.enableHighAccuracy should be a boolean.');
//	endAsync();
}

// Wrong type for maximumAge.
var maximumAgeTypeError = 'options.maximumAge should be a non-negative 32 ' +
						'bit signed integer or Infinity.';

function test2_forceRanges_4()
{
	formatDebugMessage("<br/><br/>Testing: getCurrentPosition (wrong type maximumAge)");
	assertError(function() {
//		beginAsync();
		bondi.geolocation.getCurrentPosition(dummyCallback2,
								   dummyCallback2,
								   {maximumAge: 42.9});
	}, maximumAgeTypeError);
//	endAsync();
}

function test2_forceRanges_5()
{
	formatDebugMessage("<br/><br/>Testing: getCurrentPosition (wrong value maximumAge)");
	assertError(function() {
//		beginAsync();
		bondi.geolocation.getCurrentPosition(dummyCallback2,
								   dummyCallback2,
								   {maximumAge: -1});
	}, maximumAgeTypeError);
//	endAsync();
}

function test2_forceRanges_6()
{
	formatDebugMessage("<br/><br/>Testing: getCurrentPosition (wrong value maximumAge - 2)");
	assertError(function() {
//		beginAsync();
		bondi.geolocation.getCurrentPosition(dummyCallback2,
								   dummyCallback2,
								   {maximumAge: 2147483648});  // 2^31
	}, maximumAgeTypeError);
//	endAsync();
}

function test2_forceRanges_7()
{
	formatDebugMessage("<br/><br/>Testing: getCurrentPosition (wrong maximumAge)");
	assertError(function() {
//		beginAsync();
		bondi.geolocation.getCurrentPosition(dummyCallback2,
								   dummyCallback2,
								   {maximumAge: -Infinity});
	}, maximumAgeTypeError);
//	endAsync();
}

// Wrong type for timeout.
var timeoutTypeError = 'options.timeout should be a non-negative 32 bit ' +
					 'signed integer.';

function test2_forceRanges_8()
{
	formatDebugMessage("<br/><br/>Testing: getCurrentPosition (wrong type timeout)");
	assertError(function() {
//		beginAsync();
		bondi.geolocation.getCurrentPosition(dummyCallback2,
								   dummyCallback2,
								   {timeout: 42.9});
	}, timeoutTypeError);
//	endAsync();
}

function test2_forceRanges_9()
{
	formatDebugMessage("<br/><br/>Testing: getCurrentPosition (wrong value timeout)");
	assertError(function() {
//		beginAsync();
		bondi.geolocation.getCurrentPosition(dummyCallback2,
								   dummyCallback2,
								   {timeout: -10});
	}, timeoutTypeError);
//	endAsync();
}

function test2_forceRanges_10()
{
	formatDebugMessage("<br/><br/>Testing: getCurrentPosition (wrong value timeout - 2)");
	assertError(function() {
//		beginAsync();
		bondi.geolocation.getCurrentPosition(dummyCallback2,
								   dummyCallback2,
								   {timeout: 2147483648});  // 2^31
	}, timeoutTypeError);
//	endAsync();
}

function test3_ZeroTimeout() {
	// A request with a zero timeout should call the error callback immediately.
	formatDebugMessage("<br/><br/>Testing: getCurrentPosition with 0 timeout");
	beginAsync();
	bondi.geolocation.getCurrentPosition(dummyCallback2, timeoutCallback, {timeout: 0});
//		endAsync();
}

function test4_getCurrentPosition()
{
	formatDebugMessage("<br/><br/>Geolocation getCurrentPosition");

	beginAsync();
	bondi.geolocation.getCurrentPosition(onPositionSuccess, onPositionError, {timeout:30});
//	endAsync();
}

function test5_getStoredPosition()
{
	formatDebugMessage("<br/><br/>Geolocation getStoredPosition");

	beginAsync();
	bondi.geolocation.getCurrentPosition(onPositionSuccess, onPositionError, {maximumAge:600000, timeout:0});
//	endAsync();
}

/**
 * \brief Tests to watch the position.
 *
 * This test requires the geolocation.position API feature and asserts that the position can be accessed.
 * The test ends successfully when a second callback is received
 *
 * \api-feature http://bondi.omtp.org/api/geolocation.position
 * \id watchPositionPermitted/1
 * \assert The position can be accessed.
 * \policy default
 */
function test6_watchPosition() {
	beginAsync();
	watchCount = 0;
	watchStopped = false;
	watchWarningNumber = 0;
	watchId = bondi.geolocation.watchPosition(onWatchPositionSuccess, onWatchPositionError, {maximumAge:0, timeout:0});
	formatDebugMessage("<br/><br/>Geolocation watchPosition - id is " + watchId);
}


/**
 * \brief Error test to clear the watch
 *
 * This test calls clearWatch with wrong parameter
 *
 * \api-feature http://bondi.omtp.org/api/geolocation.position
 * \id clearWatchError/1
 * \assert An exception is thrown
 * \policy default
 */
function test7_clearWatchErr1() {
	formatDebugMessage("<br/><br/>Testing clearWatch error - 1");
	assertError(function() {
		bondi.geolocation.clearWatch();
	}, "clearWatch with no parameter did not raise exception");
}


/**
 * \brief Error test to clear the watch
 *
 * This test calls clearWatch with wrong parameter
 *
 * \api-feature http://bondi.omtp.org/api/geolocation.position
 * \id clearWatchError/2
 * \assert An exception is thrown
 * \policy default
 */
function test8_clearWatchErr2() {
	formatDebugMessage("<br/><br/>Testing clearWatch error - 2");
	assertError(function() {
		bondi.geolocation.clearWatch(123456);
	}, "clearWatch with non valid id did not raise exception");
}


/**
 * \brief tests that bondi.geolocation.Geolocation API
 *
 * coverage: bondi.geolocation.getCurrentPosition
 */

var testcase = {
	name: "geolocation/1",
	tests: {
		"Properties": test0_Properties,
//		"Good calls 0": test1_goodCalls_0,
//		"Good calls 1": test1_goodCalls_1,
//		"Good calls 2": test1_goodCalls_2,
//		"Good calls 3": test1_goodCalls_3,
//		"Good calls 4": test1_goodCalls_4,
//		"Good calls 5": test1_goodCalls_5,
//		"Good calls 6": test1_goodCalls_6,
		"Force parameters ranges 0": test2_forceRanges_0,
		"Force parameters ranges 1": test2_forceRanges_1,
		"Force parameters ranges 2": test2_forceRanges_2,
		"Force parameters ranges 3": test2_forceRanges_3,
//		"Force parameters ranges 4": test2_forceRanges_4, // excluded because it stops the test
//		"Force parameters ranges 5": test2_forceRanges_5, // excluded because it stops the test
//		"Force parameters ranges 6": test2_forceRanges_6, // excluded because it stops the test
		"Force parameters ranges 7": test2_forceRanges_7,
//		"Force parameters ranges 8": test2_forceRanges_8, // excluded because it stops the test
//		"Force parameters ranges 9": test2_forceRanges_9, // excluded because it stops the test
//		"Force parameters ranges 10": test2_forceRanges_10, // excluded because it stops the test
		"Zero timeout": test3_ZeroTimeout,
		"getCurrentPosition": test4_getCurrentPosition,
		"getStoredPosition": test5_getStoredPosition,
		"watchPosition": test6_watchPosition,
		"clearWatchErr1": test7_clearWatchErr1,
		"clearWatchErr2": test8_clearWatchErr2
	}
};

// legacy
runTestCaseOld(testcase.name, testcase.tests);
