/* NFC Spy is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

NFC Spy 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
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Wget.  If not, see <http://www.gnu.org/licenses/>.

Additional permission under GNU GPL version 3 section 7 */

package com.sinpo.nfcspy;

import static android.net.wifi.p2p.WifiP2pManager.EXTRA_WIFI_P2P_DEVICE;
import static android.net.wifi.p2p.WifiP2pManager.EXTRA_WIFI_STATE;
import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION;
import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION;
import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION;
import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION;

import java.util.ArrayList;
import java.util.Collection;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.ChannelListener;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class ActivityManageP2P extends ActivityBase {

	public void startDiscover(View v) {
		resetPeers();

		if (!WiFiP2PManager.isWiFiEnabled(this)) {
			showMessage(R.string.status_no_wifi);
			return;
		}

		new CommandHelper(new Wifip2pDiscoverPeers(eventHelper), p2p,
				getString(R.string.info_discovering)).execute();
	}

	public void disconnectPeer(View v) {
		new Wifip2pCancelConnect(eventHelper).execute(p2p);
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_manage_p2p);

		peerdevs = new ArrayList<WifiP2pDevice>();
		peers = new ArrayAdapter<CharSequence>(this, R.layout.listitem_peer);
		eventHelper = new EventHelper();

		ListView lv = ((ListView) findViewById(R.id.list));
		lv.setAdapter(peers);
		lv.setOnItemClickListener(eventHelper);

		thisDevice = (TextView) findViewById(R.id.txtThisdevice);
	}

	@Override
	protected void onResume() {

		p2p = new WiFiP2PManager();
		p2p.init(this, eventHelper);
		registerReceiver(eventHelper, getWiFiP2PIntentFilter());

		super.onResume();
	}

	@Override
	protected void onPause() {
		closeProgressDialog();

		new Wifip2pStopPeerDiscovery(null).execute(p2p);

		unregisterReceiver(eventHelper);
		p2p.reset();
		p2p = null;

		resetPeers();

		super.onPause();
	}

	@SuppressWarnings("unchecked")
	boolean handleMessage(int type, int status, Object obj) {

		if (type == WiFiP2PCommand.CMD_RequestPeers) {

			resetPeers();

			if (obj != null) {

				for (WifiP2pDevice dev : (Collection<WifiP2pDevice>) obj) {
					peerdevs.add(dev);
					peers.add(getWifiP2pDeviceInfo(dev));
				}
			}
			return true;
		}

		if (type == WiFiP2PCommand.CMD_CancelConnect) {
			new Wifip2pRemoveGroup(eventHelper).execute(p2p);
			return true;
		}

		if (type == WiFiP2PCommand.CMD_RemoveGroup) {
			new Wifip2pDiscoverPeers(eventHelper).execute(p2p);
			return true;
		}

		return true;
	}

	void handlePeerListClick(int index) {
		WifiP2pDevice dev = peerdevs.get(index);

		if (dev.status == WifiP2pDevice.CONNECTED
				|| dev.status == WifiP2pDevice.INVITED) {
			disconnectPeer(dev);
		} else if (dev.status != WifiP2pDevice.UNAVAILABLE) {
			connectPeer(dev);
		}
	}

	void handleBroadcast(Intent intent) {
		closeProgressDialog();

		final String action = intent.getAction();
		if (WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
			int state = intent.getIntExtra(EXTRA_WIFI_STATE, -1);
			if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
				p2p.isWifiP2pEnabled = true;
			} else {
				showMessage(R.string.event_p2p_disable);
				resetData();
			}
		} else if (WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
			new Wifip2pRequestPeers(eventHelper).execute(p2p);

		} else if (WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
			WifiP2pDevice me = (WifiP2pDevice) intent
					.getParcelableExtra(EXTRA_WIFI_P2P_DEVICE);

			thisDevice.setText(getWifiP2pDeviceInfo(me));
		}
	}

	void showMessage(int resId) {
		showMessage(getString(resId));
	}

	void showMessage(CharSequence msg) {
		Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
	}

	void showProgressDialog(CharSequence msg) {
		closeProgressDialog();

		ProgressDialog pd = new ProgressDialog(this,
				ProgressDialog.THEME_HOLO_LIGHT);
		progressDialog = pd;

		pd.setMessage(msg);
		pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
		pd.setIndeterminate(true);
		pd.setCancelable(true);
		pd.setCanceledOnTouchOutside(false);
		pd.show();
	}

	void closeProgressDialog() {
		if (progressDialog != null) {
			progressDialog.dismiss();
			progressDialog = null;
		}
	}

	void onChannelDisconnected() {
		showMessage(R.string.event_p2p_disable);
		resetData();
		p2p.reset();
	}

	private void connectPeer(WifiP2pDevice peer) {

		CharSequence dev = getWifiP2pDeviceInfo2(peer);
		CharSequence msg = Logger.fmt(getString(R.string.info_connect), dev);
		CharSequence msg2 = Logger
				.fmt(getString(R.string.info_connecting), dev);
		CommandHelper cmd = new CommandHelper(new Wifip2pConnectPeer(peer,
				eventHelper), p2p, msg2);

		new AlertDialog.Builder(this, AlertDialog.THEME_HOLO_LIGHT)
				.setTitle(R.string.lab_p2p_connect).setMessage(msg)
				.setNegativeButton(R.string.action_cancel, cmd)
				.setPositiveButton(R.string.action_ok, cmd).show();
	}

	private void disconnectPeer(WifiP2pDevice peer) {

		CharSequence dev = getWifiP2pDeviceInfo2(peer);
		CharSequence msg = Logger.fmt(getString(R.string.info_disconnect), dev);
		CommandHelper cmd = new CommandHelper(new Wifip2pCancelConnect(
				eventHelper), p2p, null);

		new AlertDialog.Builder(this, AlertDialog.THEME_HOLO_LIGHT)
				.setTitle(R.string.lab_p2p_disconnect).setMessage(msg)
				.setNegativeButton(R.string.action_cancel, cmd)
				.setPositiveButton(R.string.action_ok, cmd).show();
	}

	private void resetPeers() {
		peerdevs.clear();
		peers.clear();
	}

	private void resetData() {
		p2p.isWifiP2pEnabled = false;
		thisDevice.setText(null);
		resetPeers();
	}

	private CharSequence getWifiP2pDeviceInfo(WifiP2pDevice dev) {
		CharSequence sta = getWifiP2pDeviceStatus(dev);
		return Logger.fmt("%s [%s] [%s]", dev.deviceName, dev.deviceAddress,
				sta);
	}

	private CharSequence getWifiP2pDeviceInfo2(WifiP2pDevice dev) {
		return Logger.fmt("%s [%s]", dev.deviceName, dev.deviceAddress);
	}

	private CharSequence getWifiP2pDeviceStatus(WifiP2pDevice dev) {

		switch (dev.status) {
		case WifiP2pDevice.CONNECTED:
			return getString(R.string.status_p2p_connected);
		case WifiP2pDevice.INVITED:
			return getString(R.string.status_p2p_invited);
		case WifiP2pDevice.FAILED:
			return getString(R.string.status_p2p_failed);
		case WifiP2pDevice.AVAILABLE:
			return getString(R.string.status_p2p_available);
		case WifiP2pDevice.UNAVAILABLE:
		default:
			return getString(R.string.status_p2p_unavailable);
		}
	}

	private ArrayAdapter<CharSequence> peers;
	private ArrayList<WifiP2pDevice> peerdevs;
	private TextView thisDevice;
	private ProgressDialog progressDialog;
	private EventHelper eventHelper;
	private WiFiP2PManager p2p;

	private final class CommandHelper implements OnClickListener {
		private final WiFiP2PCommand command;
		private final WiFiP2PManager ctx;
		private final CharSequence message;

		CommandHelper(WiFiP2PCommand cmd, WiFiP2PManager p2p, CharSequence msg) {
			ctx = p2p;
			command = cmd;
			message = msg;
		}

		void execute() {
			command.execute(ctx);

			if (message != null)
				showProgressDialog(message);
		}

		@Override
		public void onClick(DialogInterface dialog, int which) {
			dialog.dismiss();

			if (which == DialogInterface.BUTTON_POSITIVE)
				execute();
		}
	}

	private final class EventHelper extends BroadcastReceiver implements
			ServiceFactory.SpyCallback, ChannelListener, OnItemClickListener {

		@Override
		public void handleMessage(int type, int status, Object obj) {
			ActivityManageP2P.this.handleMessage(type, status, obj);
		}

		@Override
		public void onReceive(Context context, Intent intent) {
			ActivityManageP2P.this.handleBroadcast(intent);
		}

		@Override
		public void onChannelDisconnected() {
			ActivityManageP2P.this.onChannelDisconnected();
		}

		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position,
				long id) {
			ActivityManageP2P.this.handlePeerListClick(position);
		}
	}

	private final IntentFilter getWiFiP2PIntentFilter() {
		final IntentFilter ret = new IntentFilter();
		ret.addAction(WIFI_P2P_STATE_CHANGED_ACTION);
		ret.addAction(WIFI_P2P_CONNECTION_CHANGED_ACTION);
		ret.addAction(WIFI_P2P_PEERS_CHANGED_ACTION);
		ret.addAction(WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
		return ret;
	}
}