package gr.uoc.csd.hy439.positioning.fingerprint;

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

import android.content.Context;
import android.location.Location;
import android.net.wifi.ScanResult;
import android.os.Environment;
import android.util.Log;

/**
 * Abstract class which represents a Fingerprint algorithm.
 *
 */
public abstract class FingerprintAlgorithm {
	protected Context context;
	
	public static final String FILES_PREFIX= Environment.getExternalStorageDirectory().getAbsolutePath()+"/positioning/";
	public static final String TRAINING_DATA_DIR_NAME= "fingerprint-training-data";
	public static final String XY_TO_LATLON= "xy_to_latlon.txt";
	
	// insert here struct for radio map
	
	/**
	 * Trains the model with measurements collected during the training phase.
	 * @throws IOException when something goes wrong when reading from file(s).
	 */
	protected abstract void trainModel();
	
	/**
	 * Saves the model in file(s) to avoid training it again, later.
	 * <p>Usually, training the model is slower that reading it from a file.</p>
	 * @throws IOException when failing to write the model file(s).
	 */
	protected abstract void saveModel() throws IOException;
	
	/**
	 * Loads the model from file(s), which is usually faster that training it from scratch.
	 * @throws Exception when failing to read the model file(s).
	 */
	protected abstract void retrieveModel() throws Exception;
	
	/**
	 * Subclasses should implement this method to get ready to be trained, read or write their files,
	 * using the {@link FingerprintAlgorithm#trainModel() trainmodel()},
	 * {@link FingerprintAlgorithm#saveModel() saveModel()} or
	 * {@link FingerprintAlgorithm#retrieveModel() retrieveModel()}
	 * methods.
	 */
	protected abstract void onCreate();
	
	/**
	 * Sees a new list of {@link ScanResult ScanResults} and estimates the {@link Location location} of the device.
	 * @param scanResults Trigger the 802.11 interface to scan the channels and feed this method with the scanResults.
	 * @return the estimated location
	 * @throws OutOfTrainingAreaException when the model doesn't know any of the scanResults Access Points. 
	 */
	abstract Location estimateLocation(ArrayList<ScanResult> scanResults) throws OutOfTrainingAreaException;	
	
	
	FingerprintAlgorithm(Context context) {
		this.context= context;
		onCreate();
		try {
			retrieveModel();
		} catch (Exception e) {
			Log.w(this.getClass().getName(), "Failed to read the model properties from the file(s). Let's create them from scratch.");
			trainModel();
			try {
				saveModel();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
	}

}
