/* 
 * Copyright 2013 by AVM GmbH <info@avm.de>
 *
 * This software contains free software; you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License ("License") as 
 * published by the Free Software Foundation  (version 3 of the License). 
 * This software is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the copy of the 
 * License you received along with this software for more details.
 */

package de.avm.android.fritzapp.gui;

import java.io.IOException;
import java.util.ArrayList;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.DialogInterface.OnClickListener;
import android.content.SharedPreferences.Editor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.preference.Preference.OnPreferenceClickListener;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import de.avm.android.fritzapp.R;
import de.avm.android.fritzapp.com.ComSettingsChecker;
import de.avm.android.fritzapp.com.DataHub;
import de.avm.android.fritzapp.com.DataHub.OnCompleteListener;
import de.avm.android.fritzapp.com.VoIPAutoConfigurator;
import de.avm.android.fritzapp.com.VoIPAutoConfigurator.Result;
import de.avm.android.fritzapp.com.discovery.BoxInfo;
import de.avm.android.fritzapp.service.BoxServiceConnection;
import de.avm.android.fritzapp.service.IBoxService;
import de.avm.android.fritzapp.sipua.ui.Sipdroid;
import de.avm.android.fritzapp.util.DeviceId;
import de.avm.android.fritzapp.util.PasswordBuilder;
import de.avm.android.fritzapp.util.ResourceHelper;
import de.avm.android.tr064.Tr064Boxinfo;
import de.avm.android.tr064.Tr064Capabilities;
import de.avm.android.tr064.exceptions.SslErrorException;
import de.avm.android.tr064.model.VoIPClientInfo;
import de.avm.android.tr064.model.VoIPInfoEx;

/* GUI for the settings of call route exceptions */
public class SettingsVoIPConfigActivity extends PreferenceActivity
{
	private static final String TAG = "SettingsVoIPConfigActivity";
	
	interface OnIsInSettingsListener
	{
		/**
		 * Callback to get result from isInSettings()
		 * 
		 * @param udn box the result is related to
		 * @param result the result
		 */
		void onIsInSettings(String udn, boolean result);
	}
	
	public static final String PREF_VOIPCLIENT_NAME = "sipname"; // not a pref any more

	public static final String EXTRA_AUTOFINISH = "de.avm.android.fritzapp.extra.AUTOFINISH";
	
	private static final String SAVED_LIST = "voipclients";
	private static final String SAVED_BOXAVAIL = "box";
	private static final String SAVED_LOADING = "loading";
	private static final String SAVED_NEWSEL = "sel";
	
	private static final int NEW_PASSWORD_LENGTH = 8;

	private ListView mListView = null;

	private boolean mAddNewOnEmptyList = true;
	private boolean mBoxAvailable = false;

	private static DataHub mFritzBox = new DataHub();
	private DeviceId mDeviceId = null;
	private VoIPClientInfo mNewSel = null;
	private LoadTask mLoaderTask = null;
	private Handler mHandler = new Handler();
	private WaitDialog mWaitDialog = null;
	private boolean mNeedReload = false; // do not cancel, list has to be updated
	private boolean mInitiallyBlank = false;

	
	private ArrayList<VoIPClientInfo> mList = null;
	
	// cached infos
	private static String[] mCachedInfoUdn = new String[1];
	private static boolean mCachedIsInSettings = false;

	static
	{
		mCachedInfoUdn[0] = null;
	}
	
	public static void updateCachedInfo(String boxUdn, boolean isInSettings)
	{
		synchronized(mCachedInfoUdn)
		{
			mCachedInfoUdn[0] = boxUdn;
			mCachedIsInSettings = isInSettings;
		}									
	}
	
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		mDeviceId = DeviceId.create(this);
		
		setContentView(R.layout.settings);
		mListView = (ListView)findViewById(android.R.id.list);
		mListView.setSelector(R.drawable.list_selector_background);

		// Title and description
		ResourceHelper.setAltTitleSymbol(this);
		ResourceHelper.setTitle(this, R.string.settings_voipconfig);
    	TextView description = (TextView)findViewById(R.id.Description);
    	description.setText(R.string.settings_voipconfig2);
    	description.setVisibility(View.VISIBLE);

