/*
 * Copyright (c) 2015, StrategyQuant - All rights reserved.
 *
 * Code in this file was made in a good faith that it is correct and does what it should. 
 * If you found a bug in this code OR you have an improvement suggestion OR you want to include 
 * your own code snippet into our standard library please contact us at:
 * http://tasks.strategyquant.com/projects/snippets/
 *
 * This code can be used only within StrategyQuant products. 
 * Every owner of valid (free, trial or commercial) license of any StrategyQuant product 
 * is allowed to freely use, copy, modify or make derivative work of this code without limitations,
 * to be used in all StrategyQuant products and share his/her modifications or derivative work 
 * with the StrategyQuant community.
 *  
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES 
 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *  
 */
package com.strategyquant.extend.Test;

import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Scanner;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.strategyquant.extend.Functions.TestInfo;
import com.strategyquant.lib.app.MainApp;
import com.strategyquant.lib.results.SQResult;
import com.strategyquant.lib.results.SQResultsGroup;
import com.strategyquant.lib.results.SQStats;
import com.strategyquant.lib.scripter.Program;
import com.strategyquant.lib.tests.SQTestCase;
import com.strategyquant.lib.tests.TestOutput;
import com.strategyquant.lib.tests.TestScript;
import com.strategyquant.lib.utils.FlexibleSettings;
import com.strategyquant.lib.utils.SQUtils;


public class StatsValuesComputing extends TestScript {
	public static final Logger Log = LoggerFactory.getLogger("StatsValuesComputing");
	private ArrayList<TestInfo> tests = new ArrayList<TestInfo>();
    
	public StatsValuesComputing() {
		setCategory("Stats values computing");
	}
	
	@Override
	public void runTest() {
		
		if(loadTestFile()) {
			runLoadedTests();
		}
	}

	private void runLoadedTests() {
		// first of all find out which files should be loaded
		HashSet<String> filesToLoad = new HashSet();
		
		for(TestInfo ti : tests) {
			filesToLoad.add(ti.fileName);
		}
		
		for (String fileName : filesToLoad) {
			runAllTestsForFile(fileName);
		}
	}
	
	private void runAllTestsForFile(String fileName) {
		
		String fullFileName = MainApp.getDataPath()+"/tests/StatsValues/"+fileName;
		
		File file = new File(fullFileName);
		if(!file.exists() || file.isDirectory()) {
			outputError("Test report file not found!", fullFileName);
			return;
		}
		

		try {
			SQResultsGroup strategyResults = (SQResultsGroup) Program.get("Loader").call("loadFile", fullFileName);
			
			for(TestInfo ti : tests) {
				if(ti.fileName.equals(fileName)) {
				
					setName(fileName + " / "+ti.resultKey);
					
					SQResult result = strategyResults.getResult(ti.resultKey);
					if(result == null) {
						outputError("Cannot find this result key", ti.resultKey);
						continue;
					}
					
					SQStats stats = result.getStats(ti.direction, ti.plType, ti.sampleType);
					if(stats == null) {
						outputError("Cannot find this stats combination", ti.getStatsCombination());
						continue;
					}
					
					
					double computedValue = stats.getDouble(ti.key);
					
					if(computedValue == FlexibleSettings.DOUBLE_MISSING) {
						outputError("Cannot find this stats value:", ti.resultKey);
						continue;
					}
					
					assertEquals(ti.getCompleteKey(), ti.expectedValue, computedValue);
				}
			}
		
		} catch (Exception e) {
			Log.error("Exc.", e);
			processException(fileName, e);
		}
	}

	private boolean loadTestFile() {
		tests.clear();

		setCategory(getCategory());

    	String fileName = MainApp.getDataPath()+"/tests/StatsValues/Tests.csv";
		
		File file = new File(fileName);
		if(!file.exists() || file.isDirectory()) {
			SQTestCase testCase = new SQTestCase("Loading test file");
			outputError("Cannot load test file", file.getAbsolutePath());
			return false;
		}
		
    	try {
			parseTests(SQUtils.fileToString(file));
		} catch (Exception e) {
			SQTestCase testCase = new SQTestCase("Loading test file");
			outputError("Problem parsing test file!", e.getMessage());
			return false;
		}
    	
    	if(tests.size() == 0) {
			SQTestCase testCase = new SQTestCase("Loading test file");
			outputError("There are no tests defined in the test file!", file.getAbsolutePath());
			return false;
    	}

    	return true;
	}	

	private void parseTests(String content) throws Exception {
		String rowData = null;
		int i=0;
		
		//read a results per line
		Scanner scanner = new Scanner(content);
		while (scanner.hasNextLine()) {
			i++;

			rowData = scanner.nextLine();

			if(rowData.startsWith("#")) {
				// skip comment
				continue; 
			}

			if(rowData.trim().length() == 0) {
				// skip empty line
				continue; 
			}
			
			tests.add(new TestInfo(i, rowData));
		}
	}	

	
}