public abstract class AbstractActivity extends MapActivity implements WarningListener{

    protected static final String KEY_EXIT = "key_exit";

	protected static final int DIALOG_GPS_WARNING = 0;
	protected static final int DIALOG_NO_SIM_WARNING = DIALOG_GPS_WARNING + 1;
	protected static final int DIALOG_NO_INTERNET_CONNECTION = DIALOG_NO_SIM_WARNING + 1;
	protected static final int DIALOG_WIFI_WARNING = DIALOG_NO_INTERNET_CONNECTION + 1;
	protected static final int DIALOG_ROAMING_WARNING = DIALOG_WIFI_WARNING +1;
	protected static final int DIALOG_ROAMING_IS_TURNED_OFF_WARNING = DIALOG_ROAMING_WARNING + 1;
	protected static final int DIALOG_DATA_CONNECTING_WARNING = DIALOG_ROAMING_IS_TURNED_OFF_WARNING + 1;
	protected static final int DIALOG_GENERAL_NETWORK_ERROR = DIALOG_DATA_CONNECTING_WARNING + 1;
    protected static final int DIALOG_NEW_INTERNAL_VERSION_AVAILABLE = DIALOG_GENERAL_NETWORK_ERROR + 1;
    protected static final int DIALOG_NEW_INTERNAL_VERSION_AVAILABLE_FORCED = DIALOG_NEW_INTERNAL_VERSION_AVAILABLE + 1;
    protected static final int DIALOG_NEW_EXTERNAL_VERSION_AVAILABLE = DIALOG_NEW_INTERNAL_VERSION_AVAILABLE_FORCED + 1;
    protected static final int DIALOG_NEW_EXTERNAL_VERSION_AVAILABLE_FORCED = DIALOG_NEW_EXTERNAL_VERSION_AVAILABLE + 1;
    protected static final int DIALOG_IN_FLIGHTMODE = DIALOG_NEW_EXTERNAL_VERSION_AVAILABLE_FORCED + 1;
    protected static final int DIALOG_NEXT_AVAILABLE_ID = DIALOG_IN_FLIGHTMODE + 1;

	private static final String LOGTAG = "AbstractActivity";
	private static int createdActivities = 0;
	private static int activeActivities = 0;
	
	private MapsApplication application;
	private Runnable roamingPositiveAction;
	private String generalErrorMessage;
	private int autoDismissTime;
	private boolean gpsWarningDisplayed;
	private boolean isFlightModeOk;
	private boolean isNoLocationOk;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
//		this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
		application = (MapsApplication) this.getApplication();

