/*
    Copyright (C) 2012 Bartosz Broda, Jacek Bochenek, Łukasz Biłeńkij, 
    Damian Jaworski, Wojciech Mazur, Dominik Piasecki, Maciej Piasecki, 
    Radosław Ramocki
    
    This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option)
any later version.

    This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. 

    See the LICENSE and COPYING files for more details.
*/

#include "config.h"
#include <boost/program_options.hpp>
#include <iostream>
#include <fstream>
#include <sstream>

#include <boost/algorithm/string.hpp>

#include <boost/foreach.hpp>

#include <libwccl/parser/Parser.h>

namespace builder{

	void config::parse_operator(Operator & oper, const std::string & filename) const
	{		
		std::ifstream in(filename.c_str());
		if(!in)
			throw std::runtime_error("Cannot open file for reading: " + filename);


		std::string line;
		// parse header: relation_name;posrow1:posrow2:...;poscol1:poscol2:...
		std::getline(in, line);
		std::vector<std::string> tokens;
		boost::algorithm::split(tokens, line, boost::is_any_of(";"));
		if(tokens.size() != 3)
			throw std::runtime_error("Mismatched first line of operator: " + line);

		oper.relation_name = tokens[0];
		std::string row_poses = tokens[1];
		std::string col_poses = tokens[2];
		boost::algorithm::split(tokens, row_poses, boost::is_any_of(":"));
		BOOST_FOREACH (std::string pos, tokens)
			oper.row_poses.insert(pos);
		boost::algorithm::split(tokens, col_poses, boost::is_any_of(":"));
		BOOST_FOREACH (std::string pos, tokens)
			oper.operator_poses.insert(pos);

		
		// read rest of document
		std::stringstream ss;
		while( std::getline(in, line))
			ss << line << std::endl;
		
		static Wccl::Parser parser(tagset);
		oper.proper_operator = parser.parseBoolOperator(ss.str());
	}

	config config::parse_args(int ac, char **av)
	{
		namespace po = boost::program_options;

		config cfg;

		po::options_description cmdline("Command line only options", 100);
		po::options_description basic("Basic options", 100);
		std::string configfile;
		std::vector<std::string> opfiles;

		cmdline.add_options()
			("help", "Prints this message")
			("cfg-file", po::value<std::string>(&configfile)->default_value(std::string("builder.cfg")),
				"Optional config file")
			;
		basic.add_options()
			("tagset,t", po::value<std::string>(&cfg.tagset)->default_value("kipi"),
				"Name of a tagset")
			("reader,r", po::value<std::string>(&cfg.reader_class), "Name of a reader")
			("corpus,c", po::value<std::vector<std::string> >(&cfg.corpora)->multitoken(), "Path(s) to corpus")
		        ("operator,w", po::value<std::vector<std::string> >(&opfiles)->multitoken(), "File(s) with WCCL operator")
			("outfile,o", po::value<std::string>(&cfg.outfile)->default_value("out.csv"),
				"Path for file with results")
			("append-pos,a", po::value<bool>(&cfg.append_pos)->default_value(false),
				"If true then lemmas will be prefixed with POS")
			;

		po::options_description all("",80);
		all.add(cmdline).add(basic);

		po::variables_map vm;
		po::store(po::parse_command_line(ac, av, all), vm);
		po::notify(vm);

		if( vm.count("help" ) )
		{
			std::cout << "Builder by Bartosz Broda, bartosz.broda@gmail.com\n";
			std::cout << "Builds a matrix using wccl operators\n";
			std::cout << all << std::endl;
			exit(0);
		}

		std::ifstream cfgfile( configfile.c_str() );

		if(cfgfile)
		{
			po::store(po::parse_config_file(cfgfile, basic), vm);
			po::notify(vm);
		}
		else if( vm.count("cfg-file") )
			std::cout << "Cannot open config file " << configfile << ". Proceeding with commandline and defaults...\n";

		if(! vm.count("operator"))
		{
			std::cerr << "You need to specify operator" <<  std::endl;
			exit(1);
		}
		if(! vm.count("reader"))
		{
			std::cerr << "You need to specify reader" <<  std::endl;
			exit(1);
		}
		if(! vm.count("corpus"))
		{
			std::cerr << "You need to specify at least one corpus" <<  std::endl;
			exit(1);
		}
		
		cfg.operators.resize(opfiles.size());
		for (unsigned i = 0; i < opfiles.size(); ++i)
			cfg.parse_operator(cfg.operators[i], opfiles[i]);


		return cfg;
	}
}//namespace builder
