// 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;

function testErrorConstants() {
	bondi.geolocation.getCurrentPosition(
	function() {
		formatErrorMessage("Failed provoking error callback to test PositioError constants");
		endAsync();
	},
	function(error) {
		// TODO how can this ever work, when webvm fails to deliver error as an object?
		runTest("Testing PositionError constants", function(error) {
			//assertEqual(0, error.UNKNOWN_ERROR, "Unknown error value differs from specification");
			assertEqual(1, error.PERMISSION_DENIED, "permission denied error value differs from specification");
			assertEqual(2, error.POSITION_UNAVAILABLE, "position unavailable value differs from specification");
			assertEqual(3, error.TIMEOUT , "timeout value differs from specification");
			endAsync();
		}, error);
	},
	{
		timeout: 0
	});
}

// getCurrentPosition test callbacks
function expectedSuccess() {
	formatPassMessage("Success callback successfully called.");
	endAsync();
}

function unexpectedError(error) {
	formatErrorMessage("Error callback should not be called");
	endAsync();
}

/**
 * \brief Tests getting position success callback.
 *
 * \api-feature http://bondi.omtp.org/api/1.1/geolocation.position
 * \id getCurrentPostion/0
 * \assert Success callback called.
 * \policy permit
 */
function testGetCurrentPosition0() {
	beginAsync();
	bondi.geolocation.getCurrentPosition(expectedSuccess);
}

/**
 * \brief Tests getting position success callback.
 *
 * \api-feature http://bondi.omtp.org/api/1.1/geolocation.position
 * \id getCurrentPostion/1
 * \assert Success callback called.
 * \policy permit
 */
function testGetCurrentPosition1() {
	beginAsync();
	bondi.geolocation.getCurrentPosition(expectedSuccess, unexpectedError);
}

/**
 * \brief Tests getting position success callback.
 *
 * \api-feature http://bondi.omtp.org/api/1.1/geolocation.position
 * \id getCurrentPostion/2
 * \assert Success callback called.
 * \policy permit
 */
function testGetCurrentPosition2() {
	beginAsync();
	bondi.geolocation.getCurrentPosition(expectedSuccess, unexpectedError, {});
}

/**
 * \brief Tests getting position success callback.
 * 
 * Including position options.
 *
 * \api-feature http://bondi.omtp.org/api/1.1/geolocation.position
 * \id getCurrentPostion/3
 * \assert Success callback called.
 * \policy permit
 */
function testGetCurrentPosition3() {
	beginAsync();
	bondi.geolocation.getCurrentPosition(expectedSuccess, unexpectedError, {
		enableHighAccuracy: false,
		maximumAge: 32000000,
		timeout: 20000
	});
}

/**
 * \brief Tests getting position success callback.
 * 
 * Including position options.
 *
 * \api-feature http://bondi.omtp.org/api/1.1/geolocation.position
 * \id getCurrentPostion/4
 * \assert Success callback called.
 * \policy permit
 */
function testGetCurrentPosition4() {
	beginAsync();
	bondi.geolocation.getCurrentPosition(expectedSuccess, unexpectedError, {
		maximumAge: 32000000,
		timeout: 20000
	});
}

/**
 * \brief Tests getting position success callback.
 * 
 * Including position options.
 *
 * \api-feature http://bondi.omtp.org/api/1.1/geolocation.position
 * \id getCurrentPostion/5
 * \assert Success callback called.
 * \policy permit
 */
function testGetCurrentPosition5() {
	beginAsync();
	bondi.geolocation.getCurrentPosition(expectedSuccess, unexpectedError, {
		enableHighAccuracy: true,
		maximumAge: 32000000,
		timeout: 20000
	});
}

// callback for test below
function timeoutCallback(error) {
	runTest("Testing error in expected error callback.", function(error) {
		assertEqual(error.TIMEOUT, error.code, 'Error callback should be called with code TIMEOUT.');
		endAsync();
	}, error);
}

