public interface Receiver {
	public void onReceiveResult(int resultCode, Bundle resultData);
} public class IS24ApiService extends IntentService {

	public static final String API_RECEIVER = "api_receiver";
	public static final String LAT = "lat";
	public static final String LNG = "lng";
	public static final String NO_FLATS = "no_flats";

	public static final int STATUS_RUNNING = 1;
	public static final int STATUS_FINISHED = 2;
	public static final int STATUS_ERROR = 3;
	
	public IS24ApiService() {
		super("");
	}

	@Override
	protected void onHandleIntent(Intent intent) {
		final ResultReceiver receiver = intent.getParcelableExtra(API_RECEIVER);
		double lat = intent.getDoubleExtra(LAT, 0.0);
		double lon = intent.getDoubleExtra(LNG, 0.0);
		Bundle b = new Bundle();
		Log.d( Const.LOG_TAG, "IS24 search started" ); 
		try {
			receiver.send(STATUS_RUNNING, Bundle.EMPTY);
			final float[] radii = Const.SEARCH_RADII;
			// search for flats in radii[i]. finish if enough flats found (1 is enough in the last run)
			for ( int i = 0; i < radii.length; i++ ) {
				int min = i == radii.length-1 ? 1 : Const.SEARCH_MIN_RESULTS; 
				Flats flats = loadFlats(lat, lon, radii[i], min, Const.SEARCH_MAX_RESULTS );
				if ( flats != null ) {
					Log.d( Const.LOG_TAG, "IS24 search finished. #flats: " + flats.size() ); 
					b.putParcelableArrayList("flats", flats);
					receiver.send(STATUS_FINISHED, b);
					this.stopSelf();
					return;
				}
			}
			// no flats found
			Log.d( Const.LOG_TAG, "IS24 search finished with no flats: " ); 
			b.putString(Intent.EXTRA_TEXT, NO_FLATS);
		} catch (Exception e) {
			Log.e( Const.LOG_TAG, "IS24 search caught Exception: ", e );
		}
		receiver.send(STATUS_ERROR, b); 
		this.stopSelf();
	}

	/**
	 * Runs an IS2 search with the given lat,lon,r
	 * Returns at most 'max' Flats or null if there are less than 'min' flats.   
	 * @param lat Latitude
	 * @param lon Longitude
	 * @param r Radius
	 * @param min minimum nuber of flats
	 * @param max maximum nuber of flats
	 * @return Flats or null
	 * @throws JSONException. MalformedURLException, NullPointerException 
	 */
	private Flats loadFlats(double lat, double lon, float r, int min, int max ) throws JSONException, MalformedURLException 
	{
		Log.d( Const.LOG_TAG, "IS24 search: Lat: " + lat + " Lon: " + lon + " R: " + r + " min: " + min + " max: " + max ); 
		// get the first result page and extract paging info
		JSONObject json = loadPage(lat, lon, r, 1 );  // IS24 page nr starts at 1
		JSONObject resultList = json.getJSONObject("resultlist.resultlist");
		JSONObject pagingInfo = resultList.getJSONObject("paging");
		int numPages = pagingInfo.getInt( "numberOfPages" );
		int results  = pagingInfo.getInt( "numberOfHits" );
		int pageSize = pagingInfo.getInt( "pageSize" );

		Log.d( Const.LOG_TAG, "IS24 search got first page, numPages: " + numPages + " results: " + results +  " pageSize: " + pageSize   ); 
		// return if there aren't enough results
		if ( results < min || numPages*pageSize < min || results <= 0 )
			return null;
		
		// parse flats from 1st result page
		Flats flats = new Flats( max );
		flats.parse( json );
		
		// calc pages to get
		int pages = max / pageSize;
		if ( pages >= 0 && max % pageSize > 0 )
			pages++;
		if ( pages > numPages ) // if this happens theres something wrong here or in the json
			pages = numPages;
		
		// evtly get more pages
		for ( int i = 2; i <= pages; i++ ) {
			json = loadPage(lat, lon, r, i);
			flats.parse( json );
			Log.d( Const.LOG_TAG, "IS24 search got page " + i + "/" + pages + " #flats: " + flats.size() ); 
		}

		// restrict number of results
		if ( flats.size() > max ) {
			Flats lessFlats = new Flats( max );
			lessFlats.addAll( flats.subList(0, max) );
			flats = lessFlats;
		}
		return flats;
	}

	/**
	 * Gets result page number 'page' from IS24 for the given lat,lon,r
	 * @param lat
	 * @param lon
	 * @param r
	 * @param page
	 * @return
	 * @throws MalformedURLException
	 * @throws JSONException
	 */
	private JSONObject loadPage( double lat, double lon, float r, int page ) throws MalformedURLException, JSONException {
		URL url = new URL( OAuthData.SERVER + OAuthData.SEARCH_PREFIX
				+ "search/radius.json?realEstateType=apartmentrent&pagenumber="
				+ page + "&geocoordinates=" + lat + ";" + lon + ";" + r );
		JSONObject obj = WebHelper.getHttpData(url, true, this);
		if (obj == null) { // does this ever happen?
			throw new JSONException( "Got (JSONObject) null for search result. Lat: " + lat + "Lon: " 
									+ lon + " R: " + r + " pageNr: " + page );
		}
		return obj;
	}
} public class ReceiverState {
	public ApiResultReciever mReceiver;
	public boolean mSearching = false;

	public ReceiverState() {
		mReceiver = new ApiResultReciever(new Handler());
	}

	public interface Receiver {
		public void onReceiveResult(int resultCode, Bundle resultData);
	}
} public class ImmopolyActivity extends FragmentActivity implements
		OnMapItemClickedListener, OnTrackingEventListener {

	public static final String FRAGMENT_MAP = "map";
	public static final String C2DM_START = "c2dm_start";
	public static final int START_HISTORY = 0x1;
	private MapView mMapView;
	private Fragment mMapViewHolder;

	private TabHost mTabHost;
	private TabManager mTabManager;
	private GoogleAnalyticsTracker mTracker;

	private static String VERISONINFO="";
	/**
	 * Init the game
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		mTracker = GoogleAnalyticsTracker.getInstance();
		// Start the tracker in manual dispatch mode...

		mTracker.startNewSession(TrackingManager.UA_ACCOUNT, Const.ANALYTICS_INTERVAL, getApplicationContext());

		UserDataManager.instance.setActivity(this);
		setContentView(R.layout.immopoly_activity);

		mTabHost = (TabHost) findViewById(android.R.id.tabhost);
		mTabHost.setup();

		mTabManager = new TabManager(this, mTabHost, R.id.fragment_container);

		// TODO cleanup fragment management for fragments with an without tabs
		// (currently in widget.TabManager)
		addTab(R.drawable.ic_tab_map, FRAGMENT_MAP, MapFragment.class, false);
		addTab(R.drawable.ic_tab_portfolio, "portfolio", PortfolioListFragment.class, false);
		addTab(R.drawable.ic_tab_portfolio, "portfolio_map", PortfolioMapFragment.class, true);
		addTab(R.drawable.ic_tab_profile, "profile", ProfileFragment.class, false);
		addTab(R.drawable.ic_tab_history, "history", HistoryFragment.class, false);
		FragmentManager.enableDebugLogging(true);
//		getSupportFragmentManager().beginTransaction().add(android.R.id.tabhost, new ItemsFragment(), "itemsFragment")
//				.commit();

		if (savedInstanceState != null) {
			mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
		} else {
			// show game description if wanted
			SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
			if ( prefs.getBoolean( "showFirstAid", true ) ) {
				new Handler().postDelayed( new Runnable() {
					@Override
					public void run() {
						new FirstAidDialog(ImmopolyActivity.this).show();
					}
				}, 4000 );
			}
		}
		// for generating oauth token
		// signIn();
		VERISONINFO=getVersionInfo();
	}

	private void addTab(int imageId, String name, Class<?> clss, boolean tabless) {
		TabSpec tabSpec = mTabHost.newTabSpec(name);
		if (!tabless) {
			ImageButton tab = (ImageButton) LayoutInflater.from(this).inflate(R.layout.tab_map, null);
			tab.setImageResource(imageId);
			tab.setBackgroundResource(R.drawable.tab_button);
			tabSpec.setIndicator(tab);
		}
		mTabManager.addTab(tabSpec, clss, null, tabless);
	}

	@Override
	protected void onStart() {
		super.onStart();
	}

	public TabManager getTabManager() {
		return mTabManager;
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		boolean retrieveUserInfo = parseData();
		if ( retrieveUserInfo || UserDataManager.instance.getState() == UserDataManager.USER_UNKNOWN ) {
			UserDataManager.instance.getUserInfo();
		}
	}


	
	/**
	 * n Activity is visible but someone called for a action
	 */
	@Override
	public void onNewIntent(Intent newIntent) {
		// update original intent
		setIntent(newIntent);	
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		outState.putString("tab", mTabHost.getCurrentTabTag());
	}

	/*
	 * parse intent and do action
	 * 
	 * @return whether userInfo should be updated 
	 */
	private boolean parseData() {
		// Start with specific fragment
		Intent i = getIntent();
		if (mTabHost != null && i.hasExtra(ImmopolyActivity.C2DM_START)) {
			switch (i.getIntExtra(ImmopolyActivity.C2DM_START, ImmopolyActivity.START_HISTORY)) {
			case ImmopolyActivity.START_HISTORY:
				mTabHost.setCurrentTabByTag("history");
				break;

			default:
				mTabHost.setCurrentTabByTag("history");
				break;
			}
			i.removeExtra(ImmopolyActivity.C2DM_START);
			return true;
		}
		return false;
	}

	@Override
	public void onFlatClicked(Flat flat) {
		// Toast.makeText(this, "onFlatClicked", Toast.LENGTH_LONG).show();
		DialogFragment newFragment = ExposeFragment.newInstance(flat);
		// newFragment.setArguments(tmp);
		newFragment.show(getSupportFragmentManager(), "dialog");
		mTracker.trackEvent(TrackingManager.CATEGORY_CLICKS, TrackingManager.ACTION_EXPOSE,
				TrackingManager.LABEL_EXPOSE_MAP, 0);

	}

	/**
	 * Used by a Fragment to gain ownership of the one and only MapView
	 * 
	 * @param mapViewHolder
	 *            The Fragment that wants to use the MapView
	 * @return our MapView
	 */
	public MapView acquireMapView(Fragment mapViewHolder) {
		if (this.mMapViewHolder != null) {
			throw new IllegalStateException("The one and only MapView was not released by "
							+ mMapViewHolder.getClass().getName());
		}
		this.mMapViewHolder = mapViewHolder;
		if (mMapView == null) {
			mMapView = new MapView(this, getString(R.string.google_maps_key));
			mMapView.setClickable(true);
			mMapView.setTag("map_view");
		}
		return mMapView;
	}

	/**
	 * Used by a Fragment to release ownership of the one and only MapView
	 * 
	 * @param mapViewHolder
	 *            The Fragment that wants to release the MapView
	 */
	public void releaseMapView(Fragment mapViewHolder) {
		if (mapViewHolder != mMapViewHolder) {
			throw new IllegalStateException("Wrong Fragment tried to release the one and only MapView " + " Holder: "
					+ this.mMapViewHolder.getClass().getName() + " Releaser: " + mapViewHolder.getClass().getName());
		}
		if (mMapView.getParent() != null && mMapView.getParent() instanceof ViewGroup)
			((ViewGroup) mMapView.getParent()).removeView(mMapView);
		mMapView.getOverlays().clear();
		mMapView.removeAllViews();
		mMapViewHolder = null;
	}

	// @Override
	// public void onShareClick(int exposeID, boolean isInPortfolio) {
	// Log.i(Const.LOG_TAG, "https://github.com/immopoly/android/issues/15");
	// }

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		UserDataManager.instance.onActivityResult(requestCode, resultCode, data);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.menu, menu);
		return true;
	}

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		if (UserDataManager.instance.getState() == UserDataManager.USER_UNKNOWN) {
			menu.findItem(R.id.menu_logout).setTitle("Anmelden");
		} else {
			menu.findItem(R.id.menu_logout).setTitle("Abmelden");
		}
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		Intent intent;
		int itemId = item.getItemId();
		switch (itemId) {
		case R.id.menu_settings:
			intent = new Intent(this, SettingsActivity.class);
			startActivity(intent);
			break;
		case R.id.menu_website:
			intent = new Intent(Intent.ACTION_VIEW);
			intent.setData(Uri.parse("http://immopoly.org"));
			startActivity(intent);
			break;
		case R.id.menu_highscore:
//			intent = new Intent(Intent.ACTION_VIEW);
//			intent.setData(Uri.parse("http://immopoly.org/livestats.html?c=android"));
//			startActivity(intent);
			new HighScoreDialog( this ).show();
//			showHighscoreDialog( "Highscores werden geladen...", "Highscores", "http://immopoly.org/frameless-topx_balance.html" );
			break;
		case R.id.menu_help:
//			intent = new Intent(Intent.ACTION_VIEW);
//			intent.setData(Uri.parse("http://immopoly.org/frameless-helpandroid.html"));
//			startActivity(intent);
//			showWebDialog( "Hilfe wird geladen...", "Hilfe",  );
			new WebViewDialog( this, "Hilfe", "http://immopoly.org/frameless-helpandroid.html" ).show();
			break;
		// case R.id.menu_recommend:
		// intent = new Intent(Intent.ACTION_SEND);
		// intent.setType("text/plain");
		// intent.putExtra(Intent.EXTRA_TEXT,
		// "Immopoly is geil, lade es dir hier runter http://immopoly.org/download.html");
		// startActivity(Intent.createChooser(intent, "Sahre"));
		// break;
		case R.id.menu_contact:
			intent = new Intent(Intent.ACTION_SEND);
			intent.setType("message/rfc822");
			intent.putExtra(Intent.EXTRA_EMAIL, new String[] { "immopolyteam@gmail.com" });
			intent.putExtra(Intent.EXTRA_SUBJECT, "Immopoly Feedback " + getVersionInfo());
			startActivity(Intent.createChooser(intent, "Feedback:"));
			break;
		case R.id.menu_logout:
			if (UserDataManager.instance.getState() == UserDataManager.LOGGED_IN) {
				UserDataManager.instance.logout();
			} else {
				UserDataManager.instance.login();
			}
			break;
		default:
			break;
		}

		return true;
	}

	public String getVersionInfo() {
		try {
			return getPackageManager().getPackageInfo(getPackageName(), 0).versionName + " ("
					+ getPackageManager().getPackageInfo(getPackageName(), 0).versionCode + ")";
		} catch (NameNotFoundException e) {
			return "";
		}
	}

	public static String getStaticVersionInfo() {
		return VERISONINFO;
	}
	
	@Override
	public void onDestroy() {
		super.onDestroy();
		mTracker.stopSession();
	}

	@Override
	public void onTrackPageView(String page) {
		mTracker.trackPageView(page);
	}

	@Override
	public void onTrackEvent(String category, String action, String label, int i) {
		mTracker.trackEvent(category, action, label, i);
	}

	public void signIn() {
		String authUrl = "";
		SharedPreferences shared = getSharedPreferences("oauth", 0);
		String accessToken = shared.getString("oauth_token", "");
		if (accessToken.length() > 0) {
			OAuthData.getInstance(this).signedIn = true;
			OAuthData.getInstance(this).accessToken = accessToken;
		} else {
			OAuthData.getInstance(this).signedIn = false;
			try {
				authUrl = OAuthData.getInstance(this).provider.retrieveRequestToken(
						OAuthData.getInstance(this).consumer, OAuth.OUT_OF_BAND);
			} catch (OAuthMessageSignerException e) {
				e.printStackTrace();
			} catch (OAuthNotAuthorizedException e) {
				e.printStackTrace();
			} catch (OAuthExpectationFailedException e) {
				e.printStackTrace();
			} catch (OAuthCommunicationException e) {
				e.printStackTrace();
			}

			// Login in web view
			Intent i = new Intent(this, OauthLoginActivity.class);
			i.putExtra("oauth_url", authUrl);
			i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			startActivity(i);
		}
	}
} public interface UserDataListener {
	
	public void onUserDataUpdated();

} public class UserDataManager {
	public static final int USER_UNKNOWN = 0;
	public static final int LOGIN_PENDING = 1; // TODO unused (yet)
	public static final int LOGGED_IN = 2;

//	private boolean actionPending;

	private int state = USER_UNKNOWN;
	private Activity activity;
	private GoogleAnalyticsTracker mTracker;

	private Vector<UserDataListener> listeners = new Vector<UserDataListener>();
	private Flat flatToAddAfterLogin;

	// the singleton instance
	public static final UserDataManager instance = new UserDataManager();

	private UserDataManager() {
	}

	public void setActivity(Activity activity) {
		this.activity = activity;

		if (mTracker == null) {
			mTracker = GoogleAnalyticsTracker.getInstance();
			// Start the tracker in manual dispatch mode...
			mTracker.startNewSession(TrackingManager.UA_ACCOUNT,
					Const.ANALYTICS_INTERVAL, activity.getApplicationContext());
		}
	}

	public void addUserDataListener(UserDataListener udl) {
		listeners.add(udl);
	}

	public void removeUserDataListener(UserDataListener udl) {
		listeners.remove(udl);
	}

	public int getState() {
		return state;
	}

	/**
	 * summons UserSignupActivity to login or register informs listeners on
	 * successful operation
	 */
	public void login() {
		Log.i(Const.LOG_TAG, "UserDataManager.login() state = " + state);
//		if (actionPending) {
//			Log.w(Const.LOG_TAG,
//					"Refusing to log in while another server request is running");
//			return;
//		}
		if (state != USER_UNKNOWN) {
			Log.e(Const.LOG_TAG, "Already logged in. Log out first.");
			return;
		}

//		actionPending = true;
		state = LOGIN_PENDING;
		Intent intent = new Intent(activity, UserSignupActivity.class);
		activity.startActivityForResult(intent, Const.USER_SIGNUP);
	}

	public boolean logout() {
		Log.i(Const.LOG_TAG, "UserDataManager.logout() state = " + state);
//		if (actionPending) {
//			Log.w(Const.LOG_TAG,
//					"Refusing to log out while another server request is running");
//			return false;
//		}
		if (state != LOGGED_IN) {
			Log.e(Const.LOG_TAG, "Already logged in. Log out first.");
			return false;
		}
		state = USER_UNKNOWN;
		ImmopolyUser.resetInstance();
		if (null != this.activity)
			setToken(activity, null);
		fireUsedDataChanged();
		return true;
	}

	/**
	 * Receives results from Actitvies (UserSignupActivity for now)
	 * 
	 * informs listeners if signup succeeded
	 * 
	 * ! Must be invoked from ImmopolyActivity.onActivityResult
	 * 
	 */
	void onActivityResult(int requestCode, int resultCode, Intent data) {
		Log.i(Const.LOG_TAG, "UserDataManager.onActivityResult() state = "
				+ state);
//		actionPending = false;
		if (requestCode == Const.USER_SIGNUP) {
			if (resultCode == Activity.RESULT_OK) {
				state = LOGGED_IN;
				Log.i(Const.LOG_TAG,
						"UserDataManager.onActivityResult() state2  = " + state);
				fireUsedDataChanged();
				if (flatToAddAfterLogin != null)
					addToPortfolio(flatToAddAfterLogin);
			} else {
				Log.i(Const.LOG_TAG,
						"UserDataManager.onActivityResult() state3  = " + state);
				state = USER_UNKNOWN;
				fireUsedDataChanged();
			}
		}
		Log.i(Const.LOG_TAG, "UserDataManager.onActivityResult() state4  = "
				+ state);
	}

	/**
	 * retrieves UserInfo data from server and fills ImmopolyUser.instance
	 * 
	 * informs listeners on successful operation
	 */
	public void getUserInfo() {
		String token = ImmopolyUser.getInstance().readToken(activity);
		if ( token == null || token.length() == 0 ) {
			Log.i(Const.LOG_TAG, "UserDataManager.getUserInfo() called, but no token there. Returning... ");
			return;
		}
		Log.i(Const.LOG_TAG, "UserDataManager.getUserInfo() state = " + state);
//		if (actionPending) {
//			Log.w(Const.LOG_TAG,
//					"Refusing to get user info while another server request is running");
//			return;
//		}
		Log.i(Const.LOG_TAG, "UserDataManager.getUserInfo() state2 = " + state);
//		actionPending = true;
		state = LOGIN_PENDING;
		Log.i(Const.LOG_TAG, "UserDataManager.getUserInfo() state3 = " + state);
		GetUserInfoTask task = new GetUserInfoTask(activity) {
			@Override
			protected void onPostExecute(ImmopolyUser user) {
//				actionPending = false;
				if (user != null) {
					state = LOGGED_IN;
				} else {
					state = USER_UNKNOWN;
				}
				Log.i(Const.LOG_TAG, "UserDataManager.getUserInfo() state4 = "
						+ state);
				fireUsedDataChanged();
			}
		};
		task.execute(token);
	}

	/**
	 * Tries to add a flat to the users portfolio using AddToPortfolioTask.
	 * Informs listeners on successful operation
	 * 
	 * @param flat
	 *            the flat to add
	 */
	public void addToPortfolio(final Flat flat) {
		Log.i(Const.LOG_TAG, "UserDataManager.addToPortfolio " + flat.uid);
		// login first if not yet
		if (state == USER_UNKNOWN) {
			flatToAddAfterLogin = flat;
			login();
			return;
		}

		if (!checkState())
			return;
//		actionPending = true;
		new AddToPortfolioTask(activity, mTracker) {
			protected void onPostExecute(final Result result) {
				super.onPostExecute(result);
				
				//TODO schtief der Rotz hier kommt nach super da gibs jetzt nen UserDataManager.update 
				if (result.success) {
					flat.owned = true;
					flat.takeoverDate = System.currentTimeMillis();
					ImmopolyUser.getInstance().getPortfolio().add(flat);
					mTracker.trackEvent(TrackingManager.CATEGORY_ALERT_EXPOSE_TAKEN, TrackingManager.ACTION_TOOK_EXPOSE, TrackingManager.LABEL_POSITIVE, 0);
				}
				/**
				 * show the feedback in a dialog, from there the user can either
				 * share the result or
				 */
				int title = result.success ? R.string.take_over_success_dlg_title : R.string.take_over_fail_dlg_title;
				showExposeDialog(flat, result, activity.getString(title));
				//TODO schtief wird schon in super gemacht
				fireUsedDataChanged();
//				actionPending = false;
			}
		}.execute(flat);
	}

	protected void showExposeDialog(final Flat flat, final Result result, final String title ) {
		AlertDialog.Builder builder = new AlertDialog.Builder(activity);
		builder.setTitle( title );
		final String text = null != result.history ? result.history.getText() 
			: (null != result.exception ? result.exception.getMessage()
			: "Ein Fehler ist aufgetreten.");

		builder.setMessage(text);
		// builder.setContentView(R.layout.maindialog);
		builder.setCancelable(true).setNegativeButton(activity.getString(R.string.share_item), new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int id) {
				Settings.getFlatLink( Integer.toString(flat.uid), false);
				Settings.shareMessage(activity, title, text, Settings.getFlatLink(
						Integer.toString(flat.uid), false) /* LINk */);
				mTracker.trackEvent(TrackingManager.CATEGORY_ALERT_EXPOSE_TAKEN, TrackingManager.ACTION_SHARE, TrackingManager.LABEL_POSITIVE, 0);
			}
		});
		builder.setPositiveButton(result.success ? R.string.button_ok : R.string.button_mist, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int id) {
				mTracker.trackEvent(TrackingManager.CATEGORY_ALERT_EXPOSE_TAKEN, TrackingManager.ACTION_SHARE, TrackingManager.LABEL_NEGATIVE, 0);
			}
		});
		AlertDialog alert = builder.create();
		alert.show();
	}

	/**
	 * Tries to release a flat from the users portfolio using
	 * RemoveFromPortfolioTask. Informs listeners on successful operation
	 * 
	 * @param flat
	 *            the flat to add
	 */
	public void releaseFromPortfolio(final Flat flat) {
		Log.i(Const.LOG_TAG, "UserDataManager.releaseFromPortfolio " + flat.uid);
		if (!checkState())
			return;
//		actionPending = true;
		new ReleaseFromPortfolioTask(activity, mTracker) {
			@Override
			protected void onPostExecute(Result result) {
				super.onPostExecute(result);
				if (result.success) {
					// remove the flat from users portfolio list
					flat.owned = false;
					Flat toBeRemoved = null;
					for (Flat f : ImmopolyUser.getInstance().getPortfolio())
						if (f.uid == flat.uid)
							toBeRemoved = f;
					if (toBeRemoved != null) {
						Log.i(Const.LOG_TAG,
								"UserDataManager.releaseFromPortfolio() Flat removed: "
										+ flat.name);
						ImmopolyUser.getInstance().getPortfolio()
								.remove(toBeRemoved);
						toBeRemoved.owned = false;
					} else {
						Log.w(Const.LOG_TAG,
								"UserDataManager.releaseFromPortfolio() Flat NOT removed: "
										+ flat.name);
					}
					
					/**
					 * show the feedback in a dialog, from there the user can either
					 * share the result or
					 */
					showExposeDialog(flat, result, activity.getString(R.string.flat_released_dlg_title));
					
					fireUsedDataChanged();
//					actionPending = false;
				}
			};
		}.execute(flat);
	}

	public void fireUsedDataChanged() {
		Log.i(Const.LOG_TAG, "UserDataManager.fireUsedDataChanged()");
		for (final UserDataListener listener : listeners){
			activity.runOnUiThread(new Runnable() {	
				@Override
				public void run() {
					listener.onUserDataUpdated();
				}
			});
		}
	}

	private boolean checkState() {
//		if (actionPending) {
//			Log.w(Const.LOG_TAG,
//					"Refusing to send request while another server request is running");
//			return false;
//		}
		if (state != LOGGED_IN) {
			Log.e(Const.LOG_TAG, "Not logged in.");
			return false;
		}
		return true;
	}

	// handle the token only here set null to remove
	public static void setToken(ContextWrapper context, String token) {
		SharedPreferences shared = context.getSharedPreferences(
				ImmopolyUser.sPREF_USER, 0);
		SharedPreferences.Editor editor = shared.edit();
		if (token == null)
			editor.remove(ImmopolyUser.sPREF_TOKEN);
		else
			editor.putString(ImmopolyUser.sPREF_TOKEN, token);
		editor.commit();
	}

	public void update(ImmopolyHistory history) {
		ImmopolyUser u =ImmopolyUser.getInstance();
		if(null==u)
			return;
		
		u.getHistory().add(0, history);
		
		if(null!=history.getAmount())
			u.setBalance(u.getBalance()+history.getAmount());

		fireUsedDataChanged();
	}
} public class Const {

	public static final String LOG_TAG = "IMPO";

	// Intents

	// Intent open webview
	public static final String EXPOSE_ID = "exposeID";
	public static final String EXPOSE_NAME = "exposeName";
	public static final String EXPOSE_DESC = "exposeDescription";
	public static final String EXPOSE_URL = "exposeURL";
	public static final String EXPOSE_IN_PORTOFOLIO = "exposeInPortfolio";
	
//	public static final String EXPOSE_OWNED = "exposeOwned";

	// Intent add portofolio
	public static final String EXPOSE_ADD_PORTIFOLIO = "addToPortifolio";
	public static final String EXPOSE_RELEASE_PORTIFOLIO = "releaseFromPortifolio";

	public static final String SOURCE = "source";

	// immopoly
	public static final String EXPOSE_PICTURE_SMALL = "exposeDescription";

	public static final String SHARED_PREF_EXPOSE_WEBVIEW = "exposeWebView";
	public static final String KEY_VISITED = "visited";

	public static final String AUTH_URL = "oauth_url";
	public static final long EXPOSE_THRESHOLD_OLD = 1000L * 60L * 60L * 24L
			* 30L;
	public static final long EXPOSE_THRESHOLD_NEW = 1000L * 60L * 60L * 24L
			* 7L;

	public static final String MESSAGE_IMMOPOLY_EXCEPTION = "org.immopoly.common.ImmopolyException";

	public static final String IMMOPOLY_EMAIL = "immopolyteam@gmail.com";
	public static final int ANALYTICS_INTERVAL = 20;

	public static final int USER_SIGNUP = 110;

	// IS24 search control - search different radii until at least SEARCH_MIN_RESULTS flats are found  
	public static final float[] SEARCH_RADII 	   = { 1, 3, 10 }; // in km
	public static final int     SEARCH_MIN_RESULTS = 50;		   // ignored for last search radius
	public static final int     SEARCH_MAX_RESULTS = 80;		   // forced result limit. fernglas me, baby!
} public class HudPopupHelper {

	public static final int TYPE_FINANCE_POPUP = 0x1;
	private final static NumberFormat nFormat = NumberFormat.getCurrencyInstance(Locale.GERMANY);

	private LinearLayout mLayoutView = null;
	private PopupWindow mPopupView = null;

	public HudPopupHelper(Activity activity, int type) {
		switch (type) {
		case TYPE_FINANCE_POPUP:
			mLayoutView = (LinearLayout) activity.getLayoutInflater().inflate(R.layout.hud_statistic, null);
			break;

		default:
			mLayoutView = (LinearLayout) activity.getLayoutInflater().inflate(R.layout.hud_statistic, null);
			break;
		}
		if (mLayoutView != null) {
			mPopupView = new PopupWindow(mLayoutView, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, false);
			mPopupView.setOutsideTouchable(true);
			mPopupView.setBackgroundDrawable(new BitmapDrawable());
			mPopupView.setTouchable(true);
			mPopupView.setTouchInterceptor(new View.OnTouchListener() {

				@Override
				public boolean onTouch(View v, MotionEvent event) {
					// do this later - otherwise HudFragment would pup me up again imidiately (better ideas welcome) 
					new Handler().postDelayed(new Runnable() {
						public void run() {
							mPopupView.dismiss();
						}
					}, 200 );
					return true;
				}
			});
		}
	}

	public void show(View view, int xOffset, int yOffset) {
		if (mPopupView != null) {
			if (!mPopupView.isShowing()) {
				ImmopolyUser user = ImmopolyUser.getInstance();

				TextView currentCostTextView = (TextView) mLayoutView.findViewById(R.id.current_cost);
				if (currentCostTextView != null) {
					nFormat.setMinimumIntegerDigits(1);
					nFormat.setMaximumFractionDigits(0);
					nFormat.setCurrency(Currency.getInstance(Locale.GERMANY));

					currentCostTextView.setText(nFormat.format(user.getLastRent()));
				}
				
				String calculatedCosts = nFormat.format((int) (user.getLastRent() * 30));
				TextView calculatedCostTextView = (TextView) mLayoutView.findViewById(R.id.calculated_cost);
				if (calculatedCostTextView != null) {
					calculatedCostTextView.setText(calculatedCosts);
				}

				String lastProvision = nFormat.format((int) (user.getLastProvision()));
				TextView lastProvisionTextView = (TextView) mLayoutView.findViewById(R.id.last_provision);
				if (lastProvisionTextView != null) {
					lastProvisionTextView
							.setText(lastProvision);
				}
				
				TextView balanceCostTextView = (TextView) mLayoutView.findViewById(R.id.current_balance);
				if (balanceCostTextView != null) {
					balanceCostTextView.setText(nFormat.format(user.getBalance()));
				}
				
				TextView numFlatsView = (TextView) mLayoutView.findViewById( R.id.num_flats );
				numFlatsView.setText( user.getPortfolio().size() +" / " + user.getMaxExposes() );

				mPopupView.showAsDropDown(view, view.getWidth(), 0 );
			} else {
				mPopupView.dismiss();
			}
		}

	}

	public boolean isShowing() {
		return (mPopupView != null && mPopupView.isShowing());
	}

	public void dismiss() {
		if (mPopupView != null) {
			mPopupView.dismiss();
		}
	}
} public class LocationHelper {

	public interface LocationCallback {
		void onLocationChanged(boolean center);

		void failed();
	}

	// teshhold when location is too old
	// private static final int TRESH = 150000;

	public static double sLat = 52.548932;
	public static double sLng = 13.416416;
	public static float sAccuracy = Float.MAX_VALUE;;
	public static long sTime = 0;
	public static String mAddress = "";
	private static LocationListener mlocListener;
	private static LocationManager mLocationManager;
	private static Criteria mCriteria = null;

	// user can force location update
	// private static final int LOCATION_REFRESH_TRESH = 1;
	private static int sCountRequest = 0;

	public static void requestLocationSettings(final Context context) {
		// LocationHelper.getLastLocation(this);
		AlertDialog.Builder builder = new AlertDialog.Builder(context);
		builder.setTitle(R.string.allow_localization_title);
		builder.setMessage(R.string.allow_localization_message);
		builder.setCancelable(true).setNegativeButton(R.string.button_cancel,
				new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int id) {
					}
				});
		final Intent locationSettingsIntent = new Intent(
				android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
		final ComponentName toLaunch = new ComponentName(
				"com.android.settings", "com.android.settings.SecuritySettings");

		locationSettingsIntent.addCategory(Intent.CATEGORY_LAUNCHER);
		locationSettingsIntent.setComponent(toLaunch);
		locationSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

		final Intent generellSettingsIntent = new Intent(
				Settings.ACTION_SETTINGS);
		builder.setPositiveButton("Einstellungen",
				new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int id) {

						if (context.getPackageManager().resolveActivity(
								locationSettingsIntent,
								PackageManager.MATCH_DEFAULT_ONLY) != null) {
							context.startActivity(locationSettingsIntent);
						} else if (context.getPackageManager().resolveActivity(
								generellSettingsIntent,
								PackageManager.MATCH_DEFAULT_ONLY) != null) {
							context.startActivity(generellSettingsIntent);
						} else {
							Toast.makeText(
									context,
									context.getString(R.string.allow_localization_message_manuel),
									Toast.LENGTH_LONG).show();
						}
					}
				});
		AlertDialog alert = builder.create();
		alert.show();
	}

	// The default search radius when searching for places nearby.
	// public static int DEFAULT_RADIUS = 150;
	// The maximum distance the user should travel between location updates.
	// public static int MAX_DISTANCE = DEFAULT_RADIUS / 2;
	// The maximum time that should pass before the user gets a location update.
	// public static long MAX_TIME = AlarmManager.INTERVAL_FIFTEEN_MINUTES;

	public static void getLastLocation(final Context context,
			final LocationCallback callback) {
		// double tmpLat = sLat;
		// double tmpLng = sLng;
		sCountRequest++;

		getCriteria(context);
		if (mLocationManager == null) {
			mLocationManager = (LocationManager) context
					.getApplicationContext().getSystemService(
							Context.LOCATION_SERVICE);
		}
		// if (sTime < MAX_TIME || sAccuracy > MAX_DISTANCE || sCountRequest >
		// LOCATION_REFRESH_TRESH) {
		sCountRequest = 0;
		if (mlocListener == null) {
			String bestProvider = getBestProvider(context);
			if (bestProvider != null) {
				mlocListener = new LocationListener() {

					@Override
					public void onLocationChanged(Location loc) {
						boolean newLoc = false;
						// if (sAccuracy >= loc.getAccuracy()) {
						sLat = loc.getLatitude();

						sLng = loc.getLongitude();

						sAccuracy = loc.getAccuracy();
						sTime = loc.getTime();
						newLoc = true;
						// }
						if (callback != null) {
							callback.onLocationChanged(newLoc);
						}
						if (mlocListener != null)
							mLocationManager.removeUpdates(mlocListener);

						mlocListener = null;
					}

					@Override
					public void onProviderDisabled(String provider) {
						if (mlocListener != null) {
							mLocationManager.removeUpdates(mlocListener);
						}
						if (callback != null) {
							callback.failed();
						}
						mlocListener = null;
						requestLocationSettings(context);
					}

					@Override
					public void onProviderEnabled(String provider) {

					}

					@Override
					public void onStatusChanged(String arg0, int arg1,
							Bundle arg2) {
						if (mlocListener != null)
							mLocationManager.removeUpdates(mlocListener);
						mlocListener = null;
						requestLocationSettings(context);
					}
				};

				mLocationManager.requestLocationUpdates(bestProvider, 0, 0,
						mlocListener);
			} else {
				requestLocationSettings(context);
			}
		}

	}

	private static void getCriteria(final Context context) {
		if (mCriteria == null) {
			mCriteria = new Criteria();
			mCriteria.setAccuracy(Criteria.ACCURACY_COARSE);
			mCriteria.setAltitudeRequired(false);
			mCriteria.setBearingRequired(false);
			mCriteria.setCostAllowed(true);
			mCriteria.setPowerRequirement(Criteria.POWER_LOW);
		}
	}

	public static void getLastLocationFromProvider(Context context) {

		Location lastLocation = null;
		try {
			getCriteria(context);
			lastLocation = mLocationManager
					.getLastKnownLocation(mLocationManager.getBestProvider(
							mCriteria, true));
			if (lastLocation != null) {
				sLat = lastLocation.getLatitude();
				sLng = lastLocation.getLongitude();
				sAccuracy = lastLocation.getAccuracy();
				sTime = lastLocation.getTime();
			}
		} catch (IllegalArgumentException e) {
			// do nothing at the moment, ideas ?
			requestLocationSettings(context);
		}

	}

	public static String getBestProvider(Context context) {
		getCriteria(context);
		if (mLocationManager == null) {
			mLocationManager = (LocationManager) context
					.getApplicationContext().getSystemService(
							Context.LOCATION_SERVICE);
		}
		return mLocationManager.getBestProvider(mCriteria, true);
	}

} public interface OnTrackingEventListener {
	public void onTrackPageView(String page);
	public void onTrackEvent(String category, String action, String label, int i);
} public class TrackingManager {

	public static final String UA_ACCOUNT = "UA-25341313-1";

	// Page views, basicly Activities where you can do events
	public static final String VIEW_SIGNUP = "signup";
	public static final String VIEW_REGISTER = "register";
	public static final String VIEW_LOGIN = "login";
	public static final String VIEW_MAP = "map";
	public static final String VIEW_EXPOSE = "expose";
	public static final String VIEW_HISTORY = "history";
	public static final String VIEW_SHARE = "share";
	public static final String VIEW_ITEMS = "actionItems";
	public static final String VIEW_PORTFOLIO_LIST = "portfolioList";
	public static final String VIEW_PORTFOLIO_MAP = "portfolioMap";
	public static final String VIEW_PROFILE = "profile";
	public static final String VIEW_SETTINGS = "settings";
	public static final String VIEW_HELP = "help";
	public static final String VIEW_HIGHSCORE_OVERALL = "highscoreOverall";
	public static final String VIEW_HIGHSCORE_MONTH = "highscoreMonth";
	public static final String VIEW_HIGHSCORE_RELEAS_TESTER = "highscoreReleaseTester";
	public static final String VIEW_WEB_VIEW_DIALOG = "webviewDialog";
	public static final String VIEW_FIRST_AID = "firstAid";
	public static final String VIEW_ACTION_ITEM_SPY = "actionItemSpye";
	

	public static final String CATEGORY_CLICKS = "clicks";
	public static final String CATEGORY_SCROLL = "scroll";
	public static final String CATEGORY_ALERT_EXPOSE_TAKEN = "alert";
	public static final String CATEGORY_CLICKS_IN_WEBSITE = "click_in_website";
	public static final String CATEGORY_SHAREBUTTON = "click_on_share_button";

	public static final String ACTION_SHARE = "share";
	public static final String ACTION_VIEW = "view";
	public static final String ACTION_ERROR = "error";
	public static final String ACTION_EXPOSE = "tookExpose";
	public static final String ACTION_TOOK_EXPOSE = "tookExpose";
	public static final String ACTION_RELEASED_EXPOSE = "releasedExpose";
	public static final String ACTION_CONTACT = "clickWebviewContact";
	public static final String ACTION_FIRST_AID = "firstAid";
	public static final String ACTION_SEARCH = "search";
	public static final String ACTION_BADGE = "badge";

	public static final String LABEL_TRY = "try";
	public static final String LABEL_RELEASE = "release";
	public static final String LABEL_POSITIVE = "positive";
	public static final String LABEL_NEGATIVE = "negative";
	public static final String LABEL_IMAGES = "image";
	public static final String LABEL_IMAGES_DETAILS = "imagesDetails";
	public static final String LABEL_CHANGE_TO_REGISTER_FROM_LOGIN = "changeFromRegisterToLogin";
	public static final String LABEL_CHANGE_TO_LOGIN_FROM_REGISTER = "changeFromLoginToRegister";
	public static final String LABEL_BACK_INSIDE_IMMOSCOUT_WEBSITE = "clickBackInsideImmoscoutWebsite";
	public static final String LABEL_HUD_POPUP = "showHudPopup";
	public static final String LABEL_EXPOSE_PORTFOLIO = "openExposeFromPortfolio";
	public static final String LABEL_EXPOSE_MAP = "openExposeFromMap";
	public static final String LABEL_DISABLED = "disabled";
	public static final String LABEL_ENABLED = "enabled";
	public static final String LABEL_REFRESH = "refresh";
	public static final String LABEL_VIEW = "view";


} public class Flat implements Parcelable, Comparable<Flat>, SQLData {

	public static final int AGE_OLD    = 0;
	public static final int AGE_NORMAL = 1;
	public static final int AGE_NEW    = 2;
	
	private static SimpleDateFormat DF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
	// http://developer.immobilienscout24.de/wiki/Expose/GET
	public int uid;
	public String name;
	public String description;
	public String locationNote;
	public double lat;
	public double lng;
	
	public boolean displayed = false;
	public boolean owned = false;

	public int houseNumber;
	public String street;
	public String city;
	public String postcode;
	public double distance;

	public String quarter;
	public String titlePictureTitle;
	public String titlePictureDescriptionNote;
	public String titlePictureFurnitureNote;
	public String titlePictureLocationNote;
	public String titlePictureSmall = "";
	public String titlePictureMedium = "";
	public String titlePictureLarge = "";
	public String marketingType;
	public String priceValue;
	public String priceIntervaleType;
	public String currency;
	public double livingSpace;
	public int    numRooms;
	public long   creationDate=0;
	public int    age;
	public int    takeoverTries;
	public long   takeoverDate;
	public boolean visible = true;
	
	public int describeContents() {
		// TODO Auto-generated method stub
		return 0;
	}

	public void writeToParcel(Parcel dest, int flags) {
		dest.writeInt(uid);
		dest.writeString(name);
		dest.writeString(description);
		dest.writeString(city);
		dest.writeString(titlePictureSmall);
		dest.writeString(priceValue);
		dest.writeString(currency);
		dest.writeString(priceIntervaleType);
		dest.writeDouble(lat);
		dest.writeDouble(lng);
		dest.writeLong(creationDate);
	}

	public static final Parcelable.Creator<Flat> CREATOR = new Parcelable.Creator<Flat>() {
		public Flat createFromParcel(Parcel in) {
			return new Flat(in);
		}

		public Flat[] newArray(int size) {
			return new Flat[size];
		}
	};

	public Flat(Parcel in) {
		uid = in.readInt();
		name = in.readString();
		description = in.readString();
		city = in.readString();
		titlePictureSmall = in.readString();
		priceValue = in.readString();
		currency = in.readString();
		priceIntervaleType = in.readString();
		lat = in.readDouble();
		lng = in.readDouble();
		creationDate=in.readLong();
		long ageMs = System.currentTimeMillis() - creationDate;
		age = ageMs < Const.EXPOSE_THRESHOLD_NEW ? AGE_NEW
				: ageMs < Const.EXPOSE_THRESHOLD_OLD ? AGE_NORMAL
			    : AGE_OLD;
	}

	public Flat() {
	}

	public Flat(JSONObject jsonObject) throws JSONException {
		distance = jsonObject.optDouble("distance", 0);
		uid = jsonObject.optInt("realEstateId");
		// OWN OBJECT
		JSONObject objRealEstate = jsonObject
				.getJSONObject("resultlist.realEstate");
		name = objRealEstate.optString("title");
		description = objRealEstate.optString("descriptionNote");
		locationNote = objRealEstate.optString("locationNote");
		livingSpace = objRealEstate.optDouble("livingSpace");
		numRooms = objRealEstate.optInt("numberOfRooms");
		// OWN OBJECT

		/**
		 * Address Fields
		 */
		JSONObject objAddress = objRealEstate.getJSONObject("address");
		street = objAddress.optString("street");
		houseNumber = objAddress.optInt("houseNumber", 0);
		postcode = objAddress.optString("postcode");
		city = objAddress.optString("city");
		quarter = objAddress.optString("quater");
		if (objAddress != null && objAddress.has("wgs84Coordinate")) {
			JSONObject coordinate = objAddress.getJSONObject("wgs84Coordinate");
			lat = coordinate.optDouble("latitude");
			lng = coordinate.optDouble("longitude");
		} else // TODO get rid of this flat
			Log.w( Const.LOG_TAG, "Exposee has no coordinates: " + uid  );
		if (objRealEstate.has("titlePicture")) {
			JSONObject objPicture = objRealEstate.getJSONObject("titlePicture");
			titlePictureTitle = objPicture.optString("title");
			titlePictureDescriptionNote = objPicture
					.optString("descriptionNote");
			titlePictureFurnitureNote = objPicture.optString("furnishingNote");
			titlePictureLocationNote = objPicture.optString("locationNote");
			titlePictureSmall = objPicture.optString("@xlink.href");
			if (objPicture.has("urls")
					&& objPicture.getJSONArray("urls").length() > 0) {
				// JSONArray urls =
				// objPicture.getJSONArray("urls").getJSONObject(
				// 0).getJSONArray("url");
				JSONObject urls = objPicture.getJSONArray("urls")
						.getJSONObject(0).getJSONObject("url");
				titlePictureSmall = urls.optString("@href");
				/*
				 * if (urls.length() > 0) { titlePictureSmall =
				 * urls.getJSONObject(0).getString("href"); } else if
				 * (urls.length() > 1) { titlePictureMedium =
				 * urls.getJSONObject(1).getString("href"); } else if
				 * (urls.length() > 2) { titlePictureLarge =
				 * urls.getJSONObject(2).getString("href"); }
				 */
			}
		}
		if (objRealEstate.has("price")) {
			marketingType = objRealEstate.getJSONObject("price").optString("marketingType");
			priceValue = objRealEstate.getJSONObject("price").optString("value");
			priceIntervaleType = objRealEstate.getJSONObject("price").optString("priceIntervalType");
			currency = objRealEstate.getJSONObject("price").optString("currency");
			try {
				double price = Double.parseDouble(priceValue);
				priceValue = Integer.toString( (int) Math.round(price) );
			} catch (Exception e) {} 
		} else {
			priceValue = "?";
		}
		//schtief issue #7 2006-09-19T15:27:19.000+02:00
		if (jsonObject.has("@modification")) {
			String creationDateS=jsonObject.getString("@modification");
//			Log.i(PlacesMap.TAG,"creationDate "+creationDateS);
			creationDateS=creationDateS.replace('T', ' ');
			creationDateS=creationDateS.substring(0,creationDateS.indexOf("+"));
			try {
				creationDate=DF.parse(creationDateS).getTime();
			} catch (ParseException e) {
				Log.e("ERRO", "could not parse creationDate", e);
			}
		}else{
//			Log.e(PlacesMap.TAG,"no creationDate "+jsonObject.toString());
		}
		long ageMs = System.currentTimeMillis() - creationDate;
		age = ageMs < Const.EXPOSE_THRESHOLD_NEW ? AGE_NEW
				: ageMs < Const.EXPOSE_THRESHOLD_OLD ? AGE_NORMAL
			    : AGE_OLD;
	}

	@Override
	public int compareTo(Flat another) {
		// TODO Auto-generated method stub
		return this.name.compareTo(another.name);
	}

	@Override
	public String getSQLTypeName() throws SQLException {
		return "de.tosa.findaflat.flat";
	}

	@Override
	public void readSQL(SQLInput arg0, String arg1) throws SQLException {
		// TODO Auto-generated method stub

	}

	@Override
	public void writeSQL(SQLOutput arg0) throws SQLException {
		// TODO Auto-generated method stub

	}

} public class Flats extends ArrayList<Flat> {

	/**
	 * Make sure when adding fields to add them in write to Parcel as well
	 */
	private static final long serialVersionUID = 4642208262846389104L;

	public Flats() {}

	public Flats( int capacity ) {
		super( capacity );
	}
	
	public void parse(JSONObject obj) {
		try {
			Flat item;
			JSONObject resultList = obj.getJSONObject("resultlist.resultlist");
			JSONArray resultEntries = resultList
					.optJSONArray("resultlistEntries");
			if (resultEntries != null && resultEntries.length() > 0) {
				JSONObject flatsObj = resultEntries.getJSONObject(0);
				JSONArray resultEntry = flatsObj.optJSONArray("resultlistEntry");
				if(resultEntry == null){
					JSONObject flatObj = flatsObj.optJSONObject("resultlistEntry");
					if ( flatObj != null) {
						item = new Flat(flatObj);
						add(item);
						if ( flatObj.has("distance") )
							Log.d( Const.LOG_TAG, "Parsed 1 flat. Max distance: " + flatObj.get( "distance" ) );
					}
				} else {
					if (resultEntries != null && resultEntry != null) {
						double maxDistance = 0;
						for (int i = 0; i < resultEntry.length(); i++) {
							JSONObject flatObj = resultEntry.getJSONObject(i);
							item = new Flat(flatObj);
							add(item);
							if ( flatObj.has("distance") ) {
								double dist = flatObj.getDouble("distance");
								if ( dist > maxDistance )
									maxDistance = dist;
							}
						}
						Log.d( Const.LOG_TAG, "Parsed " + resultEntry.length() + " flats. Max distance: " + maxDistance );
					}
				}
			}
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
} public class ImmopolyUser extends User {

	public static final String sPREF_USER = "user";
	public static final String sPREF_TOKEN = "user_token";

	private String mUserToken;
	private String mUserName;
	private String mEmail;
	private String mTwitter;
	private double mBalance;
	private List<ImmopolyHistory> mUserHistory;
	private Flats flats;
	private double sLastProvision;
	private double sLastRent;
	private static ImmopolyUser sInstance = null;

	private List<ImmopolyBadge> badges;

	private List<ImmopolyActionItem> actionItems;

	private int maxExposes;

	
// private static long mTimeUpdated = -1;

	private ImmopolyUser() {
		mUserHistory = new ArrayList<ImmopolyHistory>();
		badges = new ArrayList<ImmopolyBadge>();
		actionItems = new ArrayList<ImmopolyActionItem>();
		flats = new Flats();
	}

	@Override
	public double getBalance() {
		return mBalance;
	}

	/**
	 * 
	 * @param context
	 * @return
	 * @deprecated was soll der schmarn hier? fragt den USerDataManager nach dem status
	 */
	public String readToken(Context context) {
		if (mUserToken == null || mUserToken.length() == 0) {
			SharedPreferences shared = context.getSharedPreferences(sPREF_USER,
					0);
			String userToken = shared.getString(sPREF_TOKEN, "");
			mUserToken = userToken;
		}
		return mUserToken;
	}

	@Override
	public String getToken() {
		return mUserToken;
	}

	@Override
	public String getUserName() {
		return mUserName;
	}

	@Override
	public void setBalance(double balance) {
		mBalance = balance;
	}

	@Override
	public void setToken(String token) {
		mUserToken = token;
	}

	@Override
	public void setUsername(String username) {
		mUserName = username;
	}

	@Override
	public JSONObject toJSON() {
		return null;
	}

	public static ImmopolyUser getInstance() {
		if (sInstance == null) {
			sInstance = new ImmopolyUser();
		}
		return sInstance;
	}
	
	public static void resetInstance(){
		sInstance=null;
	}

	@Override
	public void setPortfolio(JSONObject portfolio) {
		if (portfolio != null) {
			// this.mTimeUpdated = Calendar.getInstance().getTimeInMillis();
			JSONArray results;
			JSONArray resultEntries;
			try {
				Flat item;
				results = portfolio.getJSONArray("resultlistEntries");
				resultEntries = results.getJSONArray(0);

				JSONObject expose;
				JSONObject realEstate;
				flats = new Flats();
				for (int i = 0; i < resultEntries.length(); i++) {
					item = new Flat();
					expose = resultEntries.getJSONObject(i).getJSONObject(
							"expose.expose");
					realEstate = expose.getJSONObject("realEstate");
					item.priceValue = realEstate.optString("baseRent");
					try {
						double price = Double.parseDouble(item.priceValue);
						item.priceValue = Integer.toString( (int) Math.round(price) );
					} catch (Exception e) {} 
					item.name = realEstate.optString("title");
					item.uid = realEstate.optInt("@id");
					item.lat = realEstate.getJSONObject("address")
							.getJSONObject("wgs84Coordinate")
							.optDouble("latitude");
					item.lng = realEstate.getJSONObject("address")
							.getJSONObject("wgs84Coordinate")
							.optDouble("longitude");
					item.takeoverDate  = realEstate.optLong("overtakeDate");
					item.takeoverTries = realEstate.optInt("overtakeTries");
					item.numRooms      = realEstate.optInt("numberOfRooms");
					item.livingSpace   = realEstate.optInt("livingSpace");
					
					if (realEstate.has("titlePicture")) {
						JSONObject objPicture = realEstate.getJSONObject("titlePicture");
						if (objPicture.has("urls") && objPicture.getJSONArray("urls").length() > 0) {
							JSONObject urls = objPicture.getJSONArray("urls").getJSONObject(0).getJSONObject("url");
							if ( urls != null )
							item.titlePictureSmall = urls.optString("@href");
						}
					}
					item.owned         = true;
					flats.add(item);
				}
			} catch (JSONException e) {
				Log.e( Const.LOG_TAG, "Exception while parsing portfolio: ", e );
			}
		}
	}
	
	public Flats getPortfolio() {
		return flats;
	}
	

	@Override
	public History instantiateHistory(JSONObject o) {
		return new ImmopolyHistory(o);
	}

	@Override
	public void setHistory(List<History> history) {
		mUserHistory.clear();
		for (History history2 : history) {
			mUserHistory.add((ImmopolyHistory) history2);
		}

	}

	public List<ImmopolyHistory> getHistory() {
		return mUserHistory;
	}

	@Override
	public void setLastProvision(double lastProvision) {
		sLastProvision = lastProvision;
	}

	@Override
	public void setLastRent(double lastRent) {
		sLastRent = lastRent;
	}

	public double getLastProvision() {
		return sLastProvision;
	}

	public double getLastRent() {
		return sLastRent;
	}

	public String getEmail() {
		return mEmail;
	}

	public String getTwitter() {
		return mTwitter;
	}

	public void setEmail(String email) {
		mEmail = email;
	}

	public void setTwitter(String twitter) {
		mTwitter = twitter;
	}

	public List<ImmopolyBadge> getBadges() {
		return badges;
	}

	@Override
	public Badge instantiateBadge(JSONObject o) {
		return new ImmopolyBadge(o);
	}

	@Override
	public void setBadges(List<Badge> badges) {
		this.badges.clear();
		for (Badge badge: badges) {
			this.badges.add((ImmopolyBadge) badge);
		}

	}

	public List<ImmopolyActionItem> getActionItems() {
		return actionItems;
	}

	public boolean hasActionItemWithAmount() {
		if (null == actionItems)
			return false;
		for (ImmopolyActionItem actionItem : actionItems) {
			if (actionItem.getAmount() > 0)
				return true;
		}
		return false;
	}

	@Override
	public ActionItem instantiateActionItem(JSONObject o) {
		return new ImmopolyActionItem(o);
	}

	@Override
	public void setActionItems(List<ActionItem> actionItems) {
		this.actionItems.clear();
		for (ActionItem actionItem : actionItems) {
			this.actionItems.add((ImmopolyActionItem) actionItem);
		}

	}

	@Override
	public void setMaxExposes(int maxExposes) {
		this.maxExposes = maxExposes;
	}

	public int getMaxExposes() {
		return maxExposes;
	}
	
	@Override
	public void setNumExposes(int numExposes) {
		// numExposes == flats.size() !
	}
	
	public void removeActionItem(int type) {
		for (ImmopolyActionItem item : actionItems) {
			if (item.getType() == type) {
				item.removeAmount(1);
			}
		}
		UserDataManager.instance.fireUsedDataChanged();
	}
} public class FreeFlatsTask extends AsyncTask<Flats, Void, Flats> {

	@Override
	protected Flats doInBackground(Flats... params) {
		Flats flats = params[0];
		JSONArray jsonArray = new JSONArray();
		if (flats != null) {
			for (Flat f : flats) {
				jsonArray.put(f.uid);
			}
			try {
				JSONObject obj = new JSONObject();
				obj.put("exposes", jsonArray);
				obj.put("token", ImmopolyUser.getInstance().getToken());
				obj.put("actiontype", ActionItem.TYPE_ACTION_FREEEXPOSES);
				JSONArray flatsArray = WebHelper.postFlatIdsHttpData(WebHelper.SERVER_URL_PREFIX + "/user/action", obj);
				int l = flatsArray.length();
				for (Flat f : flats) {
					for (int i = 0; i < l; i++) {
						if (f.uid == flatsArray.getInt(i)) {
							f.visible = true;
							break;
						} else {
							f.visible = false;
						}
					}
				}
				ImmopolyUser.getInstance().removeActionItem(ActionItem.TYPE_ACTION_FREEEXPOSES);
				return flats;
			} catch (JSONException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

} public class ImmoscoutPlacesOverlay extends ItemizedOverlay<OverlayItem> {

	private static final float MIN_INTERSECTION_AMOUNT = 0.15f;
	private static int MIN_INTERSECTION_AREA;

	private final ArrayList<ClusterItem> tmpItems = new ArrayList<ClusterItem>();
	private MapView mMapView;
	private Fragment mMapFragment;

	public static Rect markerBounds;	// TODO public static
	private Flats mFlats;
	private int prevLatProjection = -1;
	private TeaserView bubble;
	private boolean isPortfolio;
	private GestureDetector gestureDetector;
	private long itemTapTime;

	static Drawable mapMarkerIcon;
	static Drawable mapMarkerIcon_old;
	static Drawable mapMarkerIcon_new;
	static Drawable mapMarkerIcon_owned;
	static Drawable mapMarkerIcon_cluster;

	public ImmoscoutPlacesOverlay(Fragment fragment, MapView mapView, LayoutInflater inflator, boolean isPortfolio) {
		super(boundCenter(fragment.getResources().getDrawable(R.drawable.map_marker_icon)));
		mMapView = mapView;
		this.isPortfolio = isPortfolio;
		mMapFragment = fragment;
		Resources resources = fragment.getResources();
		mapMarkerIcon = boundCenter(resources.getDrawable(R.drawable.map_marker_icon));
		mapMarkerIcon_new = boundCenter(resources.getDrawable(R.drawable.map_marker_icon_new));
		mapMarkerIcon_old = boundCenter(resources.getDrawable(R.drawable.map_marker_icon_old));
		mapMarkerIcon_owned = boundCenter(resources.getDrawable(R.drawable.map_marker_property_icon));
		mapMarkerIcon_cluster = boundCenter(resources.getDrawable(R.drawable.map_marker_icon_cluster));

		markerBounds = mapMarkerIcon.getBounds();

		MIN_INTERSECTION_AREA = (int) (markerBounds.width() * markerBounds.height() * MIN_INTERSECTION_AMOUNT);

		ClusterMarker.init(resources.getDisplayMetrics(), mapMarkerIcon.getIntrinsicHeight());
		gestureDetector = new GestureDetector( new GestureDetector.SimpleOnGestureListener() {
			public boolean onDoubleTap(MotionEvent e) {
				if ( System.currentTimeMillis() - itemTapTime > 500 ) // hack to prevent zoom for double tap on item
					mMapView.getController().zoomInFixing((int) e.getX(), (int) e.getY());
				return super.onDoubleTap(e);
			}
		});
	}

	public void setFlats(Flats mFlats) {
		this.mFlats = mFlats;
		clusterize();
	}

	public Rect getMarkerBounds() {
		return markerBounds;
	}
	
	@Override
	protected OverlayItem createItem(int i) {
		return tmpItems.get(i).getOverlayItem();
	}

	@Override
	public int size() {
		return tmpItems.size();
	}

	@Override
	protected boolean onTap(int index) {
		if ( bubble != null )
			bubble.detach();
		if ( tmpItems == null || index >= tmpItems.size()) {
			if (mMapFragment instanceof MapFragment) // show wind rose (hack)
				((MapFragment) mMapFragment).showCompass();
			return false;
		}
		final ClusterItem item = tmpItems.get(index);
		final RelativeLayout.LayoutParams relLayoutParams = new RelativeLayout.LayoutParams(
				LayoutParams.FILL_PARENT, 210 );
		relLayoutParams.addRule( RelativeLayout.BELOW, R.id.header );
		bubble = new TeaserView( mMapFragment, mMapView, item.flats, isPortfolio );
		if (mMapFragment instanceof MapFragment) // hide wind rose (hack)
			((MapFragment) mMapFragment).hideCompass();
		itemTapTime = System.currentTimeMillis(); // hack to prevent zoom for double tap on item
		return true;
	}

	@Override
	public boolean onTap(GeoPoint p, MapView mapView) {
		if (!super.onTap(p, mapView)) {
			hideBubble();
			mMapView.setBuiltInZoomControls(true);
			mMapView.getZoomButtonsController().setVisible(true);
			return true;
		}
		return false;
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event, MapView mapView) {
		return gestureDetector.onTouchEvent(event);
	}

	
	// TODO we're doing a lot of strange things here and draw() doesnt feel comfortable with that off-purpose stuff 
	public void draw(Canvas canvas, MapView mapView, boolean shadow) {
		// test for map movement. Remove Balloon evtly. 
		if ( bubble != null && bubble.animationDone ) {
			Point ntp = bubble.mapIconPos;	// screen pos of selected icon as the bubble prefers 
			Point p   = new Point();		// current screen pos of selected icon 
			mMapView.getProjection().toPixels( bubble.mapIconGeoPoint, p );
			if ( Math.abs( ntp.x - p.x) > 20 || Math.abs( ntp.y - p.y) > 20 ) {
				hideBubble();
			}
		}
		// test for map zoom. Evtly do clusterizing 
		int latProjection = (mapView.getProjection().fromPixels( 200, 200 ).getLatitudeE6()
						   - mapView.getProjection().fromPixels( 0, 0 ).getLatitudeE6() );
		if (Math.abs(latProjection - prevLatProjection) > 10) {
			prevLatProjection = latProjection;
			clusterize();
		}
		super.draw(canvas, mapView, shadow);
	}

	/**
	 * clusterize flats based on their supposed marker position
	 */
	public void clusterize() {
		if (mFlats == null)
			return;
		final Flats flats = mFlats;
		final ArrayList<ClusterItem> items = tmpItems;
		final Projection projection = mMapView.getProjection();
		final Point screenPos = new Point();
		items.clear();

		// create tmp items with flat, geopoint & screenBounds
		for (int i = 0; i < flats.size(); i++) {
			final Flat flat = flats.get(i);
			if (flat.lat == 0 && flat.lng == 0 || !flat.visible)
				continue;
			Rect itemBounds = new Rect(markerBounds);
			GeoPoint point = new GeoPoint((int) (flat.lat * 1E6), (int) (flat.lng * 1E6));
			projection.toPixels(point, screenPos);
			itemBounds.offset(screenPos.x, screenPos.y);
			items.add(new ClusterItem(flat, point, itemBounds));
		}

		// join ClusterItems if their markers would intersect
		ArrayList<ClusterItem> newItems = new ArrayList<ClusterItem>();
		final Rect intersection = new Rect();
		final int size = items.size();
		for (int i = 0; i < size; i++) {
			final ClusterItem item = (ClusterItem) items.get(i);
			if (item.consumed)
				continue;
			for (int j = i + 1; j < size; j++) {
				final ClusterItem otherItem = (ClusterItem) items.get(j);
				if (!otherItem.consumed
						&& intersection.setIntersect(item.screenBounds, otherItem.screenBounds)
						&& intersection.width() * intersection.height() >= MIN_INTERSECTION_AREA)
					item.add(otherItem);
			}
			newItems.add(item);
		}
		tmpItems.clear();
		tmpItems.addAll(newItems);

		// see http://groups.google.com/group/android-developers/browse_thread/thread/38b11314e34714c3
		setLastFocusedIndex(-1);
		populate();
	}
	
	public void hideBubble() {
		if ( bubble != null ) {
			bubble.detach();
			bubble = null;
			if (mMapFragment instanceof MapFragment) // show wind rose (hack)
				((MapFragment) mMapFragment).showCompass();
		}
	}

	public void updateBubble() {
		if ( bubble != null )
			bubble.refreshContent();
	}

	/*
	 * Class used while clustering.
	 */
	private final class ClusterItem { // TODO join with ImmoPlaceOverlayItem or something
		public boolean consumed;
		long latSum, lonSum;
		Rect screenBounds;
		Flats flats = new Flats();
		GeoPoint point;
		OverlayItem overlayItem;

		public ClusterItem(Flat flat, GeoPoint point, Rect screenBounds) {
			this.screenBounds = screenBounds;
			latSum = point.getLatitudeE6();
			lonSum = point.getLongitudeE6();
			flats.add(flat);
		}

		public void add(ClusterItem item) {
			flats.addAll(item.flats);
			latSum += item.latSum;
			lonSum += item.lonSum;
			item.consumed = true;
		}

		OverlayItem getOverlayItem() {
			if ( overlayItem != null )
				return overlayItem;

			int size = flats.size();

//			point = new GeoPoint( (int) (latSum / size), (int) (lonSum / size) );
			point  = new GeoPoint( (int) (flats.get(0).lat * 1E6), (int) (flats.get(0).lng * 1E6) );

			overlayItem = new ImmoPlaceOverlayItem( point, flats );
			if (size == 1) {
				Flat f = flats.get(0);
				if (f.owned)
					overlayItem.setMarker( boundCenter( new SingleFlatMarker( mapMarkerIcon_owned ) ));
				else if (f.age == Flat.AGE_NEW)
					overlayItem.setMarker( boundCenter( new SingleFlatMarker( mapMarkerIcon_new )));
				else if (f.age == Flat.AGE_OLD)
					overlayItem.setMarker( boundCenter( new SingleFlatMarker( mapMarkerIcon_old )));
				else
					overlayItem.setMarker( boundCenter( new SingleFlatMarker( mapMarkerIcon )));
			} else
				overlayItem.setMarker( boundCenter( new ClusterMarker( flats, mapMarkerIcon_cluster ) ) );
			return overlayItem;
		}
	}

} public class MyPositionOverlay extends ItemizedOverlay<PlaceOverlayItem> {

	private PlaceOverlayItem overlayItem = null;

	public MyPositionOverlay(Drawable defaultMarker) {
		super(defaultMarker);
	}

	public MyPositionOverlay(Drawable defaultMarker, Context context,
			MapView map, LayoutInflater inflator) {
		super(defaultMarker);
	}

	@Override
	protected PlaceOverlayItem createItem(int i) {
		boundCenterBottom(overlayItem.getMarker(0));
		return overlayItem;
	}

	@Override
	public int size() {
		if (null == overlayItem)
			return 0;
		return 1;
	}

	public void setPlaceOverlayItem(PlaceOverlayItem overlayItem) {
		this.overlayItem = overlayItem;
		populate();
	}

	public void clear() {
		overlayItem = null;
	}
	
	@Override
	public void draw(Canvas canvas, MapView mapView, boolean shadow) {
		if ( ! shadow )
			super.draw(canvas, mapView, shadow);
	}
} public class PlaceOverlayItem extends OverlayItem {

	public Flat flat;


	public PlaceOverlayItem(GeoPoint point, Flat f) {
		super(point, f.name, f.locationNote);
		flat = f;
	}

	public PlaceOverlayItem(GeoPoint point, String string, String string2) {
		super(point, string, string2);
	}

	
}
import java.io.IOException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.immopoly.android.R;
import org.immopoly.android.api.ApiResultReciever.Receiver;
import org.immopoly.android.api.IS24ApiService;
import org.immopoly.android.api.ReceiverState;
import org.immopoly.android.app.ImmopolyActivity;
import org.immopoly.android.app.UserDataListener;
import org.immopoly.android.app.UserDataManager;
import org.immopoly.android.constants.Const;
import org.immopoly.android.helper.HudPopupHelper;
import org.immopoly.android.helper.LocationHelper;
import org.immopoly.android.helper.OnTrackingEventListener;
import org.immopoly.android.helper.TrackingManager;
import org.immopoly.android.model.Flat;
import org.immopoly.android.model.Flats;
import org.immopoly.android.model.ImmopolyUser;
import org.immopoly.android.tasks.FreeFlatsTask;
import org.immopoly.android.widget.ImmoscoutPlacesOverlay;
import org.immopoly.android.widget.MyPositionOverlay;
import org.immopoly.android.widget.PlaceOverlayItem;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.location.Address;
import android.location.Geocoder;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ZoomControls;
import com.google.android.apps.analytics.GoogleAnalyticsTracker;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
package org.immopoly.android.fragments;





public class MapFragment extends Fragment implements Receiver, OnMapItemClickedListener, UserDataListener {

	public static final String TAG = "Immopoly";

	private MapController mMapController;
	private List<Overlay> mMapOverlays;
	private PlaceOverlayItem myLocationOverlayItem;
	private MapView mMapView;
	private ImmoscoutPlacesOverlay overlays;
	private Flats mFlats;

	public static final int RELOAD_DELAY_MILLIS = 800;
	ReceiverState mState;

	private MyPositionOverlay myLocationOverlays;
	private int mNumberGeoCodeTry;
	private HudPopupHelper mHudPopup;

	private Button hudText;
	private ImageButton mapButton;

	private OnMapItemClickedListener mOnMapItemClickedListener;
	private OnTrackingEventListener mEventListener;

	private ProgressBar mProgressIndicator;
	private ImageView mCompassButton;

	private View mSplashscreen;

	private View mActionItemFreeFlats;

	private ImageButton itemsButton;

	private GoogleAnalyticsTracker mTracker;

	public OnMapItemClickedListener getOnMapItemClickedListener() {
		return mOnMapItemClickedListener;
	}

	// @Override
	// public void onHudAction(View view) {
	// switch (view.getId()) {
	// case R.id.hud_map:
	// // hud map
	// // already there
	// LocationHelper.getLastLocation(getActivity());
	// break;
	// case R.id.hud_portfolio:
	// startActivity(new Intent(getActivity(), DashboardActivity.class));
	// break;
	// case R.id.hud_profile:
	// startActivity(new Intent(getActivity(), DashboardActivity.class));
	// break;
	// case R.id.hud_text:
	// // Toast.makeText(this, ImmopolyUser.getInstance().flats.toString(),
	// // Toast.LENGTH_LONG);
	// if (mHudPopup != null) {
	// mHudPopup.show(getActivity().findViewById(R.id.hud_text), -200, -60);
	// }
	// break;
	// default:
	// break;
	// }
	// }

	@Override
	public void onAttach(Activity activity) {
		super.onAttach(activity);
		try {
			mOnMapItemClickedListener = (OnMapItemClickedListener) activity;
		} catch (ClassCastException e) {
			throw new ClassCastException(activity.toString() + " must implement OnMapItemClickedListener");
		}
		try {
			mEventListener = (OnTrackingEventListener) activity;
		} catch (ClassCastException e) {
			throw new ClassCastException(activity.toString() + " must implement OnTrackingEventListener");
		}
	}

	@Override
	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		setRetainInstance(true);
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		mTracker = GoogleAnalyticsTracker.getInstance();
		// Start the tracker in manual dispatch mode...
		mTracker.startNewSession(TrackingManager.UA_ACCOUNT,
				Const.ANALYTICS_INTERVAL, getActivity().getApplicationContext());