/*
 *  ADP (Another Data Processor) www.adp.la
 *  Copyright (C) 2010 Katsuhisa Ohfuji <katsuhisa@ohfuji.name>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  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
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *  MA 02110-1301, USA.
 */

#ifndef __KZ_READCSV__
#define __KZ_READCSV__
/**********************************************************************
 CSVファイルの読み込み
 試したコンパイル環境
    VC++ .NET 2003 / WINDOWS XP Professional 64 bit edition.
    GCC C++ 3.3.6 / glibc 2.3.4 / Vine Linux 4.2
**********************************************************************/

#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>

/**********************************************************************
 クオート文字の定義構造体
**********************************************************************/
struct quote{
	char	start;	// 開始文字
	char	end;	// 終了文字
	char	escape;	// エスケープ文字
	quote( char start_, char end_, char escape_) :
		 start(start_), end(end_), escape(escape_) {}
};

struct cmpStartQuote : public std::binary_function<quote,char,bool> {
	bool operator()(const quote &l_s1, const char &l_s2) const {
		return l_s1.start == l_s2;
	}
};

/**********************************************************************
 CSVの読取
**********************************************************************/
inline bool readCSV(
	std::vector< std::string > &result,		// 結果格納ベクター
	std::istreambuf_iterator<char> &i,		// 入力文字イテレータ
	std::string &separator,					// 区切り文字
	std::vector<quote> &quotes)				// クオート文字ベクター
{
	if ( i == std::istreambuf_iterator<char>() ) {
		return false;
	}
	result.clear();
	std::string	item;
	char	bc = '\0';
	bool	first = true;
	std::vector<quote>::iterator	ff = quotes.end();

	while ( i != std::istreambuf_iterator<char>() && 
					(ff != quotes.end() || *i != '\n') ) {
		if ( ff == quotes.end() && 
							strchr( separator.c_str(), *i) != 0 ) {
			result.push_back(item);
			item.clear();
			first = true;
		} else {
			if ( first && 
				(ff = find_if( quotes.begin(), 
							quotes.end(), 
							bind2nd( cmpStartQuote(), *i))) 
					!= quotes.end() ) {
				first = false;
			} else if ( ff != quotes.end() && ff->end == *i ) {
				if ( ff->end == ff->escape ) {
					bc = *i++;
					if ( i == std::istreambuf_iterator<char>() ) 
						break;
					if ( *i == ff->end ) {
						item.push_back(*i);
					} else {
						ff = quotes.end();
						continue;
					}
				} else {
					if ( bc == ff->escape ) {
						item.push_back(*i);
					} else {
						ff = quotes.end();
					}
				}
			} else {
				item.push_back(*i);
				first = false;
			}
		}
		bc = *i++;
	}
	result.push_back(item);
	if ( i != std::istreambuf_iterator<char>() ) {
		i++;
	}
	return true;
}

#endif
