package gr.uoc.csd.hy439.positioning;

import gr.uoc.csd.hy439.positioning.fingerprint.FingerprintAlgorithm;
import gr.uoc.csd.hy439.positioning.fingerprint.FingerprintService;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaPlayer;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

/**
 * <h1>Allows the collection of Wi-Fi measurements used to train fingerprint-based positioning models.</h1>
 * 
 * <p>The area of interest is divided in cells. The smartphone collecting the measurements should stay
 * stationary in each cell for some time, make measurements and write them in a file. For each
 * Access Point detected, a line of the form <timestamp, MAC_address, RSSI> is written in the file.</p>
 */
public class MeasureActivity extends Activity {
	/** The interval between Wi-Fi scans, in milliseconds (ms). */
	private final int WIFI_SCAN_INTERVAL= 1400;
	/** The measurement duration for one cell. */
	private final int CELL_MEASUREMENT_DURATION= WIFI_SCAN_INTERVAL*10/*0*/;
	
	/* References to the child view objects. */
	private EditText xEditText, yEditText;
	private Button startButton;
	private TextView  resultsTextView;
	
	/** The directory (folder) object, where the measurement files will be placed. */
	private File measurementsDir;
	/** The file where measurements will be written. */
	private File measurementFile;
	/** Provides convenient methods to write in the
	 * {@link MeasureActivity#measurementFile measurementFile}. */
	private PrintStream printStream;
	
	private WifiManager wifiManager;
	/** Periodically executes a {@link MeasureActivity.ScanTask ScanTask} object. */
	private Timer scanTimer;
	/**
	 * When {@link MeasureActivity#CELL_MEASUREMENT_DURATION} time has passed, it executes a {@link
	 * MeasureActivity.StopScanningTask StopScanningTask} object.
	 */
	private Timer stopTimer;
	/** Plays a notification sound when the measurements are done. */
	private MediaPlayer notificationSoundPlayer;
	
	/**
	 * This TimerTask object is executed periodically. It requests a Wi-Fi scan for Access Points (APs).
	 */
	private class ScanTask extends TimerTask {
		@Override
		public void run() {
			Log.i(this.getClass().getName(), "Timer task doing work");
	        wifiManager.startScan();
		}
	}
	
	/**
	 * This TimerTask object is executed when {@link MeasureActivity#CELL_MEASUREMENT_DURATION} time has
	 * passed. It stops the {@link MeasureActivity.ScanTask ScanTask} from requesting new Wi-Fi scans. It
	 * also notifies the user via a sound that measurement interval has elapsed.
	 */
	private class StopScanningTask extends TimerTask {
		@Override
		public void run() {
			Log.i(this.getClass().getName(), "Enough measurements for this cell");
			if (scanTimer != null) {
		        scanTimer.cancel();
		        scanTimer.purge();
		        scanTimer = null;
		    }
			if (stopTimer != null) {
		    	stopTimer.cancel();
		    	stopTimer.purge();
		    	stopTimer = null;
		    }			
			unregisterReceiver(wifiReceiver);			
			printStream.flush();
		    printStream.close();
		    notificationSoundPlayer.start();
		}
	}
    
	/**
	 * This BroadcastReceiver will be registered to receive an intent objects when fresh scan results are available.
	 * When it receives an intent, it will get the fresh scan results from the WifiManager and write the needed values
	 * to the via the measurementFile, using the printStream object.
	 */
	private BroadcastReceiver wifiReceiver = new BroadcastReceiver() {		
		@Override
		public void onReceive(Context context, Intent intent) {
			String string="";
			long curTime= System.currentTimeMillis();
			List<ScanResult> scanResultList = wifiManager.getScanResults();
			for (ScanResult scanResult : scanResultList) {
				string+= curTime+" "+scanResult.BSSID+" "+scanResult.level+"\n";				
			}
			printStream.print(string);
			printStream.flush();
			resultsTextView.setText(string);
			Log.d(this.getClass().getName(), string);
		}
	};

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_measure);
        wifiManager= (WifiManager) getSystemService(Context.WIFI_SERVICE);
        
        resultsTextView= (TextView) findViewById(R.id.resultsTextView);
        xEditText= (EditText) findViewById(R.id.editText1);
        yEditText= (EditText) findViewById(R.id.editText2);
    	startButton= (Button) findViewById(R.id.AssignInput);
    	
    	/*File sdCard = Environment.getExternalStorageDirectory();*/
		measurementsDir = new File(FingerprintAlgorithm.FILES_PREFIX+FingerprintAlgorithm.TRAINING_DATA_DIR_NAME /*sdCard.getAbsolutePath() + "/radiomap"*/);
		measurementsDir.mkdirs();
    	
    	startButton.setOnClickListener(new View.OnClickListener() {			
			@Override
    		public void onClick(View v) {
				// new file and printStream
				String x= xEditText.getText().toString();
				String y= yEditText.getText().toString();				
				measurementFile = new File(measurementsDir, x+"_"+y);
				try {
					printStream = new PrintStream(new FileOutputStream(measurementFile), true);
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				}				
				registerReceiver(wifiReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));				
				stopTimer= new Timer();
				stopTimer.schedule(new StopScanningTask(), CELL_MEASUREMENT_DURATION);				
				scanTimer= new Timer();
				scanTimer.schedule(new ScanTask(), 0, WIFI_SCAN_INTERVAL);
			}
		});	    
	    notificationSoundPlayer = MediaPlayer.create(MeasureActivity.this, Settings.System.DEFAULT_NOTIFICATION_URI);
		/*mp.setOnCompletionListener(new OnCompletionListener() {
	        @Override
	        public void onCompletion(MediaPlayer mp) {
	            // TODO Auto-generated method stub
	            mp.release();
	        }
	    });*/
    }

    @Override
	public void onDestroy() {
	    super.onDestroy();
	    if (scanTimer != null){
	        scanTimer.cancel();
	        scanTimer.purge();
	        scanTimer = null;
	    }
	    if (stopTimer != null){
	    	stopTimer.cancel();
	    	stopTimer.purge();
	    	stopTimer = null;
	    }
	}
}