/*********************************************************************
 * This file is part of the cpplibs suite.
 *
 * Copyright (C) 2001 Topi Mäenpää
 * All rights reserved.
 *
 * This program is free software. You can redistribute and/or modify
 * it under the terms of the free software licence found in the
 * accompanying file "COPYING". The licence terms must always be
 * redistributed with this source file. The above copyright notice
 * must be reproduced in all modified and unmodified copies of this
 * source file.
 *
 * $Revision: 1.7 $
 *********************************************************************/

#include "Properties.h"

#include <fstream>
#include <sstream>
#include <StreamTokenizer.h>
#include "Util.h"
#include "String.h"

using namespace std;
using namespace util::io;

namespace util
{
	typedef StreamTokenizer::Token Token;
	typedef StreamTokenizer::SectionToken SectionToken;
	typedef StreamTokenizer::WordToken WordToken;
	typedef StreamTokenizer::NormalToken NormalToken;
	typedef StreamTokenizer::NumberToken NumberToken;

	Properties::Properties(istream& in, bool relaxed) throw (IOException&)
	{
		StreamTokenizer tokenizer;

		if (!relaxed)
			{
				try
					{
						do
							{
								int type;
								Token* token = NULL;
								do
									{
										delete token;
										token = tokenizer.getNextToken(in);
										type = token->getType();
									} while (type == TOKEN_SECTION && ((SectionToken*)token)->getName() == "comment");
								if (type != TOKEN_WORD && type != TOKEN_NORMAL)
									{
										delete token;
										throw IOException("Properties::Properties(istream&,bool): Invalid property name");
									}
								string propertyName;
								if (type == TOKEN_WORD)
									propertyName = ((WordToken*)token)->getWord();
								else
									propertyName += ((NormalToken*)token)->getCharacter();

								delete token;
								token = tokenizer.getNextToken(in);
								type = token->getType();
								if (type != TOKEN_NORMAL || ((NormalToken*)token)->getCharacter() != '=')
									{
										delete token;
										throw IOException("Properties::Properties(istream&,bool): Missing an equality sign.");
									}
								delete token;
								token = tokenizer.getNextToken(in);
								type = token->getType();
								string tmp;
								switch (type)
									{
									case TOKEN_SECTION:
										if (((SectionToken*)token)->getName() != "string")
											throw IOException("Properties::Properties(istream&,bool): Invalid property name.");
										put(propertyName,String::substitute(((SectionToken*)token)->getContents(),*this));
										break;
									case TOKEN_WORD:
										put(propertyName,((WordToken*)token)->getWord());
										break;
									case TOKEN_NUMBER:
										put(propertyName,((NumberToken*)token)->getNumberString());
										break;
									case TOKEN_NORMAL:
										tmp += ((NormalToken*)token)->getCharacter();
										put(propertyName,tmp);
										break;
									default:
										delete token;
										throw IOException("Properties::Properties(istream&,bool): Not a valid property stream.");
									}
								delete token;
								token = tokenizer.getNextToken(in);
								type = token->getType();
								if (type != TOKEN_NORMAL || ((NormalToken*)token)->getCharacter() != ';')
									{
										delete token;
										throw IOException("Properties::Properties(istream&,bool): Missing a semicolon.");
									}
							} while (true);
					}
				catch (EOFException& eofe)
					{
					}

			}
		else
			{
				try
					{
						do
							{
								stringbuf strbuf;
								in.get(strbuf);
								if (!in) break;
								string line(strbuf.str());
								int len = line.size();
								int i=0;
								for (;i<len && isspace(line[i]); i++);
								if (i>=len || line[i] == '#') continue;
								string propertyName;
								while (i<len &&
											 isalnum(line[i]))
									propertyName += line[i];
								if (propertyName.size() == 0) continue;
								for (;i<len && isspace(line[i]); i++);
								if (line[i] == '=' || line[i] == ':' || line[i] == '-')
									for (i++;i<len && isspace(line[i]); i++);
								string propertyValue;
								if (i<len)
									propertyValue = line.substr(i);
								put (propertyName,propertyValue);
							} while (true);
					}
				catch (EOFException& eofe)
					{
					}
			}
	}
}