        Intent intent = this.getIntent();
        final boolean exit = intent.getBooleanExtra(KEY_EXIT, false);
        if(exit) {
            this.finish();
            System.exit(0);  
            return;
        }
	}

	@Override
	protected void onPause() {
		super.onPause();
		activeActivities--;
		if (activeActivities <= 0) {
			// None of the WayfinderActivities are interacting with the user
			// right now.
			// Beware, this could mean that we have a dialog on top of the
			// WayfinderActivity.
		}
	}

	@Override
	protected void onStop() {
		super.onStop();

		createdActivities--;
		if (createdActivities <= 0) {
			createdActivities = 0;
			// No activities are visible on the screen. Be aware that this
			// method may never be called from the system
			Log.i("AbstractActivity", "onStop() Last activity stopped[" + this
					+ "]");
			this.application.pausePositioning(true);
			this.application.cancelNoLocationTimer();
		}
	}

	@Override
	protected void onStart() {
		super.onStart();
		createdActivities++;
		if (createdActivities == 1) {
			// This is the first activity started.
			Log.i(LOGTAG, "onStart() starting positioning");
			this.application.pausePositioning(false);
			this.application.startNoLocationTimer();
		}
	}

	@Override
	protected void onResume() {
		super.onResume();
		activeActivities++;
		application.setWarningListener(this);
	}
	
	public boolean isFlightModeOk() {
		return this.isFlightModeOk;
	}
	
	public boolean isNoLocationOk() {
		return this.isNoLocationOk;
	}

	@Override
	protected Dialog onCreateDialog(int id) {
		switch (id) {
			case DIALOG_ROAMING_WARNING: {
				AlertDialog dialog = new AlertDialog(this);
				dialog.setTitle(R.string.qtn_andr_368_roaming_txt);
				dialog.setMessage(R.string.qtn_andr_368_roaming_warning_messq_txt);
				dialog.setPositiveButton(R.string.qtn_andr_368_ok_tk,
						new OnClickListener() {
							public void onClick(DialogInterface dialog, int which) {
								dialog.dismiss();
								if(roamingPositiveAction != null){
									runOnUiThread(roamingPositiveAction);
									roamingPositiveAction = null;
								}
							}
						});
				dialog.setNegativeButton(R.string.qtn_andr_368_exit_txt,
						new OnClickListener() {
							public void onClick(DialogInterface dialog, int which) {
								application.setRoamingWarningDisplayed(false);
								roamingPositiveAction = null;
								exitApplication();
							}
						});
				
				dialog.setOnCancelListener(new OnCancelListener(){
					public void onCancel(DialogInterface arg0) {
						AbstractActivity.this.finish();
					}
					
				});
				dialog.setOnDismissListener(new OnDismissListener(){
					public void onDismiss(DialogInterface arg0) {
						roamingPositiveAction = null;
						application.setRoamingWarningDisplayed(false);
					}
					
				});
				application.setRoamingWarningDisplayed(true);
				return dialog;
			}
			case DIALOG_ROAMING_IS_TURNED_OFF_WARNING: {
				AlertDialog dialog = new AlertDialog(this);
				dialog.setTitle(R.string.qtn_andr_368_you_r_roaming_txt);
				dialog.setMessage(R.string.qtn_andr_368_turn_data_roaming_onq_txt);			
	            dialog.setPositiveButton(R.string.qtn_andr_368_ok_tk,
	                    new OnClickListener() {
	                        public void onClick(DialogInterface dialog, int which) {
	                            AbstractActivity.this
	                                    .dismissDialog(DIALOG_ROAMING_IS_TURNED_OFF_WARNING);
	                            try {
	                                Intent i = new Intent(Settings.ACTION_SETTINGS);
	                                i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
	                                dialog.dismiss();
	                                startActivity(i);
	                            } catch (Throwable t) {
	                                Log.e("AbstractActivity", "onDismiss() " + t);
	                            }
	                        }
	                    });   
	            
	            dialog.setNegativeButton(R.string.qtn_andr_368_exit_txt,
	            		 new OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                    	dialog.dismiss();
                        exitApplication();
                    }
                });
	            
	            dialog.setOnDismissListener(new OnDismissListener() {
	                public void onDismiss(DialogInterface dialog) {
	                	application.setRoamingWarningDisplayed(false);
	                    if (shouldBeCloseOnError()) {
	                        AbstractActivity.this.finish();
	                    }
	                }
	            });
				return dialog;
			}
			case DIALOG_GPS_WARNING: {
				AlertDialog dialog = new AlertDialog(this);
				dialog.setTitle(R.string.qtn_andr_368_cant_find_yr_loc_txt);
				dialog.setMessage(R.string.qtn_andr_368_enable_loc_source_ch_settq_txt);
				dialog.setPositiveButton(R.string.qtn_andr_368_ok_tk,
						new OnClickListener() {
							public void onClick(DialogInterface dialog, int which) {
								try {
									Intent i = new Intent(
											Settings.ACTION_LOCATION_SOURCE_SETTINGS);
									i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
									dialog.dismiss();
									startActivity(i);
								} catch (Throwable t) {
									Log.e("AbstractActivity", "onDismiss() " + t);
								}
							}
						});
				dialog.setNegativeButton(R.string.qtn_andr_368_cancel_tk,
						new OnClickListener() {
							public void onClick(DialogInterface dialog, int which) {
								isNoLocationOk = true;
								dialog.dismiss();
								checkDialogs();
							}
						});
				dialog.setOnDismissListener(new OnDismissListener() {
					
					public void onDismiss(DialogInterface dialog) {
						gpsWarningDisplayed = false;					
					}
				});
				gpsWarningDisplayed = true;
				return dialog;
			}
	
			case DIALOG_NO_SIM_WARNING: {
				AlertDialog dialog = new AlertDialog(this);
				dialog.setTitle(R.string.qtn_andr_368_note_title);
				dialog.setMessage(R.string.qtn_andr_368_insert_sim_txt);
				dialog.setNeutralButton(R.string.qtn_andr_368_ok_tk,
						new OnClickListener() {
							public void onClick(DialogInterface dialog, int which) {
								dialog.dismiss();
							}
						});
				dialog.setOnDismissListener(new OnDismissListener() {
					public void onDismiss(DialogInterface dialog) {
						AbstractActivity.this.finish();
					}
				});
				return dialog;
			}
	
			case DIALOG_NO_INTERNET_CONNECTION: {
				AlertDialog dialog = new AlertDialog(this);
				dialog.setTitle(R.string.qtn_andr_368_note_title);
				dialog.setMessage(R.string.qtn_andr_368_conn_sett_txt);
				dialog.setPositiveButton(R.string.qtn_andr_368_ok_tk,
					new OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						AbstractActivity.this.dismissDialog(DIALOG_NO_INTERNET_CONNECTION);
						// Works for bringing up the settings
						try {
							Intent i = new Intent(Settings.ACTION_WIRELESS_SETTINGS);
							i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
							dialog.dismiss();
							startActivity(i);
						} catch (Throwable t) {
							Log.e("AbstractActivity", "onDismiss() " + t);
						}
					}
				});
				dialog.setNegativeButton(R.string.qtn_andr_368_cancel_tk,
						new OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				});
				dialog.setOnDismissListener(new OnDismissListener() {
					public void onDismiss(DialogInterface dialog) {
						application.setNoInternetConnectionDialogShown(false);
					}
				});
				return dialog;
			}
	
			case DIALOG_WIFI_WARNING: {
				AlertDialog dialog = new AlertDialog(this);
				dialog.setTitle(R.string.qtn_andr_368_note_title);
				dialog.setMessage(R.string.qtn_andr_368_turn_off_wifi_txt);
				dialog.setNeutralButton(R.string.qtn_andr_368_settings_tk,
						new OnClickListener() {
							public void onClick(DialogInterface dialog, int which) {
								Intent i = new Intent(
										Settings.ACTION_WIRELESS_SETTINGS);
								i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
								startActivity(i);
								dialog.dismiss();
							}
						});
				dialog.setPositiveButton(R.string.qtn_andr_368_close_tk,
						new OnClickListener() {
							public void onClick(DialogInterface dialog, int which) {
								finish();
							}
						});
				return dialog;
			}
			
			case DIALOG_GENERAL_NETWORK_ERROR: {
		        AlertDialog dialog = new AlertDialog(this);
	            dialog.setTitle(R.string.qtn_andr_368_note_title);
	            dialog.setMessage(generalErrorMessage);
	            dialog.setNeutralButton(R.string.qtn_andr_368_ok_tk,
	                    new OnClickListener() {
	                public void onClick(DialogInterface dialog, int which) {
	                    AbstractActivity.this.dismissDialog(DIALOG_GENERAL_NETWORK_ERROR);
	                }
	            });
	            dialog.setOnDismissListener(new OnDismissListener(){
	                public void onDismiss(DialogInterface dialog) {
	                    if(shouldBeCloseOnError()){
	                        AbstractActivity.this.finish();
	                    }
	                }
	            });
	            return dialog;
			}
			
			case DIALOG_IN_FLIGHTMODE: {
				AlertDialog dialog = new AlertDialog(this);
				dialog.setTitle(R.string.qtn_andr_368_flight_mode_txt);
				dialog.setMessage(R.string.qtn_andr_368_flight_mo_ch_settq_txt);
				dialog.setPositiveButton(R.string.qtn_andr_368_ok_tk,
						new OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						AbstractActivity.this
								.dismissDialog(DIALOG_IN_FLIGHTMODE);
						// Works for bringing up the settings
						try {
							Intent i = new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS);
							i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
							dialog.dismiss();
							startActivity(i);
						} catch (Throwable t) {
							Log.e("AbstractActivity", "onDismiss() " + t);
						}
					}
				});
				dialog.setNegativeButton(R.string.qtn_andr_368_cancel_tk,
					new OnClickListener() {
						public void onClick(DialogInterface dialog, int which) {
							isFlightModeOk = true;
							dialog.dismiss();
							checkDialogs();
					}
				});
				return dialog;
			
			}
			default: {
				return super.onCreateDialog(id);
			}
		}
	}

	/**
	 * Overridden in AbstractStartupActivity for checking status of Device before letting the user into the application 
	 */
	protected void checkDialogs() {
	}

	@Override
	protected void onPrepareDialog(int id, Dialog dialog) {
		switch (id) {
		 case DIALOG_ROAMING_WARNING: {
             AlertDialog alert = (AlertDialog) dialog;
             alert.setAutoDismissTime(this.autoDismissTime);
             break;
         }
		case DIALOG_NO_INTERNET_CONNECTION: {
			AlertDialog alert = (AlertDialog) dialog;
			alert.setAutoDismissTime(this.autoDismissTime);
			break;
		}
		default: {
			super.onPrepareDialog(id, dialog);
		}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.vodafone.android.navigator.listeners.WarningListener#displayNoSIMWarning
	 * ()
	 */
//	public void displayNoSIMWarning() {
//		showDialog(DIALOG_NO_SIM_WARNING);
//	}

	public boolean shouldBeCloseOnError() {
		return false;
	}
	
    public static boolean isApplicationActive() {
        Log.i("AbstractActivity", "created activities: " + createdActivities);
        return createdActivities > 0;
    }

    public static boolean isApplicationVisible() {
        Log.i("AbstractActivity", "active activities: " + activeActivities);
        return activeActivities > 0;
    }
    
    protected void setAutoDismissTime(int autoDismissTime) {
    	this.autoDismissTime = autoDismissTime;
	}
    
	public void displayGeneralErrorMessage(int messageId) {
		//TODO: removed temporarily
//		displayGeneralErrorDialog(messageId, null);
	}

	public void displayGpsWarning() {
		showDialog(DIALOG_GPS_WARNING);
	}

	public void displayNoInternetConnectionWarning(int autoDismissTime) {
		setAutoDismissTime(autoDismissTime);
		if (isApplicationActive()) {
			if(!application.isRoamingWarningDisplayed() && !application.isNoInternetConnectionDialogShown()){
				application.setNoInternetConnectionDialogShown(true);
				showDialog(DIALOG_NO_INTERNET_CONNECTION);
			}
		} else {
			Toast.makeText(this, R.string.qtn_andr_368_conn_sett_txt, Toast.LENGTH_LONG);
		}
	}

	public void displayDataRoamingIsTurnedOffWarning() {
		if (isApplicationActive()) {
			application.setRoamingWarningDisplayed(true);
			showDialog(DIALOG_ROAMING_IS_TURNED_OFF_WARNING);
		} else {
			Toast.makeText(this, R.string.qtn_andr_368_turn_data_roaming_onq_txt,
					Toast.LENGTH_LONG).show();
		}
	}


	public void displayNoLocationWarning() {
		if (isApplicationActive() && !gpsWarningDisplayed) {
			Toast.makeText(this, R.string.qtn_andr_368_curr_loc_not_avail_txt,
						Toast.LENGTH_LONG).show();
		}
	}
	
	public void displayRoamingWarning(int autoDismissTime) {
		if(!application.isRoamingOk()){
			if (isApplicationActive()) {
				setAutoDismissTime(autoDismissTime);
				application.setRoamingWarningDisplayed(true);
				showDialog(DIALOG_ROAMING_WARNING);
			} else {
				Toast.makeText(this, R.string.qtn_andr_368_roaming_warning_messq_txt,
						Toast.LENGTH_LONG).show();
			}
		}
	}
	/**
	 * Displays a simple dialog wich will contain the message and the error code provided as parameters.
	 * Defaul action on OK is dismissing the dialog.
	 * @param message
	 * @param errorCode
	 */
	public void displayGeneralErrorDialog(int resourceID, String errorCode) {
        String errorText = application.getApplicationContext().getResources().getString(resourceID);
        displayGeneralErrorDialog(errorText, errorCode);
        
    }
	
	/**
     * Displays a simple dialog wich will contain the message and the error code provided as parameters.
     * Defaul action on OK is dismissing the dialog.
     * @param message
     * @param errorCode
     */
    public void displayGeneralErrorDialog(String message, String errorCode) {
        String errorText = message;
        if (errorCode != null && errorCode.length() > 0) {
            errorText+= "(" + errorCode +")"; 
        }
        generalErrorMessage = errorText;
        if(isApplicationActive()) {
            showDialog(DIALOG_GENERAL_NETWORK_ERROR);
        } else {
            Toast.makeText(this, generalErrorMessage, Toast.LENGTH_LONG);
        }
    }

    public void displayNetworkErrorMessage() {
        if(isApplicationActive()) {
        	displayNoInternetConnectionWarning(0);
        }
    }

        
    
	public void displaySafetyWarning() {
		
	}

	public void displaySynchronizationCompletedMessage() {
		
	}

	public void displayWifiWarning() {
//		showDialog(DIALOG_WIFI_WARNING);
	}

	public void handleSoundMuteStateChanged() {
		
	}   
	
	protected MapsApplication getApp() {
		return application;
	}
	
	public boolean exitApplication() {
	    Intent intent = new Intent(this, LocateActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
	    intent.putExtra(LocateActivity.KEY_EXIT, true);
        this.startActivity(intent);
        finish();
		return true;
	}

	/**
	 * @param roamingPositiveAction the roamingPositiveAction to set
	 */
	protected void setRoamingPositiveAction(Runnable roamingPositiveAction) {
		this.roamingPositiveAction = roamingPositiveAction;
	}

	/**
	 * @return the roamingWarningDisplayed
	 */
	public boolean isRoamingWarningDisplayed() {
		return application.isRoamingWarningDisplayed();
	}
	
	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}
	
} public class ServicesActivity extends ServiceWindowActivity {

    public static final String KEY_URI = "key_uri";

    private String uri;
    private boolean uriOpened;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        this.requestWindowFeature(Window.FEATURE_NO_TITLE);

        Intent intent = this.getIntent();
        String uri = intent.getStringExtra(KEY_URI);

        if(!uri.equals(this.uri)) {
            Log.i("ServicesActivity", "Uri: " + uri);
            this.uri = uri;
            this.uriOpened = false;
        }
    }
    
    @Override
	protected void onResume() {
		super.onResume();
	
		if(!this.uriOpened) {
            this.getPageHandler().openServices(this.uri);
            this.uriOpened = true;
		}
	}
} public class AndroidCallbackHandler implements CallbackHandler{
	Handler handler;
	
	public AndroidCallbackHandler(Handler handler){
	    this.handler = handler;
	}

	public void callInvokeCallbackRunnable(Runnable r) {
		handler.post(r);
	}
} public class CategoryLevelData {
	
	public static final int TYPE_CATEGORY_LEVEL = 0;
	public static final int TYPE_SEARCH_RESULTS = 1;
	public static final int TYPE_SEARCH_DETAILS = 2;
	public static final int TYPE_COMBINED_DETAILS = 3;
	
	private Vector<Object> objectVector;
	private int type;
	
	public CategoryLevelData(int type, Vector<Object> objects) {
		objectVector = objects;
		this.type = type;
	}

	public Vector<Object> getObjectVector() {
		return objectVector;
	}

	public int getType() {
		return this.type;
	}
} public interface DataConnectionStateListener {
    
    void onDataConnectionStateChanged(int state);

} public interface GeoCodeChangeListener {
	void onGeoCodeChange(AddressInfo addressInfo);
} public interface WarningListener {
    
    void displayDataRoamingIsTurnedOffWarning();
    void displayRoamingWarning(int autoDismissTime);
    void displaySafetyWarning();
    void displayGpsWarning();
//    void displayWifiWarning();
    void displayNoLocationWarning();
    void displayNoInternetConnectionWarning(int autoDismissTime);
//    void displayNoSIMWarning();
    void displayGeneralErrorMessage(int messageId);
    void handleSoundMuteStateChanged();
    void displaySynchronizationCompletedMessage();
    void displayGeneralErrorDialog(String message, String errorCode);
    void displayGeneralErrorDialog(int resourceID, String errorCode);
	void displayNetworkErrorMessage();

} public class ApplicationSettings {

    private static final ApplicationSettings INSTANCE = new ApplicationSettings();
	private static final String SHARED_PREFS_NAME               = "VodafoneMapsSettings";
    private static final String KEY_MEASUREMENTS                = "key_measurements";
    private static final String KEY_SAVED_ADDRESS                = "key_saved_address";
    private static final String KEY_SAVED_ADDRESS_LATITUDE                = "key_saved_address_latitude";
    private static final String KEY_SAVED_ADDRESS_LONGITUDE                = "key_saved_address_longitude";

    private static final String KEY_SERVER_URL                  = "key_server_url";
    private static final String KEY_SERVER_PORT                 = "key_server_port";
    private static final String KEY_CLIENT_TYPE                 = "key_client_type";
        
    
    private static final String URL_VERSION_BASE = "[ENTER ADDRESS]"; 
    private static final String URL_VERSION_APK = ".apk";
    private static final String URL_VERSION_CHECK = ".version";
    
	private String serverUrl;
	private int serverPort;
	private String clientId;

	private MapsApplication mapsApplication;
    private OnSettingsChangeListener listener;

	private ApplicationSettings() {
	}

	public static final ApplicationSettings get() {
		return INSTANCE;
	}

	public void initBeforeCore(MapsApplication app) {
		this.mapsApplication = app;
		SharedPreferences prefs = openPrefs();
        this.setServerAddress(prefs.getString(KEY_SERVER_URL, MapsApplication.getServerUrl()), prefs.getInt(KEY_SERVER_PORT, MapsApplication.getServerPort()));
        this.setClientId(prefs.getString(KEY_CLIENT_TYPE, MapsApplication.getClientId()));
	}

	public void initAfterCore(MapsApplication app) {
		//Loading settings from phone and setting measurement unit 
		GeneralSettings coreSettings = this.mapsApplication.getCore().getGeneralSettings();
        SharedPreferences prefs = openPrefs();
        this.setMeasurementSystem(prefs.getInt(KEY_MEASUREMENTS, coreSettings.getMeasurementSystem()));
        this.mapsApplication.setSavedAddress(prefs.getString(KEY_SAVED_ADDRESS, null));
        int lat = prefs.getInt(KEY_SAVED_ADDRESS_LATITUDE, 0);
        int lon = prefs.getInt(KEY_SAVED_ADDRESS_LONGITUDE, 0);
        if (lat != 0 && lon != 0) {
            this.mapsApplication.setSavedAddressPosition(new Position(lat, lon));
        }
	}

	public void setServerAddress(String url, int port) {
	    if(this.serverUrl == null || !this.serverUrl.equals(url) || this.serverPort != port) {
    		this.serverUrl = url;
    		this.serverPort = port;
            if(this.listener != null) {
                this.listener.onSettingsChangeListener(this);
            }
	    }
	}

	public String getServerUrl() {
		// if this is not a debug-version then disregard user�s settings and use
		// what is defined in MapsApplication
		if (!MapsApplication.isDebug()) {
			return MapsApplication.getServerUrl();
		}
		return this.serverUrl;
	}

	public int getServerPort() {
		// if this is not a debug-version then disregard user�s settings and use
		// what is defined in NavigatorApplication
		if (!MapsApplication.isDebug()) {
			return MapsApplication.getServerPort();
		}
		return this.serverPort;
	}

	public void setClientId(String clientId) {
	    if(this.clientId == null || !this.clientId.equals(clientId)) {
    	    this.clientId = clientId;
            if(this.listener != null) {
                this.listener.onSettingsChangeListener(this);
            }
	    }
	}

	public String getClientId() {
		if (!MapsApplication.isDebug()) {
			return MapsApplication.getClientId();
		}
		return this.clientId;
	}

    public int getMeasurementSystem() {
        return this.mapsApplication.getCore().getGeneralSettings().getMeasurementSystem();
    }
    
    public void setMeasurementSystem(int measurementsSettings) {
        GeneralSettings coreSettings = this.mapsApplication.getCore().getGeneralSettings();
        
        if(coreSettings.getMeasurementSystem() != measurementsSettings) {
            coreSettings.setMeasurementSystem(measurementsSettings);
            coreSettings.commit();
            this.mapsApplication.updateUnitsFormatter();
            if(this.listener != null) {
                this.listener.onSettingsChangeListener(this);
            }
        }
    }
    
    public void setOnSettingsChangeListener(OnSettingsChangeListener listener) {
        this.listener = listener;
    }
    
    public void removeOnSettingsChangeListener(OnSettingsChangeListener listener) {
        if(this.listener == listener) {
            this.listener = null;
        }
    }
    
    public void commit() {
        SharedPreferences prefs = openPrefs();
        Editor editor = prefs.edit();

        if(this.mapsApplication.isInitialized()) {
            editor.putInt(KEY_MEASUREMENTS, this.getMeasurementSystem());
            if(this.mapsApplication.getSavedAddress() != null){
            	editor.putString(KEY_SAVED_ADDRESS, this.mapsApplication.getSavedAddress());
            }
            if(this.mapsApplication.getSavedAddressPosition() != null){
            	editor.putInt(KEY_SAVED_ADDRESS_LATITUDE, this.mapsApplication.getSavedAddressPosition().getMc2Latitude());
            	editor.putInt(KEY_SAVED_ADDRESS_LONGITUDE, this.mapsApplication.getSavedAddressPosition().getMc2Longitude());
            }
        }
        editor.commit();
    }

    private SharedPreferences openPrefs() {
        SharedPreferences prefs = this.mapsApplication.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE);
        return prefs;
    }

    public String getUrlVersionApk() {
		String appname = mapsApplication.getResources().getString(R.string.qtn_andr_368_app_name_txt);
		appname = appname.replace(' ', '_');
		return URL_VERSION_BASE + appname + URL_VERSION_APK;
	}

	public String getUrlVersionCheck() {
		String appname = mapsApplication.getResources().getString(R.string.qtn_andr_368_app_name_txt);
		appname = appname.replace(' ', '_');
		return URL_VERSION_BASE + appname + URL_VERSION_CHECK;
	}

	public interface OnSettingsChangeListener {
        void onSettingsChangeListener(ApplicationSettings settings);
    }
} public class AndroidUnitsFormatter extends UnitsFormatter {

    public AndroidUnitsFormatter(int unitSystem, Context context) {
        super(new AndroidUnitsFormatterSettings(unitSystem, context));
    }
    
    private static class AndroidUnitsFormatterSettings extends UnitsFormatterSettings {
        
    	private Context context;
        /**
         * Create a new instance.
         * 
         * @param unitSystem - the unit system to use.
         * @see UnitsFormatterSettings#UnitsFormatterConfig(int)
         */
        public AndroidUnitsFormatterSettings(int unitSystem, Context context) {
            super(unitSystem);
            this.context = context;
        }
    
        protected UnitsFormatterSettings getFrozenInstance() {
            return this; // we have no mutable data 
        }
        
        /**
         * Returns the string for long distance. E.g. "miles".
         * 
         * @return the string for long distance.
         */
        public String getLongDistance() {
            if (getUnitSystem() == UNITS_MILES_FEET
                || getUnitSystem() == UNITS_MILES_YARDS) {
                // STR_MILES
            	return context.getString(R.string.qtn_andr_368_miles_txt);
            } else {
                // use metric as default for unknowns.
                // KILOMETERS
            	return context.getString(R.string.qtn_andr_368_km_txt);
            }
        }
        
        /**
         * Returns the abbreviation for long distance. E.g. "mi", "km".
         * 
         * @return the abbreviation for long distance.
         */
        public String getLongDistanceAbbr() {
            if (getUnitSystem() == UNITS_MILES_FEET
                || getUnitSystem() == UNITS_MILES_YARDS) {
                // STR_MILES_ABBREVIATION
            	return context.getString(R.string.qtn_andr_368_miles_abbrev_txt);
            } else {
                // use metric as default for unknowns.
                // KILOMETERS
            	return context.getString(R.string.qtn_andr_368_km_txt);
            }
        }
    
        /**
         * Returns the string for short distance. E.g. "yards", "feet".
         * 
         * @return the string for short distance.
         */
        public String getShortDistance() {
            switch (getUnitSystem()) {
            case UNITS_MILES_FEET:
                // STR_FEET
            	return context.getString(R.string.qtn_andr_368_feet_txt);
    
            case UNITS_MILES_YARDS:
                // STR_YARDS
            	return context.getString(R.string.qtn_andr_368_yards_txt);
                
            default: // UNITS_METRIC and default
                // STR_METERS_ABBREVIATION
            	return context.getString(R.string.qtn_andr_368_metre_txt);
            }
        }
    
        /**
         * Returns the abbreviation for short distance. E.g. "yds", "ft", "m".
         * 
         * @return the abbreviation for short distance.
         */
        public String getShortDistanceAbbr() {
            switch (getUnitSystem()) {
            case UNITS_MILES_FEET:
                // STR_FEET_ABBREVIATION
                return context.getString(R.string.qtn_andr_368_feet_abbrev_txt);
    
            case UNITS_MILES_YARDS:
                // yards_abbr
                return context.getString(R.string.qtn_andr_368_yards_abbrev_txt);
                
            default: // UNITS_METRIC and default
                // STR_METERS_ABBREVIATION
            	return context.getString(R.string.qtn_andr_368_metre_txt);
            }
        }
    
        /**
         * Returns the localized decimal marker. Currently, always initialized to
         * "." due to limited font support in old jWMMG-code.
         * (Subject to change without notice.)
         * 
         * @return the localized decimal marker.
         */
        public String getDecimalMarker() {
            return context.getString(R.string.qtn_andr_368_decimal_marker_txt);
        }
    
        public String getHoursAbbr() {
            // wf_ROUTEV_ETG_HOURS
        	return context.getString(R.string.qtn_andr_368_hours_txt);
        }
        
        public String getMinutesAbbr() {
            // mins_abbr
        	return context.getString(R.string.qtn_andr_368_minutes_txt);
        }
        
        public String getSecondsAbbr() {
            // STR_SECONDS_ABBREVIATION
            return context.getString(R.string.qtn_andr_368_seconds_txt);
        }
    
        public String getSpeedAbbr() {
            if (getUnitSystem() == UNITS_MILES_FEET
                || getUnitSystem() == UNITS_MILES_YARDS) {
                // wayfinder_mph_text
                return context.getString(R.string.qtn_andr_368_miles_per_hour_txt);
            } else {
                // use metric as default for unknowns.
                // wayfinder_kmh_text
            	return context.getString(R.string.qtn_andr_368_km_per_hour_txt);
            }
        }
    }
} public class ImageDownloader implements Runnable {

    public static final String IMAGE_NAME_DEFAULT = "vf_search_heading_addresses";
    public static final String IMAGE_NAME_EMPTY = "empty_image";

    private static final String TAG = "ImageDownloader";
    private static ImageDownloader INSTANCE;

    private Thread downloadThread;
    private HashMap<String, Bitmap> cache = new HashMap<String, Bitmap>();
    private ArrayList<String> queue = new ArrayList<String>();
    private HashMap<String, QueueItem> mapping = new HashMap<String, QueueItem>();
    private MapsApplication mapsApplication;
    private int failCount;
    private boolean exit;

    private ImageDownloader(HttpConfigurationInterface httpConfig) {
        m_httpConfig = httpConfig;
    }

    private final HttpConfigurationInterface m_httpConfig;
    private int type;
    private int INTERNAL_IMAGE = 0;
    private int EXTERNAL_IMAGE = 1;
    public static void create(HttpConfigurationInterface httpConfig) {
        INSTANCE = new ImageDownloader(httpConfig); 
    }

    public static final ImageDownloader get() {
        return INSTANCE;
    }

    /**
     * returns bitmap for imageName if already downloaded and cached. Otherwise
     * it will queue the downloading of the bitmap and then call
     * ImageDownloadListener.onImageDownloaded. If the bitmap was downloaded and
     * cached already, the bitmap will be returned without the listener being
     * called
     * 
     * @param imageName
     * @param mapObject
     * @param listener
     * @return bitmap if already downloaded and cached
     */
    public synchronized Bitmap queueDownload(Context context, String imageName, ImageDownloadListener listener) {
        type = INTERNAL_IMAGE;
        if(imageName != null) {
        	if(imageName == null || "".equals(imageName)){
        		return null;
        	}
            Bitmap bitmap = this.getImage(context, imageName);
            if(bitmap != null) {
                return bitmap;
            }
    
            this.startThread();
            
            QueueItem queueItem = this.mapping.get(imageName);
            if(queueItem == null) {
                queueItem = new QueueItem(imageName);
                this.mapping.put(imageName, queueItem);
            }
            queueItem.addListener(listener);
    
            if (!this.queue.contains(imageName)) {
                this.queue.add(imageName);
                this.notifyAll();
            }
        }
        return null;
    }
    
    private String getImageName(String url) {
        StringTokenizer tk = new StringTokenizer(url);
        String name = null;
        while (tk.hasMoreTokens()) {
            name = tk.nextToken("/");
        }
        return name;
    }
    
    public synchronized Bitmap queueExternalImageDownload(Context context, String url, ImageDownloadListener listener) {
        type = EXTERNAL_IMAGE;
        if(url != null) {
            if(url == null || "".equals(url)){
                return null;
            }
            
            Bitmap bitmap = this.getImage(context, getImageName(url));
            if(bitmap != null) {
                return bitmap;
            }
    
            this.startThread();
            
            QueueItem queueItem = this.mapping.get(getImageName(url));
            if(queueItem == null) {
                queueItem = new QueueItem(url);
                this.mapping.put(getImageName(url), queueItem);
            }
            queueItem.addListener(listener);
            if (!this.queue.contains(url)) {
                this.queue.add(url);
                this.notifyAll();
            }
        }
        return null;
    }

    /**
     * returns a cached image, or null if image is not cached
     * 
     * @param imageName
     * @return returns a cached image, or null if image is not cached
     */
    public Bitmap getImage(Context context, String imageName) {
        Bitmap bitmap = null;
        if(imageName != null && !"".equals(imageName)) {
            this.mapsApplication = (MapsApplication) context.getApplicationContext();
    
            bitmap = this.cache.get(imageName);
            if (bitmap == null || bitmap.isRecycled()) {
                this.cache.remove(imageName);
                bitmap = this.readBitmapFromFile(imageName);
            }
        } else {
        	bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.cat_all);
        }
        return bitmap;
    }
    
    

    public void run() {
        while (!this.exit) {
            String imageName = this.getNextImageName();
            if (type == INTERNAL_IMAGE) {
                this.downloadImage(imageName);
            } else {
                this.downloadExternalImage(imageName);
            }
        }
        
        this.downloadThread = null;
        if(this.exit) {
            Log.e(TAG, "download-thread has stopped");
        }
    }


    private void startThread() {
        if(this.downloadThread == null) {
            Log.i(TAG, "download-thread is being started");
            this.exit = false;
            this.downloadThread = new Thread(this, TAG);
            this.downloadThread.start();
        }
    }
    
    private void downloadExternalImage(String a_url) {
        HttpURLConnection connection = null;
        InputStream in = null;
        try {
            URL url = new URL(a_url);
            connection = (HttpURLConnection) url.openConnection();
            
            connection.addRequestProperty("User-Agent", "android");
            connection.addRequestProperty("Accept", "*/*");

            connection.setDoInput(true);
            connection.connect();
            in = connection.getInputStream();

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int read = in.read(buffer);
            while(read > 0) {
                baos.write(buffer, 0, read);
                read = in.read(buffer);
            }
            
            byte[] fileData = baos.toByteArray();
            this.writeBitmapToFile(getImageName(a_url), fileData);
            
            ByteArrayInputStream bais = new ByteArrayInputStream(fileData);
            Bitmap origBitmap = BitmapFactory.decodeStream(bais);

            this.cache.put(a_url, origBitmap);
            this.queue.remove(a_url);

            QueueItem queueItem = this.mapping.get(getImageName(a_url));            
            if(queueItem != null) {
                queueItem.notifyListeners(origBitmap);
            } 
            this.failCount = 0;
        } catch (Exception e) {
            Log.e(TAG, "Downloading failed [" + a_url + "]: " + e);
            e.printStackTrace();
            
            //if we fail downloading 10 times in a row we shot down the thread
            this.failCount ++;
            if(this.failCount > 10) {
                this.exit = true;
            }
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                }
            }
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    private void downloadImage(String imageName) {
        HttpURLConnection connection = null;
        InputStream in = null;
        try {
            String serverUrl = this.mapsApplication.getServerAddress();
            URL url = new URL(serverUrl + "TMap/q" + imageName + "_40x40.png");

            Log.i("ImageDownloader", "downloadImage() URL: " + url);

            Proxy proxy = m_httpConfig.getProxy();
            Log.d(TAG, "proxy: " + proxy.toString());
            connection = (HttpURLConnection) url.openConnection(proxy);
            
            connection.addRequestProperty("User-Agent", ApplicationSettings
                    .get().getClientId()
                    + "/" + this.mapsApplication.getVersion());
            connection.addRequestProperty("Accept", "*/*");

            connection.setDoInput(true);
            connection.connect();
            in = connection.getInputStream();

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int read = in.read(buffer);
            while(read > 0) {
                baos.write(buffer, 0, read);
                read = in.read(buffer);
            }
            
            byte[] fileData = baos.toByteArray();
            this.writeBitmapToFile(imageName, fileData);
            
            ByteArrayInputStream bais = new ByteArrayInputStream(fileData);
            Bitmap origBitmap = BitmapFactory.decodeStream(bais);

            this.cache.put(imageName, origBitmap);
            this.queue.remove(imageName);

            QueueItem queueItem = this.mapping.get(imageName);
            if(queueItem != null) {
                queueItem.notifyListeners(origBitmap);
            }
            
            this.failCount = 0;
        } catch (Exception e) {
            Log.e(TAG, "Downloading failed [" + imageName + "]: " + e);
            e.printStackTrace();
            
            //if we fail downloading 10 times in a row we shot down the thread
            this.failCount ++;
            if(this.failCount > 10) {
                this.exit = true;
            }
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                }
            }
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    private void writeBitmapToFile(String imageName, byte[] fileData) {
        Log.i("ImageDownloader", "writeBitmapToFile() saving bitmap: " + imageName);
        FileOutputStream out = null;
        try {
            out = this.mapsApplication.openFileOutput(imageName, Context.MODE_PRIVATE);
            out.write(fileData);
            out.flush();
            Log.i("ImageDownloader", "writeBitmapToFile() bitmap saved: " + imageName);
        }
        catch(IOException e) {
            Log.e("ImageDownloader", "writeBitmapToFile() error when saving: " + e);
            e.printStackTrace();
        }
        finally {
            if(out != null) {
                try {
                    out.close();
                } catch (IOException e) {}
                out = null;
            }
        }
    }

    private Bitmap readBitmapFromFile(String imageName) {
        Log.i("ImageDownloader", "readBitmapFromFile() reading bitmap: " + imageName);
        if(imageName != null) {
            InputStream in = null;
            try {
                in = this.mapsApplication.openFileInput(imageName);
                
                Bitmap bitmap = BitmapFactory.decodeStream(in);
                this.cache.put(imageName, bitmap);
    
                Log.i("ImageDownloader", "readBitmapFromFile() bitmap read: " + imageName);
                return bitmap;
            }
            catch(FileNotFoundException e) {
                Log.i("ImageDownloader", "readBitmapFromFile() " + e);
            }
            finally {
                if(in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {}
                    in = null;
                }
            }
        }
        return null;
    }

    private synchronized String getNextImageName() {
        while (this.queue.isEmpty()) {
            try {
                this.wait();
            } catch (InterruptedException e) {
            }
        }

        return this.queue.get(0);
    }

    public interface ImageDownloadListener {
        void onImageDownloaded(Bitmap origBitmap, String imageName);
    }

    private static class QueueItem {
        private String imageName;

        private Vector<ImageDownloadListener> listeners = new Vector<ImageDownloadListener>();

        public QueueItem(String imageName) {
            this.imageName = imageName;
        }
        
        private void notifyListeners(Bitmap origBitmap) {
            for (ImageDownloadListener listener : this.listeners) {
                listener.onImageDownloaded(origBitmap, this.imageName);
            }
        }

        public void addListener(ImageDownloadListener listener) {
            if (!this.listeners.contains(listener)) {
                this.listeners.add(listener);
            }
        }
    }
} public class PropertiesManager {

    private static final PropertiesManager INSTANCE = new PropertiesManager();
    private Properties prop;
    
    private PropertiesManager() {
    }
    
    public static final PropertiesManager get() {
        return INSTANCE;
    }
    
    public void init(Context context) {
        AssetManager assets = context.getResources().getAssets();

        this.prop = new Properties();
        InputStream in = null;
        try {
            in = assets.open("properties.prop");
            this.prop.load(in);
        } catch (IOException e) {
            Log.e("MapsApplication", "Static() " + e);
        } finally {
            if(in != null) {
                try {
                    in.close();
                } catch (IOException e) {}
            }
        }

        Properties personalProp = new Properties();
        in = null;
        try {
            in = assets.open("personal_properties.prop");
            personalProp.load(in);

            //replace the values that exists in personal_properties.prop
            Set<Object> keySet = personalProp.keySet();
            for(Object key: keySet) {
                String strKey = (String) key;
                this.prop.setProperty(strKey, personalProp.getProperty(strKey));
            }
        } catch (IOException e) {
            Log.e("MapsApplication", "Static() " + e);
        } finally {
            if(in != null) {
                try {
                    in.close();
                } catch (IOException e) {}
            }
        }
    }
    
    public String get(String key) {
        return this.prop.getProperty(key);
    }
} public class VFMapComponentView extends MapView{

	private List<Overlay> mapOverlays;
	private VFItemizedOverlay itemizedOverlay;
	private MapController mapController;
	private GeoPoint nextResultToShow;
	private OwnPositionOverlay myPosOverlay;
    private MapFlipInterface parent;
	
	public VFMapComponentView(Context context) {
		super(context, PropertiesManager.get().get("map_cert_key"));
		this.setClickable(false);
		this.setFocusable(false);
		this.setEnabled(false);
		mapOverlays = this.getOverlays();
		mapController = this.getController();
		this.setBuiltInZoomControls(false);

		itemizedOverlay = new VFItemizedOverlay(this);
		
		myPosOverlay = new OwnPositionOverlay(this.getContext(), this, 100);
		mapOverlays.add(myPosOverlay);
	}
	
	public Vector<Object> saveInstanceState() {
		Vector<Object> resultVector = new Vector<Object>();
		resultVector.add(itemizedOverlay.getInflatedPoi());
		resultVector.add(this.getMapCenter());
		resultVector.add(this.getZoomLevel());
		return resultVector;
	}
	
	public void restoreInstanceState(Vector<Object> resultVector) {
		this.itemizedOverlay.setInflatedPoi(((Integer) resultVector.get(0)).intValue());
		this.mapController.setCenter((GeoPoint) resultVector.get(1));
		this.mapController.setZoom(((Integer) resultVector.get(2)).intValue());
	}
	
	public void setParent(MapFlipInterface parent) {
	    this.parent = parent;
	}

	@Override
	protected void onAttachedToWindow() {
		myPosOverlay.enableMyLocation();
		super.onAttachedToWindow();
	}

	@Override
	protected void onDetachedFromWindow() {
		myPosOverlay.disableMyLocation();
		super.onDetachedFromWindow();
	}
	
	/**
	 * Sets zoom to fit current position and the landmark sent to the method
	 * This will only zoom if there is a position 
	 * 
	 * @param landmark landmark to fit into screen
	 * @param animateToFit if map should move to box, probably true 
	 */
    private void zoomToBox(int lat, int lon, boolean animateToFit) {
    	
    	GeoPoint myPosPoint = this.myPosOverlay.getPositionCoord();
		if(myPosPoint != null){
	    	int deltaLat = lat - myPosPoint.getLatitudeE6();
			int deltaLon = lon - myPosPoint.getLongitudeE6();
			mapController.zoomToSpan((int)Math.abs((float)deltaLat * 1.4f), (int)Math.abs((float)deltaLon*1.4f));
			if(animateToFit){
				int moveLat = lat - (deltaLat >> 1);
				int moveLon = lon - (deltaLon >> 1);
				mapController.animateTo(new GeoPoint(moveLat, moveLon));
				if(parent != null){
					parent.enableZoomButtons();
				}
			}
		}
	}
    

	/**
     * Adds a searchResult to the map.
     * 
     * @param landmark The searchResult to add
     * @param category 
     * @param animateToFit calls zoomToBox with coords from landmark and animatToFit=true
     */
	public void addLandmarkToShow(SearchMatch searchMatch, HierarchicalCategory category, boolean animateToFit) {
		int lat = (int)(searchMatch.getPosition().getDecimalLatitude()*1000000);
		int lon = (int)(searchMatch.getPosition().getDecimalLongitude()*1000000);
		nextResultToShow = new GeoPoint(lat,lon);
		VFOverlayItem overlayitem = new VFOverlayItem(nextResultToShow, searchMatch, category, this);
        itemizedOverlay.addOverlay(overlayitem);
        mapOverlays.add(itemizedOverlay);
        if(animateToFit){
        	zoomToBox(nextResultToShow.getLatitudeE6(), nextResultToShow.getLongitudeE6(), true);
        }
	}
	
	public void showMyLocation () {		
		GeoPoint myGeoLocation = myPosOverlay.getPositionCoord();
		mapController.animateTo(myGeoLocation);
	}

	public void showSingleLandMark(SearchMatch searchMatch, HierarchicalCategory category, boolean animateToFit) {
		this.mapOverlays.clear();
		this.mapOverlays.add(myPosOverlay);
		this.itemizedOverlay.clear();
		addLandmarkToShow(searchMatch, category, animateToFit);
	}
    
    public void setMapEnabled(boolean enabled){
        if(enabled){
            this.setClickable(true);
            this.setFocusable(true);
            this.setEnabled(true);
        }
        else {
            this.setClickable(false);
            this.setFocusable(false);
            this.setEnabled(false);
        }
    }

	@Override
	protected void onAnimationEnd() {
		if(this.isShown()){
			this.setClickable(true);
			this.setFocusable(true);
			this.setEnabled(true);
			zoomToBox(nextResultToShow.getLatitudeE6(), nextResultToShow.getLongitudeE6(), true);
		}
		super.onAnimationEnd();
	}

	public void showDetails() {
		this.parent.onFlip();
	}

	public boolean zoom(boolean zoomIn) {
		if(zoomIn){
			return getController().zoomIn();
		}
		else{
			return getController().zoomOut();
		}
	}
}
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.util.Log;
import com.vodafone.locate.activity.AbstractActivity;
import com.vodafone.locate.activity.ServicesActivity;
import com.vodafone.locate.components.AndroidCallbackHandler;
import com.vodafone.locate.data.CategoryLevelData;
import com.vodafone.locate.listeners.DataConnectionStateListener;
import com.vodafone.locate.listeners.GeoCodeChangeListener;
import com.vodafone.locate.listeners.WarningListener;
import com.vodafone.locate.persistance.ApplicationSettings;
import com.vodafone.locate.util.AndroidUnitsFormatter;
import com.vodafone.locate.util.ImageDownloader;
import com.vodafone.locate.util.PropertiesManager;
import com.vodafone.locate.view.VFMapComponentView;
import com.wayfinder.core.Core;
import com.wayfinder.core.CoreFactory;
import com.wayfinder.core.ModuleData;
import com.wayfinder.core.ServerData;
import com.wayfinder.core.map.MapStartupListener;
import com.wayfinder.core.network.NetworkError;
import com.wayfinder.core.network.ServerError;
import com.wayfinder.core.positioning.Criteria;
import com.wayfinder.core.positioning.LocationInformation;
import com.wayfinder.core.positioning.LocationInterface;
import com.wayfinder.core.positioning.LocationListener;
import com.wayfinder.core.positioning.LocationProvider;
import com.wayfinder.core.search.SearchError;
import com.wayfinder.core.shared.Position;
import com.wayfinder.core.shared.RequestID;
import com.wayfinder.core.shared.error.CoreError;
import com.wayfinder.core.shared.error.UnexpectedError;
import com.wayfinder.core.shared.geocoding.AddressInfo;
import com.wayfinder.core.shared.settings.GeneralSettings;
import com.wayfinder.core.shared.util.UnitsFormatter;
import com.wayfinder.pal.PAL;
import com.wayfinder.pal.android.AndroidPAL;
import com.wayfinder.pal.android.network.http.HttpConfigurationInterface;
/*******************************************************************************
 * Copyright (c) 1999-2010, Vodafone Group Services
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met:
 * 
 *     * Redistributions of source code must retain the above copyright 
 *       notice, this list of conditions and the following disclaimer.
 *     * 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.
 *     * Neither the name of Vodafone Group Services 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
 ******************************************************************************/
