/*
    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 "liner.h"
#include <boost/foreach.hpp>
#include <boost/tokenizer.hpp>
#include <boost/lexical_cast.hpp>
#include <sys/wait.h>
#include <cstdio>
#include <iostream>
#include <utility>

namespace Corpus2{
	Liner::Liner(std::string model, std::string nerd,std::string linpath,std::string linfile)
	{
		model_file = model;
		nerd_path = nerd;
		liner_path = linpath;
		liner_file = linfile;
	}
	Liner::~Liner()
	{
		close_liner();
	}

	void Liner::run_liner()
	{
		if(pipe(commpipe))
		{
			throw std::runtime_error("Problem when starting liner - Pipe error!\n");
		}
		if(pipe(commpipe2))
		{
			throw std::runtime_error("Problem when starting liner - Pipe error!\n");
		}
		if( (pid=fork()) == -1)
		{
			throw std::runtime_error("Problem when starting liner - Fork error!\n");
		}

		if(pid)
		{
			close(commpipe[0]);
			setvbuf(stdout,(char*)NULL,_IONBF,0);
			dup2(commpipe2[0],0);
			close(commpipe2[1]);
		}
		else
		{
			dup2(commpipe[0],0);
			close(commpipe[1]);
			dup2(commpipe2[1],1);
			close(commpipe2[0]);
			setvbuf(stdout,(char*)NULL,_IONBF,0);

			std::string params = "batch -o tokens -silent -nerd "+nerd_path+" -ini "+model_file;
			char *str =new char[params.length()+1];
			strcpy(str,params.c_str());

			std::string tmp = liner_path+"/"+liner_file;
			char *str2 =new char[tmp.length()+1];
			strcpy(str2,tmp.c_str());

			char *str3 =new char[liner_file.length()+1];
			strcpy(str3,liner_file.c_str());

			if(execl(str2,str3,str,NULL) == -1)
			{
				throw std::runtime_error("Liner cannot start, path:" + tmp +";"+liner_file);
			}
			delete [] str;
			delete [] str2;
			delete [] str3;
		}
	}
	void Liner::close_liner(void)
	{
		int rv;
		write(commpipe[1], "EOF\n", 4);
		wait(&rv);
	}
	void Liner::reset_liner(void)
	{
		int status;
		std::cin.ignore(std::numeric_limits<std::streamsize>::max());
		std::cin.clear();
		kill(pid,SIGTERM);
		wait(&status);
		close(commpipe[0]);
		close(commpipe[1]);
		close(commpipe2[0]);
		close(commpipe2[1]);
		run_liner();
	}
	std::string Liner::do_liner(std::string sentence)
	{
		sentence+="\n";
		char *str =new char[sentence.length()+1];
		strcpy(str,sentence.c_str());
		write(commpipe[1], str, strlen(str));
		delete [] str;
		std::string text;
		std::cin>>text;
		return text;
	}

	bool Liner::tupleComp (const linerTuple& i, const linerTuple& j)
	{
	   return (i.first.first < j.first.first);
	}

	std::vector<Liner::linerTuple> Liner::process_liner_output(std::string liner_string)
	{
		std::vector<linerTuple> tuples;
		if(liner_string.compare("NONE")==0)
			return tuples;
		std::vector<linerTuple> tempTuples;
		std::vector<linerTuple>::iterator t_it;
		linerTuple temp;
		boost::char_separator<char> sep("[]\n");
		boost::char_separator<char> sep2(",");
		boost::tokenizer<boost::char_separator<char> > tokens(liner_string,sep);
		BOOST_FOREACH(std::string t, tokens)
		{
			boost::tokenizer<boost::char_separator<char> > tokens2(t, sep2);
			boost::tokenizer<boost::char_separator<char> >::iterator it=tokens2.begin();
			temp.first.first = boost::lexical_cast<int>(*(it++));
			temp.first.second = boost::lexical_cast<int>(*(it++));
			temp.second=*it;
			tempTuples.push_back(temp);
		}
		sort(tempTuples.begin(),tempTuples.end(),tupleComp);

		BOOST_FOREACH(linerTuple lt, tempTuples)
		{
			t_it=tuples.begin();
			int add=1;
			while(t_it!=tuples.end())
			{
				if(((*t_it).first.first==lt.first.first&&(*t_it).first.second<lt.first.second))
				{
					t_it=tuples.erase(t_it);
					break;
				}
				if(lt.first.first<=(*t_it).first.second)
				{
					add=0;
					break;
				}
				++t_it;
			}
			if(add)
				tuples.push_back(lt);
		}
		return tuples;
	}
}