/**
 * \brief Tests for valid timeout error in error callback.
 * 
 * \api-feature http://bondi.omtp.org/api/1.1/geolocation.position
 * \id getCurrentPostion/6
 * \assert Error callback gets called with valid error code for timeout
 * \policy permit
 */
function testGetCurrentPosition6() {
	// A request with a zero timeout should call the error callback immediately.
	formatDebugMessage("Testing: getCurrentPosition with 0 timeout.");
	beginAsync();
	bondi.geolocation.getCurrentPosition(
	function (error) {
		formatErrorMessage("Success callback should not be called.");
		endAsync();
	},
	timeoutCallback, {
		timeout: 0
	});
}

function testResult(p) {
	assert(isObject(p), "not a valid position object");
	assert(isNumber(p.timestamp), "not a valid timestamp");
	formatDebugMessage("Timestamp: " + p.timestamp);
	assert(isObject(p.coords), "not a valid coords object");
	assert(isNumber(p.coords.latitude), "not a valid latitude value");
	formatDebugMessage("Latitude: " + p.coords.latitude);
	assert(isNumber(p.coords.longitude), "not a valid longitude value");
	formatDebugMessage("Longitude: " + p.coords.longitude);
	assert(isNumber(p.coords.altitude), "not a valid altitude value");
	formatDebugMessage("Altitude: " + p.coords.altitude);
	assert(isNumber(p.coords.accuracy), "not a valid accuracy value");
	formatDebugMessage("Accuracy: " + p.coords.accuracy);
	assert(isNumber(p.coords.altitudeAccuracy), "not a valid altitude accuracy value");
	formatDebugMessage("Altitude accuracy: " + p.coords.altitudeAccuracy);
	assert(isNumber(p.coords.heading), "not a valid heading value");
	formatDebugMessage("Heading: " + p.coords.heading);
	assert(isNumber(p.coords.speed), "not a valid speed value");
	formatDebugMessage("Speed: " + p.coords.speed);
}

/**
 * \brief Tests for a valid returned position object.
 * 
 * \api-feature http://bondi.omtp.org/api/1.1/geolocation.position
 * \id getCurrentPostion/9
 * \assert A valid position object.
 * \policy permit
 */
function testReturnedPosition() {
	beginAsync();
	bondi.geolocation.getCurrentPosition(function(position) {
		runTest("Test position and coordinates properties", testResult, position);
		endAsync();
	},
	unexpectedError, {
		maximumAge: 32000000,
		timeout: 20000
	});
}

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

function onWatchPositionSuccess(position) {
	watchCount++;
	checkWatch("Watch position success callback(longitude " + position.coords.longitude + ", latitude " + position.coords.latitude + "), result number " + watchCount);
}

// this function will handle each error in position updates
function onWatchPositionError(error) {
	watchCount++;
	checkWatch("Watch position error callback, result number " + watchCount);
}

/**
 * \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/1.1/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: 32000000,
		timeout: 10000
	});
	formatDebugMessage("Geolocation watchPosition - id is " + watchId);
}

/**
 * \brief tests that bondi.geolocation.Geolocation API
 */
var testcase = {
	name: "geolocation/1",
	tests: {
		"Test PositionError constants": testErrorConstants,
		"Test getCurrentPosition success callback 0": testGetCurrentPosition0,
		"Test getCurrentPosition success callback 1": testGetCurrentPosition1,
		"Test getCurrentPosition success callback 2": testGetCurrentPosition2,
		"Test getCurrentPosition success callback 3": testGetCurrentPosition3,
		"Test getCurrentPosition success callback 4": testGetCurrentPosition4,
		"Test getCurrentPosition success callback 5": testGetCurrentPosition5,
		"Test getCurrentPosition error callback 6": testGetCurrentPosition6,
		"Test returned position object": testReturnedPosition,
		"watchPosition": test6_watchPosition
	}
};

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