package com.vodafone.locate;




public class MapsApplication extends Application implements LocationListener {

    public static final int DISMISS_TIME_WARNING_DIALOG = 10;
    public static final int NO_LOCATION_TIMEOUT = 15000; //15 seconds
   
    private static final int NETW_ERROR_WAITING_TIME = 10000;
    private static final double MOVING_SPEED_FACTOR = 7.716; 
    private static final double MOVING_SPEED_CUTTOF = 20; //  20 km/h
    private static final int SQUARE_DISTANCE_BETWEEN_MOVES = 20*20; //a square of 20 x 20

    //HEAD-server
    private static String CLIENT_ID;
    private static String SERVER_URL;
    private static int SERVER_PORT;
    private static boolean isDebug = false;
	private static boolean isInternalRelease = true;

	static {
		CLIENT_ID = "wf-android-demo";
		SERVER_URL = "oss-xml.services.wayfinder.com";
		SERVER_PORT = 80;
	}

    private Handler handler;
    private Core core;
    private boolean isRoaming;
    private WarningListener warningListener;
    private Timer timer;
    private TimerTask displayNetworkErrorTask;
    private boolean roamingWarningDisplayed = false;
    private boolean warningsInitialized = false;
    private PhoneStateListener phoneStateListener;
    private TelephonyManager telefonyManager;
    private WifiManager wifiManager;
    private boolean shouldRecheckWifi = false;
    private AndroidUnitsFormatter unitsFormatter;
    private DataConnectionStateListener dataConnectionStateListener;
    private int dataConnectionState;
    private Stack<String> iServiceWindowHistory = new Stack<String>();
    private Criteria criteria;
    private LocationInformation lastLocationInformation;
    private LocationProvider lastLocationProvider;
    private AddressInfo lastAddressInfo;
    private LocationInformation lastAddressLocation;
    private String savedAddress;
    private Position savedAddressPosition;
	private GeoCodeChangeListener getCodeChangeListener;