/* 
 * Copyright 2012 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.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
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.discovery.BoxInfo;
import de.avm.android.fritzapp.sipua.ui.Receiver;
import de.avm.android.fritzapp.util.ResourceHelper;
import de.avm.android.tr064.Tr064Capabilities;
import de.avm.android.tr064.model.WLANInfo;

/* GUI to show WLAN quality */
public class WlanTesterActivity extends Activity implements OfflineActivity
{
	private int UPDATE_PERIOD = 2000;
	private static final String SAVED_INFO = "info";
	
	private DataHub fritzBox = new DataHub();

	private View mSsidView;
	private View mWlaninfoView;
	private TextView mSsid;
	private ImageView mSignal;
	private TextView mBandwidth;
	
	private Timer mUpdateTimer = null;
	private Handler mUiHandler = new Handler();
	private FetchWLANDataTask mLoaderTask = null;
	private WaitDialog mWaitDialog = null;
	private WLANInfo mInfo = null; 

	/* (non-Javadoc)
	 * @see android.app.Activity#onCreate(android.os.Bundle)
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.wlantester);
		ResourceHelper.setAltTitleSymbol(this);

		// Title
		ResourceHelper.setTitle(this, R.string.wlantester_label);

    	// views
		mSsidView = findViewById(R.id.SsidView);
    	mWlaninfoView = findViewById(R.id.WlaninfoView);
    	mSsid = (TextView)findViewById(R.id.Ssid);
    	mSignal = (ImageView)findViewById(R.id.Signal);
    	mBandwidth = (TextView)findViewById(R.id.Bandwidth);
    	
    	// restored content
    	if (savedInstanceState != null)
    		mInfo = savedInstanceState.getParcelable(SAVED_INFO);
	}

	@Override
	protected void onSaveInstanceState (Bundle outState)
	{
		if (mInfo != null) outState.putParcelable(SAVED_INFO, mInfo);
	}

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

		if (mInfo == null) showWait();
		onUpdate();
		
		// periodically update info
		mUpdateTimer = new Timer();
		mUpdateTimer.schedule(new TimerTask()
		{
			public void run()
			{
				mUiHandler.post(new Runnable()
				{
					public void run()
					{
						refresh();
					}
				});
			}
		}, (mInfo == null) ? 200 : UPDATE_PERIOD, UPDATE_PERIOD);
	}

	@Override
	protected void onPause()
	{
		super.onPause();
		
		mUpdateTimer.cancel();
		mLoaderTask = null;
		dismissWait();
	}

	private void refresh()
	{
		if (mLoaderTask == null)
		{
			Tr064Capabilities capabilities = ComSettingsChecker.getTr064Capabilities();
			if ((capabilities != null) &&
					capabilities.has(Tr064Capabilities.Capability.WLAN_CONF))
			{
				mLoaderTask = (FetchWLANDataTask)new FetchWLANDataTask().execute();
			}
			else
			{
				// not connected
				dismissWait();
				mInfo = null;
			}
			onUpdate();
		}
	}

	private void onError(FetchWLANDataTask thread)
	{
		if (mLoaderTask == thread)
		{
			mLoaderTask = null;
			dismissWait();
			mInfo = null;
			onUpdate();
		}
	}
	
	private void onLoaded(FetchWLANDataTask thread, WLANInfo info)
	{
		if (mLoaderTask == thread)
		{
			mLoaderTask = null;
			dismissWait();
			mInfo = info;
			onUpdate();
		}
	}

	private void onUpdate()
	{
		boolean showData = (mInfo != null);
			
		// get signal range
		int signalRangeMin = 0;
		int signalRangeMax = 0;
		if (showData)
		{
			try
			{
				BoxInfo boxInfo = ComSettingsChecker.getBoxInfo();
				signalRangeMin = Integer.parseInt(boxInfo.getTr064Boxinfo()
						.getWlanSignalRangeMin());
				signalRangeMax = Integer.parseInt(boxInfo.getTr064Boxinfo()
						.getWlanSignalRangeMax());
				if (signalRangeMax < signalRangeMin) showData = false;
			}
			catch(Exception e)
			{
				showData = false;
			}
		}

		if (!showData)
		{
			// SSID if WLAN connected
			WifiInfo wifiInfo = ((WifiManager)getBaseContext()
					.getSystemService(Context.WIFI_SERVICE)).getConnectionInfo();
			String ssid = (wifiInfo == null) ? null : wifiInfo.getSSID(); 
			if (TextUtils.isEmpty(ssid))
			{
				mSsidView.setVisibility(View.GONE);
			}
			else
			{
				mSsidView.setVisibility(View.VISIBLE);
				mSsid.setText(ssid);
			}
			mWlaninfoView.setVisibility(View.GONE);
			return;
		}

		// SSID
		mSsidView.setVisibility(View.VISIBLE);
		mSsid.setText(mInfo.getSsid());

		// signal
		int signalSegment = (signalRangeMax - signalRangeMin) / 5;
		int resImage = R.drawable.signal_0;
		if (mInfo.getSignalStrength() > (signalRangeMin + signalSegment * 4))
			resImage = R.drawable.signal_5;
		else if (mInfo.getSignalStrength() > (signalRangeMin + signalSegment * 3))
			resImage = R.drawable.signal_4;
		else if (mInfo.getSignalStrength() > (signalRangeMin + signalSegment * 2))
			resImage = R.drawable.signal_3;
		else if (mInfo.getSignalStrength() > (signalRangeMin + signalSegment))
			resImage = R.drawable.signal_2;
		else if (mInfo.getSignalStrength() > signalRangeMin)
			resImage = R.drawable.signal_1;
		mSignal.setImageResource(resImage);

		// bandwidth
		String bandwith = (mInfo.getBandwidth() > 0) ?
				String.format(getString(R.string.wlan_bandwidth_fmt),
						Integer.toString(mInfo.getBandwidth())) : "";
		mBandwidth.setText(bandwith);

		mWlaninfoView.setVisibility(View.VISIBLE);
	}
	
	private void showWait()
	{
		if (mWaitDialog == null)
		{
			mWaitDialog = WaitDialog.show(this, R.string.wait_dialog,
					new DialogInterface.OnCancelListener()
			{
				public void onCancel(DialogInterface dialog)
				{
					if (dialog == mWaitDialog)
					{
						// cancel pending load
						mWaitDialog = null;
						dialog.dismiss();
						mLoaderTask = null;

						// if nothing shown, close activity
						if (mInfo == null)
							WlanTesterActivity.this.finish();
					}
					else dialog.dismiss();
				}
			});
		}
	}
	
	private void dismissWait()
	{
		if (mWaitDialog != null)
		{
			mWaitDialog.dismiss();
			mWaitDialog = null;
		}
	}

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

	@Override
	public boolean onOptionsItemSelected(MenuItem item)
	{
		switch (item.getItemId())
		{
			case R.id.About:
				Help.showAbout(this);
				break;
				
			case R.id.Help:
				Help.showHelp(this);
				break;
		}
		return true;
	}
	
	private class FetchWLANDataTask extends AsyncTask<Void, Integer, WLANInfo> 
	{
		@Override
		protected WLANInfo doInBackground(Void... params)
		{
			try
			{
				return fritzBox.getWLANInfo(WlanTesterActivity.this);
			}
			catch(Exception exp)
			{
				exp.printStackTrace();
				return null;
			}
		}

		protected void onPostExecute(WLANInfo info)
		{
			super.onPostExecute(info);
			if (info == null)
				onError(this);
			else
				onLoaded(this, info);
		}
	}

	public static Intent showIntent(Context context)
	{
		if (canShow())
			return new Intent(context, WlanTesterActivity.class)
					.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		return null;
	}
	
	public static Boolean canShow()
	{
		NetworkInfo networkInfo = ((ConnectivityManager)Receiver.mContext
				.getSystemService(Context.CONNECTIVITY_SERVICE))
				.getActiveNetworkInfo();
		return (networkInfo != null) &&
				(networkInfo.getType() == ConnectivityManager.TYPE_WIFI);
	}
}
