#include <iostream>
#include <sstream>

#include "Parser.h"

using namespace std;
int Parser::_lineNumber = 0;
char Parser::comment = ';';
char Parser::open = '(';
char Parser::close = ')';

List *Parser::parse(std::string filename)
{
	ifstream in(filename.c_str());
	return parse(in);
}

List *Parser::parse(std::istream& in)
{
	_lineNumber = 0;
	getNext(in);
	return parseOpen(in);
}

List *Parser::parseOpen(std::istream &in)
{
	List *newList = new List(_lineNumber);
	string next = getNext(in);
	while(next[0] != close) {
		if(next[0] == open)
			newList->snoc(parseOpen(in));
        else
		    newList->snoc(new Atom(string(next),_lineNumber));
		next = getNext(in);
	}
	return newList;
}

std::string Parser::getNext(std::istream& in)
{	
	consumeWhitespaceAndComments(in);

	if(in.eof() || in.fail())
		return "";

	string next;
	char c;

	in.get(c);
	do {
		if(c == '"')
			return readString(in);

		next += c;
		if(c == open || c == close) {
			in.get(c);
			break;
		}

		if(in.eof() || in.fail())
			return next;

		in.get(c);
	} while(!isspace(c) && c!= comment && c != open && c != close);

	in.putback(c);

	return next;
}

void Parser::consumeWhitespaceAndComments(std::istream& in)
{

	char c;

	in.get(c);
	while(isspace(c) || c == comment) {
		if(in.eof() || in.fail())
			break;
		if(c == '\n')
			_lineNumber ++;
		if(c == comment) {
			while(c != '\n') {
				if(in.eof())
					break;
				in.get(c);
			}
			_lineNumber++;
		}
		in.get(c);
	}

	in.putback(c);
}

std::string Parser::wordWrap(std::string &strText, int chars)
{
	stringstream text(strText + ")");
	stringstream line;

	string next = getNext(text);

	if(next != "" || !text.eof()) {
		do {
			line << next;
			next = " " + getNext(text);
		}
		while(line.str().size() + next.size() < chars && next != " )" && text.str() != "");
	}

	if(line.str().size() == strText.size())
		strText = "";
	else
		strText = strText.substr(line.str().size()+1,strText.size() - line.str().size());

	return line.str();
}

std::string Parser::readString(std::istream& in)
{
	string next;
	char c;
	in.get(c);
	while(c != '"') {
		next += c;
		in.get(c);
	}

	return next;
}