/*=============================================================================
    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"
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.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;
using namespace boost::filesystem;
void parse(path& dir);

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;
    };
}

///////////////////////////////////////////////////////////////////////////////
//
//  Main program
//
///////////////////////////////////////////////////////////////////////////////
int
main(int argc, char* argv[])
{

    string in_file;
    string out_file;
    string title;

	string option;

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

	if(argc == 1)
	{
		cerr << usage << endl;
		exit(-1);
	}

	path _path(argv[1],boost::filesystem::native);
	parse(_path);
}

void parse(path& dir)
{
	if(is_directory(dir))
	{
		// ディレクトリの場合
		directory_iterator it(dir);
		directory_iterator end;

		// ディレクトリの中身をすべて変換
		for(;it != end;++it)
		{
			path _path = *it;
			parse(_path);
		}

	} else 	{
		// ファイルの場合
		if(extension(dir) == ".cpp" || extension(dir) == ".hpp" || extension(dir) == ".h")
		{
			ifstream in(complete(dir).native_file_string().c_str());
			ofstream out;
			out.open(complete(change_extension(dir,string("tmp"))).native_file_string().c_str(),
				ios_base::out | ios_base::trunc);

			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);
				exit(-1);
			}

			in.close();
			out.close();
			// ファイルのコピー
			boost::filesystem::remove(dir);
			copy_file(change_extension(dir,"tmp"),dir);
			boost::filesystem::remove(change_extension(dir,"tmp"));
		}
	}
}