		if (savedInstanceState != null)
		{
			mNewSel = savedInstanceState.getParcelable(SAVED_NEWSEL);

			// restore list
			boolean loading = savedInstanceState.getBoolean(SAVED_LOADING, false);
			if (!loading)
				mList = savedInstanceState.getParcelableArrayList(SAVED_LIST);
			if (loading || (mList == null))
			{
				mBoxAvailable = false; // force reload
				mInitiallyBlank = true;
			}
			else
				mBoxAvailable = savedInstanceState.getBoolean(SAVED_BOXAVAIL, false);
			mAddNewOnEmptyList = false;
		}
		else mInitiallyBlank = true;

		update();
	}

	@Override
	public void onDestroy()
	{
		super.onDestroy();
		dismissWait();
		mLoaderTask = null;
	}

	@Override
	protected void onSaveInstanceState(Bundle outState)
	{
		if (mList != null)
		{
			synchronized(mList)
			{
				if (mList.size() > 0)
					outState.putParcelableArrayList(SAVED_LIST, mList);
			}
		}
		outState.putBoolean(SAVED_BOXAVAIL, mBoxAvailable);
		boolean loadingList = (mLoaderTask != null) &&
				mLoaderTask.getClass().equals(LoadListTask.class); 
		outState.putBoolean(SAVED_LOADING, loadingList || mNeedReload);
		if (mNewSel != null) outState.putParcelable(SAVED_NEWSEL, mNewSel);
	}
	
	@Override
	protected void onPause()
	{
		super.onPause();
		mBoxServiceConnection.unbindService();
	}
	
	@Override
	protected void onResume()
	{
		super.onResume();
		if (!mBoxServiceConnection.bindService(getApplicationContext()))
			Log.w(TAG, "Failed to bind to BoxService.");
		onStatusChanged();
	}	
	
	private BoxServiceConnection mBoxServiceConnection = new BoxServiceConnection()
	{
		public void onComStatusChanged()
		{
			runOnUiThread(new Runnable()
			{
				public void run()
				{
					onStatusChanged();
				}
			});
		}
	};

	/**
	 * Finishes activity if requested by caller
	 * 
	 * @return true if activity is finishing
	 */
	private boolean autoFinish()
	{
		Intent intent = getIntent();
		if (intent != null && intent.getBooleanExtra(EXTRA_AUTOFINISH, false))
		{
			finish();
			return true;
		}
		return false;
	}
	
	private void onStatusChanged()
	{
		boolean old = mBoxAvailable;
		Tr064Capabilities capabilities = ComSettingsChecker.getTr064Capabilities();
		mBoxAvailable = (capabilities != null) &&
				capabilities.has(Tr064Capabilities.Capability.VOIP_CONF); 
		if (old != mBoxAvailable) loadList(); // connection changed
	}
	
	/**
	 * Builds preference screen (actions and list)
	 */
	private void update()
	{
		PreferenceScreen root = getPreferenceManager().createPreferenceScreen(this);
		
		// VoIP client list
		PreferenceCategory group = new PreferenceCategory(this);
		group.setTitle(getString(R.string.pref_cat_voipclients));
		root.addPreference(group);

		// with VOIP_CONF_ID hide clients with ID 
		Tr064Capabilities capabilities = ComSettingsChecker.getTr064Capabilities();
		boolean autoConf = (capabilities != null) &&
				capabilities.has(Tr064Capabilities.Capability.VOIP_CONF_ID);
		
		if (mList != null)
		{
			synchronized(mList)
			{
				boolean addAutoItem = autoConf;
				for(VoIPClientInfo info : mList)
				{
					DeviceId id = DeviceId.parse(info.getId());
					boolean itsMyId = (id == null) ? false : mDeviceId.equals(id);
					if (!autoConf || (id == null) || itsMyId)
					{
						VoIPClientListItem clientPref = new VoIPClientListItem(this,
								info, autoConf && itsMyId);
						if (autoConf && itsMyId)
						{
							addAutoItem = false;
							clientPref.setOnPreferenceClickListener(
									new OnPreferenceClickListener()
							{
								public boolean onPreferenceClick(Preference preference)
								{
									switchToAuto(((VoIPClientListItem)preference).getInfo()
											.getUsername());
									return true;
								}
							});
						}
						else
						{
							clientPref.setOnPreferenceClickListener(
									new OnPreferenceClickListener()
							{
								public boolean onPreferenceClick(Preference preference)
								{
									mNewSel = ((VoIPClientListItem)preference).getInfo();
									showDialog(DIALOG_SEL);
									return true;
								}
							});
						}
						group.addPreference(clientPref);
					}
				}
				if (addAutoItem)
				{
					VoIPClientListItem clientPref = new VoIPClientListItem(this, null, true);
					clientPref.setOnPreferenceClickListener(new OnPreferenceClickListener()
					{
						public boolean onPreferenceClick(Preference preference)
						{
							addNewAuto();
							return true;
						}
					});
					group.addPreference(clientPref);
				}
			}		

			if (!autoConf)
			{
				// add command
				Preference newPref = new Preference(this);
				newPref.setOrder(VoIPClientListItem.ORDER_APPEND);
				newPref.setTitle(getString(R.string.settings_new_voipclient));
				newPref.setSummary(getString(R.string.settings_new_voipclient2));
				newPref.setPersistent(false);
				newPref.setOnPreferenceClickListener(new OnPreferenceClickListener()
				{
					public boolean onPreferenceClick(Preference preference)
					{
						if ((mList != null) && (mList.size() >= DataHub.MAX_VOIPCLIENTS))
						{
				    		TextDialog.createOk(SettingsVoIPConfigActivity.this,
				    				getString(R.string.voipclient_max_count),
				    				android.R.drawable.ic_dialog_alert).show();
						}
						else addNew();
						return true;
					}
				});
				group.addPreference(newPref);
			}
		}

		root.setPersistent(false);
		root.bind(mListView);
		mListView.setAdapter(root.getRootAdapter());
		setPreferenceScreen(root);
		
		updateSelection();
	}
	
	private void updateSelection()
	{
		String selUsername;
		boolean valid = false;
		BoxInfo boxInfo = ComSettingsChecker.getBoxInfo();
		if (boxInfo != null)
		{
			selUsername = boxInfo.getVoIPName();
			valid = boxInfo.hasVoipCredentials();
		}
		else selUsername = "";

		ListAdapter adapter = mListView.getAdapter();
		for (int ii = 0; (adapter != null) && (ii < adapter.getCount()); ii++)
		{
			Object item = adapter.getItem(ii);
			if ((item != null) &&
					item.getClass().equals(VoIPClientListItem.class))
			{
				VoIPClientListItem clientPref =(VoIPClientListItem)item;
				VoIPClientInfo info = clientPref.getInfo();
				if (valid && (info != null) &&
						selUsername.equals(info.getUsername()))
				{
					clientPref.setChecked(true);
					if (!info.getName().equals(boxInfo.getVoIPTitle()))
					{
						// update saved title
						boxInfo.setVoIPTitle(info.getName());
						ComSettingsChecker.SaveBoxInfo(this);
					}
				}
				else clientPref.setChecked(false);
			}
		}
	}
	
	private void loadList()
	{
		if (mLoaderTask == null)
		{
			showWait();
			mLoaderTask = (LoadTask)new LoadListTask().execute();
		}
	}
	
	private void addNew()
	{
		if ((mLoaderTask == null) && (mList != null))
		{
			// find unique name
			String newName = "";
			for (int ii = 1; ii <= DataHub.MAX_VOIPCLIENTS; ii++)
			{
				String name = String.format(getString(
						R.string.settings_new_voipclient_name_fmt),
						(ii > 1) ? Integer.toString(ii) : "").trim();
				boolean found = false;
				synchronized(mList)
				{
					for(VoIPClientInfo info : mList)
						if (name.equals(info.getName()))
						{
							found = true;
							break;
						}
				}
				if (!found)
				{
					newName = name;
					break;
				}
			}

			if (newName.length() > 0)
			{
				// begin adding new VoIP client
				mNeedReload = true;
				showWait();
				mLoaderTask = (LoadTask)new AddTask().execute(
						new String[] {newName, mDeviceId.toString()});
			}
		}
	}

	private void switchToAuto(String username)
	{
		BoxInfo boxInfo = ComSettingsChecker.getBoxInfo();
		if ((mLoaderTask == null) && (boxInfo != null))
		{
			boxInfo.setVoipCredentials("", "");
			boxInfo.setVoIPTitle("");
			ComSettingsChecker.SaveBoxInfo(this);
			onChanged();

			boxInfo.setVoipCredentials(username, username);
			mNeedReload = true;
			showWait();
			mLoaderTask = (LoadTask)new AutoConfigTask().execute();
		}
	}
	
	private void addNewAuto()
	{
		BoxInfo boxInfo = ComSettingsChecker.getBoxInfo();
		if ((mLoaderTask == null) && (boxInfo != null))
		{
			boxInfo.setVoipCredentials("", "");
			boxInfo.setVoIPTitle("");
			ComSettingsChecker.SaveBoxInfo(this);
			onChanged();

			mNeedReload = true;
			showWait();
			mLoaderTask = (LoadTask)new AutoConfigTask().execute();
		}
	}

	private void onListLoaded(LoadTask task, ArrayList<VoIPClientInfo> list)
	{
		if (mLoaderTask == task)
		{
			dismissWait();
			mLoaderTask = null;
			mInitiallyBlank = false;

			if (mList != null)
			{
				synchronized(mList)
				{
					mList.clear();
					mList.addAll(list);
				}
			}
			else mList = list;

			// update cached info
			BoxInfo boxInfo = ComSettingsChecker.getBoxInfo();
			if (boxInfo != null)
			{
				boolean isInSettings = false;
				for (VoIPClientInfo info : list)
					if (TextUtils.isEmpty(info.getId())) isInSettings = true;
				updateCachedInfo(boxInfo.getUdn(), isInSettings);
			}

			update();

			// if nothing loaded initially, ask for adding a new one
			try
			{
				if (mList.isEmpty() && mAddNewOnEmptyList)
				{
					TextDialog.create(this,
							getString(R.string.settings_new_voipclient),
							getString(R.string.ask_new_voipclient_autoadd),
							TextDialog.DEFAULT_EDIT_ICON)
							.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener()
							{
								public void onClick(DialogInterface dialogInterface, int id)
								{
									addNew();
								}
							})
							.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener()
							{
								public void onClick(DialogInterface dialogInterface, int id)
								{
								}
							}).show();
				}
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
			mNeedReload = false;
			mAddNewOnEmptyList = false;
		}
	}

	private void onAdded(AddTask task, VoIPClientInfo info, String password)
	{
		if (mLoaderTask == task)
		{
			// select it
			BoxInfo boxInfo = ComSettingsChecker.getBoxInfo();
			if (boxInfo != null)
			{
				boxInfo.setVoipCredentials(info.getUsername(), password);
				boxInfo.setVoIPTitle(info.getName());
				ComSettingsChecker.SaveBoxInfo(this);
				onChanged();
			}

			dismissWait();
			mLoaderTask = null;

			// tell user
			String message = String.format(
					getString(R.string.settings_new_voipclient2_done_fmt),
					info.getName(), password);
			try
			{
	    		TextDialog.create(this,
	    				TextDialog.getDefaultTitle(this), message)
	    				.setCancelable(false)
						.setPositiveButton(android.R.string.ok,
								new DialogInterface.OnClickListener()
						{
							public void onClick(DialogInterface dialog,
									int which)
							{
								if (!autoFinish())
								{
									// reload list
									showWait();
									mLoaderTask = (LoadTask)new LoadListTask()
											.execute();
								}
							}
						}).show();
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
	}

	private void onAutoConfig(LoadTask task)
	{
		if (mLoaderTask == task)
		{
			onChanged();
			mLoaderTask = (LoadTask)new LoadListTask().execute();
		}
	}
	
	private void onError(LoadTask task, String message)
	{
		if (mLoaderTask == task)
		{
			dismissWait();
			mLoaderTask = null;
		}
		mNeedReload = false;
		mAddNewOnEmptyList = false;
		mInitiallyBlank = false;
		try
		{
			TextDialog.createOk(this, message).show();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	private void onChanged()
	{
		IBoxService srv = mBoxServiceConnection.getService();
		if (srv != null) srv.reconnectSip();
	}

	private void showWait()
	{
		if (mWaitDialog == null)
		{
			if (mNeedReload)
			{
				// not cancelable
				mWaitDialog = WaitDialog.show(this, R.string.wait_dialog);
			}
			else
			{
				mWaitDialog = WaitDialog.show(this, R.string.wait_dialog,
						new DialogInterface.OnCancelListener()
				{
					public void onCancel(DialogInterface dialog)
					{
						if (!mNeedReload)
						{
							if (dialog == mWaitDialog)
							{
								// cancel pending load
								mWaitDialog = null;
								dialog.dismiss();
								mLoaderTask = null;
								
								// if first loading, close activity
								if (mInitiallyBlank)
									SettingsVoIPConfigActivity.this.finish();
							}
							else dialog.dismiss();
						}
					}
				});
			}
		}
	}
	
	private void dismissWait()
	{
		if (mWaitDialog != null)
		{
			mWaitDialog.dismiss();
			mWaitDialog = null;
		}
	}

	private interface LoadTask
	{
	}

	private class LoadListTask
			implements OnCompleteListener<VoIPClientInfo[]>, LoadTask, Runnable
	{
		protected ArrayList<VoIPClientInfo> mResult = null;
		private Exception mError = null;
		
		public LoadListTask execute()
		{
			mFritzBox.getVoIPConfClientsAsync(SettingsVoIPConfigActivity.this,
					(OnCompleteListener<VoIPClientInfo[]>)this);
			return this;
		}
		
		public void onComplete(VoIPClientInfo[] result, Exception error)
		{
			if (error == null)
			{
				mResult = new ArrayList<VoIPClientInfo>();
				if (result != null)
					for (VoIPClientInfo info : result) mResult.add(info);
			}
			else mError = error;
			mHandler.post(this);
		}

		public void run()
		{
			if (mResult == null)
			{
				if (SslErrorException.isSslError(mError))
				{
					onError(LoadListTask.this, SslErrorException.getDisplayMessage(
							SettingsVoIPConfigActivity.this, mError));
				}
				else
				{
					onError(LoadListTask.this, SettingsVoIPConfigActivity.this.
							getString(R.string.soap_tranfer_failed));
					if (IOException.class.isAssignableFrom(mError.getClass()))
					{
						IBoxService srv = mBoxServiceConnection.getService();
						if (srv != null) srv.reconnect();
					}
				}
			}
			else onListLoaded(LoadListTask.this, mResult);
		}
	}
	
	private class AddTask extends AsyncTask<String, Integer, VoIPClientInfo>
			implements LoadTask
	{
		private String mNewPassword = "";
		private Exception mError = null;
		
		@Override
		protected VoIPClientInfo doInBackground(String... params)
		{
			try
			{
				// create password
				VoIPInfoEx infoEx = mFritzBox
						.getVoIPConfInfoEx(SettingsVoIPConfigActivity.this);
				int len = (infoEx.getPasswordMinChar() > NEW_PASSWORD_LENGTH) ? 
						infoEx.getPasswordMinChar() : NEW_PASSWORD_LENGTH;
				if (len > infoEx.getPasswordMaxChar())
					len = infoEx.getPasswordMaxChar();
				mNewPassword = new PasswordBuilder()
						.setValidChars(infoEx.getPasswordAllowedChar())
						.setLength(len).create();
				
				// add one
				int index = mFritzBox.addVoIPConfClientInfo(
						SettingsVoIPConfigActivity.this, mNewPassword,
						params[0], params[1]);
				
				// reached MAX_VOIPCLIENTS?
				if (index < 0) return new VoIPClientInfo(index); 

				// load added
				return mFritzBox.getVoIPConfClientInfo(
						SettingsVoIPConfigActivity.this, index);
				
			}
			catch(Exception exp)
			{
				mError = exp;
				exp.printStackTrace();
				if (IOException.class.isAssignableFrom(exp.getClass()))
				{
					IBoxService srv = mBoxServiceConnection.getService();
					if (srv != null) srv.reconnect();
				}
				return null;
			}
		}		
		
		@Override
		protected void onPostExecute(VoIPClientInfo info)
		{
			super.onPostExecute(info);
			
			if (info == null)
			{
				if (SslErrorException.isSslError(mError))
					onError(this, SslErrorException.getDisplayMessage(
							SettingsVoIPConfigActivity.this, mError));
				else
					onError(this, SettingsVoIPConfigActivity.this.
							getString(R.string.soap_tranfer_failed));
			}
			else if (info.getIndex() < 0)
				onError(this, getString(R.string.voipclient_max_count));
			else
				onAdded(this, info, mNewPassword);
		}
	}
	
	private class AutoConfigTask
			implements VoIPAutoConfigurator.OnCompleteListener, LoadTask
	{
		private VoIPAutoConfigurator mTask = null;
		
		public AutoConfigTask execute()
		{
			if (mTask == null)
				mTask = VoIPAutoConfigurator.start(
						SettingsVoIPConfigActivity.this, this);
			return this;
		}

		public void onComplete(Result result, String errorMessage)
		{
			if (result == Result.SUCCESS)
				onAutoConfig(this);
			else if (TextUtils.isEmpty(errorMessage))
				onError(this, getString(R.string.soap_tranfer_failed));
			else
				onError(this, errorMessage);
			mTask = null;
		}
	}

	private static final int DIALOG_SEL = 1;

	@Override
	protected Dialog onCreateDialog(int id)
	{
		switch (id)
		{
			// select mNewUsername with password
			case DIALOG_SEL:
			{
				LayoutInflater inflater = (LayoutInflater)getSystemService(Context
						.LAYOUT_INFLATER_SERVICE);
				View layout = inflater.inflate(R.layout.password_dialog, null);
				((TextView)layout.findViewById(R.id.UserLabel)).setVisibility(View.GONE);
				((EditText)layout.findViewById(R.id.User)).setVisibility(View.GONE);
				((TextView)layout.findViewById(R.id.Warning)).setVisibility(View.GONE);
				final EditText password = (EditText)layout.findViewById(R.id.Password);
				
				AlertDialog.Builder builder = new AlertDialog.Builder(this);
				return builder.setView(layout)
						.setTitle(mNewSel.getName())
						.setInverseBackgroundForced(true)
						.setIcon(TextDialog.DEFAULT_EDIT_ICON)
						.setCancelable(false)
						.setPositiveButton(android.R.string.ok, new OnClickListener()
						{
							public void onClick(DialogInterface dialog, int which)
							{
								BoxInfo boxInfo = ComSettingsChecker.getBoxInfo();
								if ((boxInfo != null) && (mNewSel != null))
								{
									boxInfo.setVoipCredentials(mNewSel.getUsername(),
											password.getText().toString());
									boxInfo.setVoIPTitle(mNewSel.getName());
									ComSettingsChecker.SaveBoxInfo(
											SettingsVoIPConfigActivity.this);
									onChanged();
								}
								removeDialog(DIALOG_SEL);
								mNewSel = null;

								if (!autoFinish()) updateSelection();
							}
						})
						.setNegativeButton(android.R.string.cancel, new OnClickListener()
						{
							public void onClick(DialogInterface dialog, int which)
							{
								removeDialog(DIALOG_SEL);
								mNewSel = null;
								updateSelection();
							}
						})
						.create();
			}
		}
		
		return null;
	}
	
	/**
	 * Checks if activity should be reachable from settings
	 * listener is only called if a result has been fetched (box connected) 
	 *  
	 * @param context
	 * 			a valid context
	 * @param listener
	 * 			callback to get result
	 * @return cached result from last check or fixed result
	 */
	public static boolean isInSettings(Context context, final OnIsInSettingsListener listener)
	{
		boolean instantResult = false;
		
		final BoxInfo boxInfo = ComSettingsChecker.getBoxInfo();
		if ((listener != null) && (boxInfo != null))
		{
			Tr064Boxinfo tr064Info = boxInfo.getTr064Boxinfo();
			Tr064Capabilities capabilities = (tr064Info == null) ?
					Tr064Capabilities.EMPTY : tr064Info.getTr064Capabilities();
			if (capabilities.has(Tr064Capabilities.Capability.VOIP_CONF_ID))
			{
				mFritzBox.getVoIPConfClientsAsync(context,
						new OnCompleteListener<VoIPClientInfo[]>()
				{
					public void onComplete(VoIPClientInfo[] result, Exception error)
					{
						if ((error == null) && (result != null))
						{
							// preference visible if any manually configured clients listed
							for (VoIPClientInfo info : result)
								if (TextUtils.isEmpty(info.getId()))
								{
									listener.onIsInSettings(boxInfo.getUdn(), true);
									updateCachedInfo(boxInfo.getUdn(), true);
									return;
								}
						}
						listener.onIsInSettings(boxInfo.getUdn(), false);
						updateCachedInfo(boxInfo.getUdn(), false);
					}
				});
				
				synchronized(mCachedInfoUdn)
				{
					if (!TextUtils.isEmpty(mCachedInfoUdn[0]) &&
							mCachedInfoUdn[0].equals(boxInfo.getUdn()))
						instantResult = mCachedIsInSettings;
				}
			}
			else if (capabilities.has(Tr064Capabilities.Capability.VOIP_CONF))
			{
				instantResult = true;
			}
		}
		
		return instantResult;
	}

	/**
	 * Preparations on settings to do on app's start
	 * @param context context for reading and writing the settings
	 * @param firstRun true for first run after install
	 */
	public static void prepareSettings(Context context, boolean firstRun)
	{
		SharedPreferences prefs = PreferenceManager
				.getDefaultSharedPreferences(context); 
		Editor edit = prefs.edit();

		// remove old settings
		edit.remove(Sipdroid.PREF_SIPUSER);
		edit.remove(Sipdroid.PREF_SIPPASS);
		edit.remove(PREF_VOIPCLIENT_NAME);

		edit.commit();
	}
}
