/* 
 * 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.lang.reflect.Method;

import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.TextView;
import de.avm.android.fritzapp.R;
import de.avm.android.fritzapp.com.ComSettingsChecker;
import de.avm.android.fritzapp.com.discovery.BoxInfo;
import de.avm.android.fritzapp.service.BootCompletedReceiver;
import de.avm.android.fritzapp.service.BoxService;
import de.avm.android.fritzapp.service.BoxServiceConnection;
import de.avm.android.fritzapp.service.IBoxService;
import de.avm.android.fritzapp.service.IComErrorMessage;
import de.avm.android.fritzapp.sipua.UserAgent;
import de.avm.android.fritzapp.sipua.ui.Receiver;
import de.avm.android.fritzapp.sipua.ui.Sipdroid;
import de.avm.android.fritzapp.util.PackageManagerHelper;
import de.avm.android.fritzapp.util.PhoneNumberHelper;
import de.avm.android.fritzapp.util.ResourceHelper;

/*
 * Main GUI.
 */
public class FRITZApp extends Activity
{
	private static final String TAG = "FRITZApp";

	private static final int COLUMS_LANDSCAPE = 4;
	private static final int DIALOG_WIFIPOLICYHINT = 1;
	private static final int DIALOG_COMERROR = 2;
	private static final String PREF_WIFIPOLICYHINT = "wifi-policy";

	private static final String SAVE_DIALPAD_INPUT = "dialpad";
	private static final String SAVE_COMERROR = "comerror";

	private RecentCallsView mRecentCallsView = null;

	private GridView mGrid = null;
	private Dialpad mDialpad = null;
	private boolean mIsActive = false;
	private boolean mWifiPolicyHintDone = false;

	private Handler mHandler = new Handler();
	private StatusDisplayHandler mStatusDisplayHandler = null;
	
	private String mTamShortcut = null;
	private IComErrorMessage mShownComError = null;

	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		
		// send unhandled exceptions via email
//		ExceptionHandler.register(this, FRITZAppEMailExeptionHandler.class);

		setContentView(R.layout.main);
		ResourceHelper.setAltTitleSymbol(this);
		
		if (savedInstanceState != null)
			mShownComError = savedInstanceState.getParcelable(SAVE_COMERROR);
		
		mWifiPolicyHintDone = PreferenceManager.getDefaultSharedPreferences(this)
				.getBoolean(PREF_WIFIPOLICYHINT, false); 
		
