package net.woodyfolsom.cs6601.p3;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.woodyfolsom.cs6601.p3.domain.Company;
import net.woodyfolsom.cs6601.p3.domain.Headline;
import net.woodyfolsom.cs6601.p3.domain.StockPrice;
import net.woodyfolsom.cs6601.p3.svc.HeadlineService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class ValidationSetCreator {
	private static final File stockSymbolsCSV = new File("stock_symbols.csv");

	private static final int INVALID_DATE = 1;
	private static final int IO_EXCEPTION = 2;
	private static final int STOCK_SYMBOL_CSV_NOT_FOUND = 3;

	@Autowired
	HeadlineService mySQLHeadlineServiceImpl;

	public static void main(String... args) {

		ApplicationContext context = new FileSystemXmlApplicationContext(
				new String[] { "AppContext.xml" });
		ValidationSetCreator modelGenerator = context
				.getBean(ValidationSetCreator.class);
		DateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd");

		Date startDate = null;
		Date endDate = null;
		try {
			startDate = dateFmt.parse("2012-01-01");
			endDate = dateFmt.parse("2012-04-14");
		} catch (ParseException pe) {
			System.exit(INVALID_DATE);
		}

		Map<String, Map<Date, StockPrice>> stockTrends = new HashMap<String, Map<Date, StockPrice>>();
		try {
			List<Company> fortune50 = modelGenerator
					.getFortune50(stockSymbolsCSV);
			for (Company company : fortune50) {
				stockTrends.put(company.getStockSymbol(),
						new HashMap<Date, StockPrice>());
				System.out.println("Polling price data for "
						+ company.getName());
				File stockPriceFile = new File("data" + File.separator
						+ company.getStockSymbol() + ".txt");
				BufferedReader buf;
				try {
					buf = new BufferedReader(new InputStreamReader(
							new FileInputStream(stockPriceFile)));
				} catch (FileNotFoundException fnfe) {
					System.out
							.println("Unable to find historical stock data file for: "
									+ company.getStockSymbol());
					continue;
				}
				String line;
				int linesRead = 0;
				try {
					while ((line = buf.readLine()) != null) {
						linesRead++;
						if (linesRead == 1) {
							continue; // header line
						}
						String[] fields = line.trim().split(",");
						Date date;
						try {
							date = dateFmt.parse(fields[0]);
						} catch (ParseException pe) {
							System.out.println("Error parsing date: "
									+ fields[0]);
							continue;
						}
						if (date.compareTo(endDate) > 0) {
							continue;
						}
						if (date.compareTo(startDate) < 0) {
							break;
						}

						double open;
						double high;
						double low;
						double close;
						long volume;
						double adjClose;

						try {
							open = Double.parseDouble(fields[1]);
							high = Double.parseDouble(fields[2]);
							low = Double.parseDouble(fields[3]);
							close = Double.parseDouble(fields[4]);
							volume = Long.parseLong(fields[5]);
							adjClose = Double.parseDouble(fields[6]);
						} catch (NumberFormatException nfe) {
							System.out.println(nfe.getMessage());
							continue;
						}

						StockPrice stockPrice = new StockPrice(date, open,
								high, low, close, volume, adjClose);

						stockTrends.get(company.getStockSymbol()).put(date,
								stockPrice);
					}
				} catch (IOException ioe) {
					System.err.println(ioe.getMessage());
					continue;
				}
				try {
					buf.close();
				} catch (IOException ioe) {
					System.err.println(ioe.getMessage());
				}
			}
			List<Headline> valSet = new ArrayList<Headline>();
			for (Company company : fortune50) {
				System.out.println("Getting headlines for Fortune 50 company #"
						+ company.getId() + " (" + company.getName() + ")...");
				List<Headline> coValSet = modelGenerator.mySQLHeadlineServiceImpl
						.getHeadlines(company.getStockSymbol(), startDate,
								endDate, 3);
				System.out.println("Pulled " + coValSet.size()
						+ " VALIDATION headlines for "
						+ company.getStockSymbol() + " from " + startDate
						+ " to " + endDate);

				valSet.addAll(coValSet);
			}

			File file = new File("validation.txt");
			BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
					new FileOutputStream(file)));
			Map<String,Integer> headlineCount = new HashMap<String,Integer>();
			Map<String,Double> totalPctChange = new HashMap<String,Double>();
			
			for (Headline headline : valSet) {
				String text = headline.getText();
				Integer count = headlineCount.get(text);
				Double pctChange = totalPctChange.get(text);
				Date date = headline.getDate();
				String stock = headline.getStock();
				StockPrice stockPrice = stockTrends.get(stock).get(
						StockUtil.getNextTradingDay(date));
				double pctPriceChange;
				if (stockPrice == null) {
					pctPriceChange = 0.0;
				} else {
					pctPriceChange = StockUtil.getPercentChange(stockPrice);
				}
				if (count == null) {
					headlineCount.put(text, 1);
					totalPctChange.put(text, pctPriceChange);
				} else {
					headlineCount.put(text, count+1);
					totalPctChange.put(text, pctChange + pctPriceChange);
				}
			}
			
			Set<String> processedSet = new HashSet<String>();
			DecimalFormat decFmt = new DecimalFormat("###0.0000");
			for (Headline headline : valSet) {
				String text = headline.getText();
				if (processedSet.contains(text)) {
					continue;
				}
				processedSet.add(text);
				int id = headline.getId();
				String stock = headline.getStock();
				Date date = headline.getDate();
				String dateFormatted = dateFmt.format(date);
				
				double totalPriceChange = totalPctChange.get(text);
				int totalCount = headlineCount.get(text);
				StringBuilder sb = new StringBuilder();
				sb.append(id);
				sb.append(", ");
				sb.append(stock);
				sb.append(", ");
				sb.append(dateFormatted);
				sb.append(", ");
				sb.append(decFmt.format(totalPriceChange/totalCount));
				sb.append(", ");
				
				text = text.replaceAll(
						"[\'\";:,\\]\\[]", " ");
				text = text.replaceAll(
						"[^A-Za-z0-9 ]", "");
				sb.append(text);
				
				sb.append("\n");
				writer.write(sb.toString());
			}
			writer.close();
		} catch (FileNotFoundException fnfe) {
			System.out.println("Stock symbol CSV file does not exist: "
					+ stockSymbolsCSV);
			System.exit(STOCK_SYMBOL_CSV_NOT_FOUND);
		} catch (IOException ioe) {
			System.out.println("Stock symbol CSV file does not exist: "
					+ stockSymbolsCSV);
			System.exit(IO_EXCEPTION);
		}
	}

	private List<Company> getFortune50(File csvFile)
			throws FileNotFoundException, IOException {
		List<Company> fortune50 = new ArrayList<Company>();
		FileInputStream fis = new FileInputStream(csvFile);
		InputStreamReader reader = new InputStreamReader(fis);
		BufferedReader buf = new BufferedReader(reader);
		String csvline = null;
		while ((csvline = buf.readLine()) != null) {
			if (csvline.length() == 0) {
				continue;
			}
			String[] fields = csvline.split(",");
			if (fields.length != 3) {
				throw new RuntimeException(
						"Badly formatted csv file name (3 values expected): "
								+ csvline);
			}
			int id = Integer.valueOf(fields[0]);
			fortune50.add(new Company(id, fields[1], fields[2]));
		}
		return fortune50;
	}
}
