package org.physionet.challenge2011;
//ONLY THESE IMPORTS ARE ALLOWED //
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
//import java.lang.Math.*; //Uncomment if you need this
//DO NOT ADD IMPORTS TO THE CODE ABOVE 

public class ChallengeEntry {

	final static int FS= 500;					//Sampling Frequency
	final static int CH= 12;
	final static double WIN=FS*10;
	final static double WIN_HF=WIN/2;
	final static int M = FS *20;             	// Buffer size
	final static double PKS_MIN=5;         		// Minimum number of expected peaks in 10s 
	final static double PKS_MINHF= PKS_MIN/2;         
	final static double PKS_MAX=30;         	// Max number of expected peaks in 10s
	final static double PKS_MAXHF= PKS_MAX/2;         
	final static double FRGT=0.69;   		// Forgetting factor for peaks 
	final static double FRGT_TH=0.1;   		// Forgetting factor threshold
	final static short [] W={1,1,1,-1,1,1,-1,-1,1,1,1,1}; // Weights for each channel
	final static double MSUM = 2000; 		// Average Peak value hardcoded based on sample data
	final static double PK_TH=0.9*MSUM; 		// Threshold for peak detection
	final static int BUFLENGTH= M*(CH+CH-1);
	static short [] sum = new short[M]; //Array for storing summed channel data
	
	//Define Quality values (could also be defined as enum...)
	final static int INIT=-1;
	final static int GOOD = 0;
	final static int MAYBE=1;
	//Bad Quality ones is any output value >=2, setting more values can help with debug
	//and can make the application more useful in providing feedback for the final users
	final static int BAD=2;			//generic bad quality
	final static int BAD_NO_BEATS=3;
	final static int BAD_TOOMANY_BEATS=4;
	
	synchronized public int get_result(InputStream iFile, final ECG_MetaData m_MetaData) throws IOException {
		

		//Load data
		InputStreamReader inread= new InputStreamReader(iFile);
		BufferedReader buf = new BufferedReader(inread,BUFLENGTH);
		String strLine = null;
		int index=0, result=INIT;  	// Set initial result to an invalid state
		int pks= 0; 				// Number of BEATS detected
 		double pk_memory=0; 	// Memory of last peak
 		double pk_th = PK_TH - (m_MetaData.age+1)/6;  //set maximum number of peaks base on the age of the subject
 		
		while ((strLine = buf.readLine()) != null) {
			String [] tmp = strLine.split(",");
			//Load summed data into array 
			sum[index]= (short) (W[0]*Short.parseShort(tmp[0])); //Initialize array
			for(int ch=1;ch<CH;ch++){
				sum[index] += (W[ch]*Short.parseShort(tmp[ch]))  ;
			}	

			if((pk_memory < FRGT_TH) && sum[index] > pk_th){
				//If peak is in acceptable range, increment count and reset memory
				pks++; 
				pk_memory=FRGT;
			}else{ 
				//Allow memory to forget past peak
				pk_memory *=pk_memory;
			}

			//Check for possible early break conditions
			if(pks >= PKS_MINHF){
				if(index <= WIN_HF){
					//If half of the min # BEATS are found before half of the interval, exit with good signal if below physiological max
					result = (pks < PKS_MAXHF) ? GOOD:BAD_TOOMANY_BEATS;
					break;
				}else{
					//Using the first and second half of signal,  so apply larger threshold
					if( pks > PKS_MIN){
						result = (pks < PKS_MAX) ? GOOD:BAD_TOOMANY_BEATS;
						break;
					}
				}	
			}else {
				// In case there is no BEATS in the first half exit with bad quality early 
				if(index > WIN_HF){
					result=BAD_NO_BEATS;
					break;
				}
			}
			index++;
			if(index > WIN)
				break;
		}

		//clean-up
		buf.close();
		inread.close();
		iFile.close();	
		return result;


	}

}