		mGrid = (GridView)findViewById(R.id.DashBoard);
		if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)
			mGrid.setNumColumns(COLUMS_LANDSCAPE);
		mGrid.setAdapter(new StartButtonAdapter());
		mGrid.setOnKeyListener(new OnKeyListener() {
			public boolean onKey(View v, int keyCode, KeyEvent event) {
				if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
					GridView gridView = (GridView) v;
					View view = gridView.getSelectedView();
					if (view != null) {
						ImageButton button = (ImageButton) view
								.findViewWithTag("launcher");
						if (button != null) {
							return button.performClick();
						}
					}
				}
				return false;
			}
		});

		// android's call log
		mRecentCallsView = (RecentCallsView)findViewById(R.id.RecentCalls);

		// status display
		mStatusDisplayHandler = new StatusDisplayHandler(this);

		// initially try to connect to fritzbox
		Sipdroid.on(this,true);
		startService(new Intent(this, BoxService.class));
		try
		{
			PackageManagerHelper.setEnableReceiver(this,
					BootCompletedReceiver.class, true);
		}
		catch (NameNotFoundException e)
		{
			Log.e(TAG, "Failed to enable BootCompletedReceiver", e);
		}
		
		// Dialpad
		mDialpad = (Dialpad)findViewById(R.id.dtmf_dialer);
		mDialpad.setEnableNonDtmfInput(true); // allow input of "+"
		if (savedInstanceState != null)
			mDialpad.setText(savedInstanceState.getString(SAVE_DIALPAD_INPUT));
		mDialpad.setInitiallyOpen(true);
		final ImageButton btnDialpad = ((ImageButton)findViewById(R.id.SlideDialpad));
		btnDialpad.setImageResource(R.drawable.btn_dialpadclose);
		mDialpad.setOnDrawerCloseListener(new SlidingDrawer.OnDrawerCloseListener()
		{
			public void onDrawerClosed()
			{
				btnDialpad.setImageResource(R.drawable.btn_dialpadopen);
			}
		});
		mDialpad.setOnDrawerOpenListener(new SlidingDrawer.OnDrawerOpenListener()
		{
			public void onDrawerOpened()
			{
				btnDialpad.setImageResource(R.drawable.btn_dialpadclose);
			}
		});
		mDialpad.setOnTamListener(new Dialpad.OnTamListener()
		{
			public void onTam()
			{
				String tam = FRITZApp.this.mTamShortcut;
				if (!TextUtils.isEmpty(tam))
				{
					BoxInfo boxInfo = ComSettingsChecker.getBoxInfo();
					if (boxInfo != null) callNow(tam);
				}
			}
		});

		// Footer Buttons
		btnDialpad.setOnClickListener(new OnClickListener()
		{
			public void onClick(View v)
			{
				mDialpad.animateToggle();
			}
		});
		((Button)findViewById(R.id.CallNow)).setOnClickListener(new OnClickListener()
		{
			public void onClick(View v)
			{
				callNow();
			}
		});
		((ImageButton)findViewById(R.id.Redial)).setOnClickListener(new OnClickListener()
		{
			public void onClick(View v)
			{
				mDialpad.loadRedial(FRITZApp.this);
				if (!mDialpad.isOpened() && !TextUtils.isEmpty(mDialpad.getText()))
					mDialpad.animateToggle();
			}
		});
	}

	@Override
	public void onResume()
	{
		mRecentCallsView.onResume();
		
		super.onResume();
		mIsActive = true;
		
		// show in call screen if call is active
		if (Receiver.call_state != UserAgent.UA_STATE_IDLE) Receiver.moveTop();

		// status display
		mHandler.post(mStatusDisplayHandler);
		
		// TAM setting could have been changed
		updateTamInput();
		
		if (!mBoxServiceConnection.bindService(getApplicationContext()))
			Log.w(TAG, "Failed to bind to BoxService.");
	}

	@Override
	public void onPause()
	{
		super.onPause();
		mIsActive = false;
		
		mRecentCallsView.onPause();
		mBoxServiceConnection.unbindService();
	}
	
	private BoxServiceConnection mBoxServiceConnection = new BoxServiceConnection()
	{
		public void onBoxServiceConnected()
		{
			mHandler.post(new Runnable()
			{
				public void run()
				{
					// update launcher buttons
					if (mGrid != null)
						mGrid.setAdapter(new StartButtonAdapter());
					// TAM setting could have been changed
					updateTamInput();

					IBoxService srv = getService();
					if (srv != null)
					{
						IComErrorMessage error = srv.getLastComError();
						Log.d(TAG, "BoxServiceConnection.onBoxServiceConnected: onComError == "
								+ error);
						if (error != null)
						{
							onError(error);
							return;
						}
					}
					checkWifiPolicyHint();
				}
			});
		}

		public void onComStatusChanged()
		{
			mHandler.post(mStatusDisplayHandler);
			mHandler.post(new Runnable()
			{
				public void run()
				{
					// update launcher buttons
					if (mGrid != null)
						mGrid.setAdapter(new StartButtonAdapter());
					// TAM setting could have been changed
					updateTamInput();
					checkWifiPolicyHint();
				}
			});
		}

		public void onComError(final IComErrorMessage comError)
		{
			mHandler.post(new Runnable()
			{
				public void run()
				{
					onError(comError);
				}
			});
		}
	};
	
	@Override
	protected void onDestroy()
	{
		mRecentCallsView.onDestroy();
		super.onDestroy();
	}

	protected void onNewIntent(Intent intent)
	{
		setIntent(intent);
	}
	
	private void updateTamInput()
	{
		mTamShortcut = TamPreference.getCachedSelectedTam();
		mDialpad.setEnableTamInput(!TextUtils.isEmpty(mTamShortcut));
	}

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

	@Override
	public boolean onPrepareOptionsMenu(Menu menu)
	{
		boolean overrideClirOnce = false;
		IBoxService srv = mBoxServiceConnection.getService();
		if (srv != null) overrideClirOnce = srv.isOverrideClirOnce();
		menu.findItem(R.id.Clir)
				.setTitle((PhoneNumberHelper.isClir(this) == overrideClirOnce) ?
							R.string.menu_clir_on : R.string.menu_clir_off);
		return true;
		
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item)
	{
		switch (item.getItemId())
		{
			case R.id.Clir:
			{
				IBoxService srv = mBoxServiceConnection.getService();
				if (srv != null)
					srv.setOverrideClirOnce(!srv.isOverrideClirOnce());
				break;
			}
		
			case R.id.Settings: 
				startActivity(new Intent(this, SettingsActivity.class));
				break;
	
			case R.id.About:
				Help.showAbout(this);
				break;
				
			case R.id.Help:
				Help.showHelp(this);
				break;
				
			case R.id.Exit:
			{
				Sipdroid.on(this, false);
				startService(new Intent(this, BoxService.class));
				try
				{
					PackageManagerHelper.setEnableReceiver(this,
							BootCompletedReceiver.class, false);
				}
				catch (NameNotFoundException e)
				{
					Log.e(TAG, "Failed to disable BootCompletedReceiver", e);
				}
				finish();
			}
				break;
		}
		return true;
	}

	@Override
	protected Dialog onCreateDialog (int id)
	{
		switch (id)
		{
			case DIALOG_WIFIPOLICYHINT:
				return TextDialog.create(this,
						TextDialog.getDefaultTitle(this),
						getString(R.string.wifi_policy_hint))
						.setPositiveButton(android.R.string.yes,
								new DialogInterface.OnClickListener()
						{
							public void onClick(DialogInterface dialog, int which)
							{
								dialog.dismiss();
								// don't ask again
								mWifiPolicyHintDone = true;
								Editor editor = PreferenceManager
										.getDefaultSharedPreferences(FRITZApp.this)
										.edit();
								editor.putBoolean(PREF_WIFIPOLICYHINT, true);
								editor.commit();
								if (!Settings.System.putInt(getContentResolver(),
										Settings.System.WIFI_SLEEP_POLICY,
										Settings.System.WIFI_SLEEP_POLICY_NEVER))
									Log.e(TAG, "Failed to set WIFI_SLEEP_POLICY " +
										"to WIFI_SLEEP_POLICY_NEVER");
							}
						})
						.setNegativeButton(android.R.string.no,
								new DialogInterface.OnClickListener()
						{
							public void onClick(DialogInterface dialog, int which)
							{
								dialog.dismiss();
								// don't ask again
								mWifiPolicyHintDone = true;
								Editor editor = PreferenceManager
										.getDefaultSharedPreferences(FRITZApp.this)
										.edit();
								editor.putBoolean(PREF_WIFIPOLICYHINT, true);
								editor.commit();
							}
						})
						.setOnCancelListener(new DialogInterface.OnCancelListener()
						{
							public void onCancel(DialogInterface dialog)
							{
								dialog.dismiss();
								// don't ask again until next onCreate
								mWifiPolicyHintDone = true;
							}
						})
						.create();
			
			case DIALOG_COMERROR:
				if (mShownComError != null)
					return TextDialog.createOk(this, mShownComError.getMessage(),
							mShownComError.getIconResId()).create();
				break;
		}
		return null;
	}
	
	@Override
	protected void onSaveInstanceState(Bundle outState)
	{
		super.onSaveInstanceState(outState);
		outState.putString(SAVE_DIALPAD_INPUT, ((mDialpad != null) && (mDialpad.isOpened())) ?
				mDialpad.getText() : "");
		outState.putParcelable(SAVE_COMERROR, mShownComError);
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event)
	{
		// Dialpad
		boolean handled = (mDialpad == null) ?
				false : mDialpad.onKey(null, keyCode, event);
		if (!handled)
		{
			switch(keyCode)
			{
		        case KeyEvent.KEYCODE_CALL:
					callNow();
					return true;
			}
		}
		return (handled) ? true : super.onKeyDown(keyCode, event);
	}
	
	private void onError(IComErrorMessage comError)
	{
		IBoxService srv = mBoxServiceConnection.getService();
		if (srv != null) srv.removeLastComError(comError);

		Log.d(TAG, "onError: " + comError.getMessage());
		mShownComError = comError;
		showDialog(DIALOG_COMERROR);
	}

	/**
	 * Adapter f�r Grid der Launcherbuttons
	 */
	protected class StartButtonAdapter extends BaseAdapter
	{
		protected Class<Activity>[] allActivities;
		protected View[] buttons;

		/**
		 * Instantiates a new start button adapter.
		 */
		@SuppressWarnings("unchecked")
		public StartButtonAdapter() {
			allActivities = new Class[] { CallLogActivity.class,
					PhoneBookActivity.class, FeaturesActivity.class };
		}

		public int getCount()
		{
			return allActivities.length;
		}

		public Object getItem(int pos)
		{
			return allActivities[pos];
		}

		@Override
		public boolean hasStableIds()
		{
			return true;
		}

		public View getView(int position, View convertView, ViewGroup parent)
		{
			Drawable icon = null;
			String label = null;
			RelativeLayout activityLauncher = null;
			if (convertView == null) {
				activityLauncher = (RelativeLayout) View.inflate(FRITZApp.this,
						R.layout.t_launcherbutton, null);
			} else {
				activityLauncher = (RelativeLayout) convertView;
			}
			Class<Activity> currActivityClass = (Class<Activity>) allActivities[position];
			icon = ResourceHelper.getIconForClass(currActivityClass, true,
					FRITZApp.this);
			label = ResourceHelper.getLabelForClass(currActivityClass,
					FRITZApp.this);
			ImageButton button = (ImageButton) activityLauncher
					.findViewById(R.id.launcher_button);
			TextView text = (TextView) activityLauncher
					.findViewById(R.id.launcher_text);
			button.setImageDrawable(icon);
			text.setText(label, TextView.BufferType.NORMAL);
			button.setOnClickListener(new OnClickStartActivityIntent(
					currActivityClass));
			
			// OfflineActivity could be disabled
			boolean enable = true;
			Class<?>[] ifs = currActivityClass.getInterfaces();
			for (int interfaceItem = 0; interfaceItem < ifs.length;
					interfaceItem++)
			{
				if (OfflineActivity.class.equals(ifs[interfaceItem]))
				{
					try
					{
						// ask the activity, disable if the answer is no
						Method method = currActivityClass
								.getMethod("canShow", (Class[])null);
						if (!(Boolean)method.invoke(null, (Object[])null))
							enable = false;
					}
					catch(Exception exp) { }
				}
			}
			button.setEnabled(enable);
			text.setEnabled(enable);
			
			return activityLauncher;
		}

		public long getItemId(int position)
		{
			return position;
		}
	}

	void callNow()
	{
		if (mDialpad != null)
		{
			String number = mDialpad.getText();
			if (TextUtils.isEmpty(number))
			{
				mDialpad.loadRedial(this);
				if (!mDialpad.isOpened() && !TextUtils.isEmpty(mDialpad.getText()))
					mDialpad.animateToggle();
			}
			else
			{
				mDialpad.setText(""); 
				if (SettingsTestActivity.DIALCODE.equals(number))
					// open settings of hidden test features
					startActivity(new Intent(this, SettingsTestActivity.class));
				else
					callNow(number);
			}
		}
	}
	
	void callNow(String number)
	{
		removeDialog(DIALOG_COMERROR);
		startService(new Intent(this, BoxService.class)
				.putExtra(BoxService.EXTRA_COMMAND,
						BoxService.Command.CALL.ordinal())
				.putExtra(BoxService.EXTRA_NUMBER, number)
				.putExtra(BoxService.EXTRA_FRITZ_APP, true));
	}
	
	private void checkWifiPolicyHint()
	{
		if (mIsActive && !mWifiPolicyHintDone &&
				ComSettingsChecker.isConnected())
		{
			int value = Settings.System.getInt(getContentResolver(),
					Settings.System.WIFI_SLEEP_POLICY, -1);
			if (value != Settings.System.WIFI_SLEEP_POLICY_NEVER)
				showDialog(DIALOG_WIFIPOLICYHINT);
		}
	}
}
