/*=============================================================================
    Copyright (c) 2002-2004 Joel de Guzman
    http://spirit.sourceforge.net/

    Use, modification and distribution is subject to the Boost Software
    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
    http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>
#include "simple_cpp_lexer.hpp"

//  C++ Source to HTML converter
//
//  JDG 9/01/2002:  original code
//  JDG 2/01/2004:  tweaks + incorporated Boris Kolpackov's additions
//
//  Boris Kolpackov made some enhancements to cpp_to_html example so that it
//  can be used in real-world applications (as part of documentation
//  generation) Notably the following options were added:
//
//  -o <out-file>         to specify resulting file
//  -t <title>            to specify title
//  -css <css-file>       to specify css file other than default

using namespace std;
using namespace boost::spirit;
using namespace boost::spirit::repository;

namespace
{

	struct process
    {
		process(ostream& out,std::vector<string>& list)
            : out(out) , name(name),list(list){};

        template <typename IteratorT>
        void operator()(IteratorT first, IteratorT last) const
        {
			std::stringstream _str;
			bool b = true;

			if(list.size() > 0)
			{
				if((*(list.end() - 1)) == "#include" 
					|| (*(list.end() - 1)) == "#import" 
					|| (*(list.end() - 1)) == "L")
				{
					b = false;
				}
			
			}
			
			if(list.size() > 1)
			{
				string a = (*(list.end() - 2)) + (*(list.end() - 1));
				if( a == "_T(" )
				{
					b = false;
				}
			}

			if(b){
				out << "_T(";
			}

			while (first != last){
				_str << *first;
                out << *first++;
			}

			list.push_back(_str.str());
		
			if(b){
				out << ")";
			}

        }

        ostream& out;
		string name;
		vector<string>& list;
    };

	struct none
    {
        none(ostream& out,std::vector<string>& list,bool add = true)
            : out(out) ,name(name),list(list) { badd_list = add;};

        template <typename IteratorT>
        void operator()(IteratorT first, IteratorT last) const
        {
			std::stringstream _str;
			while (first != last){
                _str << *first;
				out << *first++;
			}

			if(badd_list){
				list.push_back(_str.str());
			}
        }

        ostream& out;
		std::string name;
		vector<string>& list;
		bool badd_list;

    };

    struct unexpected_char
    {
        unexpected_char(ostream& out)
        : out(out) {};

        template <typename CharT>
        void operator()(CharT ch) const
        {
            out << ch; // print out an unexpected_char character
        }

        ostream& out;
    };

    struct cpp_to_html_actions
    {
        cpp_to_html_actions(ostream& out)
            : preprocessor(out,list)
            , comment(out,list,false)
            , keyword(out,list)
            , identifier(out,list)
            , special(out,list)
            , string(out,list)
            , literal(out,list)
            , number(out,list)
            , unexpected(out)
        {};

        none
            preprocessor, comment, keyword, identifier,
            special, number;
		process literal,string;
        unexpected_char unexpected;
		vector<std::string> list;
    };
}

///////////////////////////////////////////////////////////////////////////////
//
//  Parse a file
//
///////////////////////////////////////////////////////////////////////////////
static int
parse(istream& in,
      ostream& out)
{
    in.unsetf(ios::skipws); //  Turn of white space skipping on the stream

    vector<char> vec;
    std::copy(
        istream_iterator<char>(in),
        istream_iterator<char>(),
        std::back_inserter(vec));

    vector<char>::const_iterator first = vec.begin();
    vector<char>::const_iterator last = vec.end();

    cpp_to_html_actions actions(out);
    simple_cpp_lexer<cpp_to_html_actions> p(actions);
    parse_info<vector<char>::const_iterator> info =
        parse(first, last, p);

    if (!info.full)
    {
        cerr << "parsing error\r\n";
        cerr << string(info.stop, last);
        return -1;
    }

    return 0;
}

///////////////////////////////////////////////////////////////////////////////
//
//  Main program
//
///////////////////////////////////////////////////////////////////////////////
int
main(int argc, char* argv[])
{
    string in_file;
    string out_file;
    string title;

	string option;

    string usage =
        string ("usage: ")
        + argv[0]
        + " [-o <out-file>]"
        + " [<in-file>]";

    for (int i = 1; i < argc; i++)
    {
        if (!option.empty())
        {
            if (option == "-o") out_file = argv[i];
            else
            {
                cerr << "Unknown option \'" << option << "\'" << endl
                         << usage << endl;
                return -1;
            }
            option.clear ();
            continue;
        }

        if (argv[i] == string ("-o"))
        {
            option = argv[i];
        }
        else
        {
            if (in_file.empty())
            {
                in_file = argv[i];
            }
            else
            {
                cerr << "Unexpected argument \'" << argv[i] << "\'" << endl
                         << usage << endl;
                return -1;
            }
        }
    }

    string in_file_name;
    string::size_type pos = in_file.find_last_of("\\/");
    if (pos != string::npos)
    {
        in_file_name.assign(in_file, ++pos, in_file.size () - pos);
    }
    else
    {
        in_file_name = in_file;
    }

    if (out_file.empty() && !in_file.empty())
    {
        string::size_type pos = in_file.find_last_of('.');
        out_file.assign(in_file, 0, pos);
        out_file += ".tmp";
    }

    if (title.empty())
        title = in_file_name;

    ifstream ifs;

    if (!in_file.empty())
    {
        ifs.open(in_file.c_str());
        if (!ifs)
        {
            cerr << "Unable to open input file: " << in_file << endl;
            return -1;
        }
    }

    istream& in = ifs.is_open() ? (istream&) ifs : (istream&) cin;
    ofstream ofs;

    if (!out_file.empty())
    {
        ofs.open(out_file.c_str());
        if (!ofs)
        {
            cerr << "Unable to open output file: " << out_file << endl;
            return -1;
        }
    }

    ostream& out = ofs.is_open() ? (ostream&)ofs : (ostream&)cout;
    
	parse(in, out);
	
	if(ifs.is_open())
	{
		ifs.close();
	}

	if(ofs.is_open())
	{	
		ofs.close();
	}
	
	// テンポラリからファイルへコピーする
}