/**
 *	AlterGeo JS-API 1.5.3-begun (getToken)
 *
 *	maxp@wi2geo.ru: 19.08.2010
 */


/*
 *	api_key: "API_ACCESS_KEY",
 *  opts: { use_bho: True, use_scanner: True, api_throttle: 1.0 }
 *  
 *  api_throttle should be in interval [0..1]
 */
function AlterGeo( api_key, opts )
{
	// begun_apikey:  AQIAAOLqS5Ny2OTs7vjfJDcD97zn4cmN
	
	var api_key = api_key, api_ver = "1.2";

	var use_bho = true;
	var use_scanner = true;
	var api_throttle = 1.0;
	
	if( opts ) {
		if( opts.use_bho != undefined ) { use_bho = opts.use_bho; }
		if( opts.use_scanner != undefined ) { use_scanner = opts.use_scanner; }
		if( opts.api_throttle != undefined ) { api_throttle = opts.api_throttle; }
	}
	
	var scanner_ver = undefined;	// [ undefined, "", "xx.xx.xx" ]
									// empty string means "on scanner response"
	
	this.OK = 1;
	this.ERR_SCANNER 		= -1;	// scanner failure
	this.ERR_API_RESPONSE	= -2;	// api connection problem
	this.ERR_API_FAILURE	= -3;	// api report an error (bad key)
	this.ERR_UNEXPECTED     = -99;

	var SCANNER_DATA  = "http://localhost:8889/js-data/";
	var SCANNER_CHECK = "http://localhost:8889/js-data/";
	var SCANNER_TOUT  = 1200;
	
	var API_LOCATION  = "http://t01.platform.altergeo.ru/getlocation?";
	var API_FEEDBACK  = "http://t01.platform.altergeo.ru/feedback?";
	var API_TOKEN     = "http://t01.platform.altergeo.ru/prepare?";
	var API_GEO_JSXML = "http://t01.platform.altergeo.ru/geo?doctype=js-xml";
	var API_TIMEOUT   = 5000;

	var document_head = document.getElementsByTagName("head")[0] || document.documentElement;
	var me = this;

	// old version support
	var bho = window._altergeo_bho || window.wi2geo; // old version support
	if( bho ) {
		if( /^2\.6/.test(bho.version) ) { use_bho = false; }
		else if( /^2\.7/.test(bho.version) ) { use_bho = false; }
		else if( /^2\.7\.1/.test(bho.version) ) { use_bho = false; }
		else if( /^2\.7\.2/.test(bho.version) ) { use_bho = false; }
	}
	else { use_bho = false; }
	
	/**
	 * on_success - callback function( token ) 
	 * on_error - callback function( err_code ) 
	 */
    this.getToken = function( on_success, on_error )
    {
    	if( Math.random() >= api_throttle  ) { on_success(""); }
    	
    	if( use_bho && bho ) 
    	{
    		api_get_token( {data:bho.data}, on_success, on_error ); 
    		return;
    	};
    	
    	if( !use_scanner || scanner_ver === "" ) 
    	{
    		// call api directly w/o scanner request
    		api_get_token( undefined, on_success, on_error );
    		return;
    	}    	
    	
    	// use data from scanner
    	get_scanner_data(
    		function(data) {
    			api_get_token( 
    				{ data: re1(/^.*<data>(.+)<\/data>.*$/, data) },
    				on_success, 
    				on_error 
    			); 
    		}, 
    		function() { api_get_token( undefined, on_success, on_error ); }
    	);
    };
    
    function api_get_token( data, on_success, on_error ) {
		call_server( 
   			make_api_url( data, "token" ),
   			function(res) {
   				var r = re1( /<token><id>(.+)<\/id><\/token>/, res );
   				if( r ) { on_success(r); }
   				else { on_error(me.ERR_API_FAILURE); }
   			},
   			function() { on_error(me.ERR_API_RESPONSE); }
   		);
    }
    
	
	/**
	 * on_success - callback function( 
	 * 		{ 'lat': latitude, 'lng': longitude, 'pos_type': n, 'prec': precision } )
	 * TODO: parameters
	 * 
	 * on_error - callback function( err_code ) 
	 */
    this.getLocation = function( on_success, on_error )
    {
    	if( use_bho && bho ) 
    	{
    		window._altergeo_bho.docType = "xml";	// default?
    		var res = bho.getLocation(api_key);
    		if( res ) {	
    			on_success( parse_server_response(res) ); 
    		}
    		else { 
    			on_error( me.ERR_API_RESPONSE ); 
    		}
    		return;
    	};
    	
    	if( !use_scanner || scanner_ver === "" ) 
    	{
    		// call api directly w/o scanner request
    		api_request( undefined, undefined, on_success, on_error );
    		return;
    	}    	
    	
    	// use data from scanner
    	get_scanner_data(
    		function(data) {
    			api_request( 
    				{ data: re1(/^.*<data>(.+)<\/data>.*$/, data) },
    				undefined,
    				on_success, 
    				on_error 
    			); 
    		}, 
    		function() { api_request( undefined, undefined, on_success, on_error ); }
    	);
    };

    /**
     * lat - latitude
     * lng - longitude
     * zoom - map zoom
     * params - { 'uuid': partner_uuid } 
     * 
     * on_success - callback function( result_data )
     * on_error - callback function( err_code ) 
     */
    this.setLocation = function( lat, lng, zoom, params, on_success, on_error )
    {
    	var new_ll = { 'newlat': lat, 'newlng': lng, 'zoom': zoom };

    	// NOTE: no BHO support
    	if( params.sd || scanner_ver === "" || !use_scanner ) 
    	{
    		api_request( params, new_ll, on_success, on_error );
    		return;
    	}

    	// use data from scanner
    	get_scanner_data(
    		function(data) { 
    			data = re1(/^.*<data>(.+)<\/data>.*$/, data); 
    			if( params ) { params.data = data; }
    			else { params = { data: data }; }
    			api_request( params, new_ll, on_success, on_error ); 
    		}, 
    		function() { api_request( params, new_ll, on_success, on_error ); }
    	);
    }

    /**
     * lat/lng - latitude/longitude
     * prov - data provided (default Altergeo)
     * on_complete - callback function 'on_callback( {...} )' 
     */
    this.getAddress = function( lat, lng, prov, on_complete )
    {
    	call_server( 
    		API_GEO_JSXML+'&apikey='+api_key+'&lat='+lat+'&lng='+lng,
    		function(res) {
            	on_complete({
            		'country': re1(/^.*<country>.*<name>(.+)<\/name>.*<\/country>.*$/, res),
            		'city': re1(/^.*<city>.*<name>(.+)<\/name>.*<\/city>.*$/, res),
            		'street': re1(/^.*<street>.*<name>(.+)<\/name>.*<\/street>.*$/, res),
            		'building': re1(/^.*<building>.*<name>(.+)<\/name>.*<\/building>.*$/, res) 
            	});
    		},
    		function() { on_complete( undefined ); }
    	);
    }    
    
    
    /**
     * 	callback: on_complete({ rc: result_code, scanner_ver: "2.x..." })
     */
    this.check_scanner = function( on_complete ) 
    {
    	get_scanner_data( 
    		function(res) {
   	    		var ver = re1(/^.* Version="(.+)".*$/, res), d = undefined;
   	    		if( ver === undefined ) {
   	    			scanner_ver = "";
   	    			d = { rc: me.ERR_SCANNER, scanner_ver: "" }; 
   	    		}
   	    		else {
   	    			scanner_ver = ver; 
   	    			d = { rc: me.OK, scanner_ver: ver };
   	    					//, data: re1(/^.*<data>(.+)<\/data>.*$/, res) 
   	    		};
   	    		on_complete(d);
   	        },    			
   	        function(){
        		on_complete({ rc: me.ERR_SCANNER });
   	        }
    	);
    }

    /**
     * returns { update: True/False, scanner_ver: "newest.version.num", download_url: "http://..." }
     */
    this.check_update = function( scanner_ver )
    {
    	// TODO: stub
    	var dl_win = "http://platform.altergeo.ru/dl/AlterGeo.MagicScanner-2.7.2.exe";
    	var dl_mac = "http://platform.altergeo.ru/dl/AlterGeoMagicScanner-2.6.2.exe";
    	
    	// if (navigator.appVersion.indexOf("Win")!=-1) os_type = 4;
    	// if (navigator.appVersion.indexOf("Mac")!=-1) os_type = 5;
    	// if (navigator.appVersion.indexOf("X11")!=-1) os_type = 6;
    	// if (navigator.appVersion.indexOf("Linux")!=-1) os_type = 7;
    	// if not Opera and (Windows or MacOS)
    		
    	return { update: False, scanner_ver: '2.8', download_url: dl_win };
    }
    
// internals //
    
    var nc_rnd = function() { return '_nc='+parseInt(Math.random()*100000); }
    
    var get_scanner_data = function( on_data, on_timeout ) {
    	var script = script_element( SCANNER_DATA+'?'+nc_rnd() );
        var tout = window.setTimeout( 
        	function() { 
        		script_remove(script);
        		scanner_ver = "";	// scanner timeout
        		on_timeout();
        	}, SCANNER_TOUT
        );
        window.wi2geoScanResponse = function(res) {
        	window.clearTimeout(tout);
        	script_remove(script);
        	on_data( res );
        };
        script_insert( script );
    }
    
    var call_server = function( url, on_success, on_timeout ) {
    	var script = script_element( url+'&'+nc_rnd() );
        var tout = window.setTimeout( 
        	function() { 
        		script_remove(script);
        		on_timeout();
        	}, SCANNER_TOUT
        );
        window.wi2geoServerResponse = function(res) {
        	window.clearTimeout(tout);
        	script_remove(script);
        	on_success( res );
        };
        script_insert( script );
    }
    
    var api_request = function( data, new_ll, on_success, on_error ) {
		call_server( 
   			make_api_url( data, new_ll ),
   			function(res) {
   				var r = parse_server_response(res);
   				if( r ) { on_success(r); }
   				else { on_error(me.ERR_API_FAILURE); }
   			},
   			function() { on_error(me.ERR_API_RESPONSE); }
   		);
    }
    
    var script_element = function(url) {
    	var s = document.createElement("script");
        s.type = 'text/javascript';
        s.charset = 'utf-8';
        s.src = url;
    	return s;
    }

    var script_insert = function(script) {
    	document_head.insertBefore( script, document_head.firstChild );
    }

    var script_remove = function(script) {    
    	try { document_head.removeChild(script); } catch(e){};
    }
    
    var re1 = function( re, s ) 
    {
    	if( s == undefined ) { return undefined; }
    	var res = re.exec(s);
    	return (res)? res[1]: undefined;
    }
    
    var parse_server_response = function(res) {
        // json: eval( 'res={'+res+'}' )
        
        if( re1(/^.*<WigoneException>(.+)<\/WigoneException>.*$/, res) ) {
        	return undefined;
        }
        
        try {
        	var lat = parseFloat( re1(/^.*<latitude>(.+)<\/latitude>.*$/, res) );
        	var lng = parseFloat( re1(/^.*<longitude>(.+)<\/longitude>.*$/, res) );
        	var prec = parseInt( re1(/^.*<precision>(.+)<\/precision>.*$/, res) );
        	var pos_type = parseInt( re1(/^.*<pos_type>(.+)<\/pos_type>.*$/, res) );
        	
        	var building = re1(/^.*<building>.*<name>(.+)<\/name>.*<\/building>.*$/, res);
        	var street = re1(/^.*<street>.*<name>(.+)<\/name>.*<\/street>.*$/, res);
        	var metro = re1(/^.*<metro>.*<name>(.+)<\/name>.*<\/metro>.*$/, res);
        	var city = re1(/^.*<city>.*<name>(.+)<\/name>.*<\/city>.*$/, res);
        	var country = re1(/^.*<country>.*<name>(.+)<\/name>.*<\/country>.*$/, res);

        }
        catch( e ) { return undefined; }
        
       	return { 
       		'lat': lat, 'lng': lng, 'pos_type': pos_type, 'prec': prec,
       		'building': building, 'street': street, 'metro': metro,
       		'city': city, 'country': country
       	};
    };

    function make_api_url( params, new_ll ) {
    	var url, pr = { 
    		'api_key': api_key, 
    		'version': api_ver,
    		'doctype': 'js-xml' // 'json'
    		// 'nogeo': '1',
    	};
    	if( params ) {
    		pr.data = params.data;
    		// pr.uuid = params.uuid;
    	}
    	if( new_ll === "token" ) {
    		url = API_TOKEN;
    	}
    	else if( new_ll ) {
    		for( var i in new_ll ) { pr[i] = new_ll[i]; };
    		url = API_FEEDBACK;
    	}
    	else {
    		url = API_LOCATION;
    	}
    	var amp = '';
    	for( var i in pr ) {
    		if( pr[i] !== undefined ) {
    			url += amp+i+'='+pr[i];
    			amp = '&';
    		}
    	}
    	return url;
    }

}

// begun 

var altergeo = new AlterGeo( "AQIAAOLqS5Ny2OTs7vjfJDcD97zn4cmN", { 
	use_bho: true, 
	use_scanner: true, 
	api_throttle: 1.0
});

if( altergeo_token_callback ) {
	altergeo.getToken( altergeo_token_callback, function( err_code ) { } );
};

//.

