#include <iostream>
#include <iterator>
#include <vector>
#include <string>

// Spirit のコードをインクルード (必要なものだけ)
#include <boost/spirit/core.hpp>
#include <boost/spirit/iterator/file_iterator.hpp>

using namespace std;
using namespace boost::spirit;

// エラー位置を検出するための行情報
template<typename IteratorT>
struct LineInfo {
    IteratorT lineIter;
    size_t lineNum;

    LineInfo( IteratorT beg ) : lineIter(beg), lineNum(1) { }
};

// 改行コードがあったら行情報を更新するファンクタ
template<typename IteratorT>
struct NewLine {
    LineInfo<IteratorT>& lineInfo;
    NewLine( LineInfo<IteratorT>& info ) : lineInfo(info) { }

    void operator()(IteratorT first, IteratorT last) const {
        lineInfo.lineIter = last;
        lineInfo.lineNum++;
    }
};

// 値をベクタにコピーする Semantic Action
// 組み込みの append と同じような処理をしている(と思う)が、ここでは、
// ダブルクォートが重なっていたら、1つに落とすという処理が追加されている
struct AddVal {
    vector<string>& values;
    AddVal( vector<string>& vec ) : values(vec) { }

    template<class IteratorT>
    void operator()(IteratorT first, IteratorT last) const { // const が重要
#ifdef _MSC_VER
        // なぜか VC6 だとコンストラクタによる初期化がうまくいかない
        string s;
        s.resize(distance(first, last));
        for (size_t i = 0; first != last; ++i) {
            s[i] = *first++;
        }
#else
        string s( first, last );
#endif
        string::size_type pos = 0;
        while (1) {
            pos = s.find("\"\"", pos);
            if (pos == string::npos)
                break;
            ++pos;
            s.erase(pos, 1);
        }
        values.push_back(s);
    }
};

// csv パーザ
template<class IteratorT>
struct CSVParser : public grammar<CSVParser<IteratorT> > {
    vector<string>& v;
    LineInfo<IteratorT>& lineInfo;

    CSVParser( vector<string>& vec, LineInfo<IteratorT>& info ) : v(vec), lineInfo(info) { }

    template <typename ScannerT>
    struct definition {
        rule<ScannerT> csv, val, quoted_val, naked_val;

        definition(const CSVParser<IteratorT>& self)
        {
            csv = val >> *(',' >> val) >>
                 (eol_p[NewLine<IteratorT>(self.lineInfo)] | end_p);

            val = *blank_p >>
                  ch_p('\"') >> quoted_val[AddVal(self.v)] >> ch_p('\"') >>
                  *blank_p
                | naked_val[AddVal(self.v)];

            quoted_val = *(eol_p[NewLine<IteratorT>(self.lineInfo)]
                           | ~ch_p('"') | str_p("\"\""));

            naked_val = *(~ch_p(',') & ~ch_p('\"') & ~ch_p('\n'));
        }

        const rule<ScannerT>& start() const { return csv; }
    };
};

// パーザ呼び出し用のラッパ関数
template<typename IteratorT>
parse_info<IteratorT>
parse_csv( const IteratorT& first, const IteratorT& last,
           vector<string>& vec, LineInfo<IteratorT>& info )
{
    CSVParser<IteratorT> csv(vec, info);

    return parse(first, last, csv);
}

// ファイルからcsvデータを読み出して表示する例
int main( int argc, char** argv)
{
    if (argc != 2) return 1;

    // Spirit は forwardイテレータを要求するので、ifstream では力不足。
    // そのため spirit が用意している file_iterator を使う。
    typedef file_iterator<char> iterator_t;

    // ファイルを開いて、その先頭を指すイテレータを生成
    iterator_t begin(argv[1]);
    if (!begin) {
        cout << "Unable to open file: " << argv[1] << endl;
        return -1;
    }

    // 先頭を指すイテレータを複製
    iterator_t first = begin;
    // 終端を指すイテレータを生成
    iterator_t last = first.make_end();

    LineInfo<iterator_t> line_info( begin );
    while ( first != last ) {
        vector<string> v;
        parse_info<iterator_t> info = parse_csv( first, last, v, line_info );

        if (!info.hit) {
            cout << "Error!!  Line: " << line_info.lineNum
                 << ", Column: " << distance(line_info.lineIter, info.stop)+1 << endl;
            break;
        }

        cout << "Parses OK:" << endl;
        for (vector<string>::size_type i = 0; i < v.size(); ++i)
            cout << i+1 << ": " << v[i] << endl;

        cout << "-------------------------\n";

        // 次の解析位置を設定
        first = info.stop;
    }

    return 0;
}



