// ---------------------------------------------------------------------------
// 
//   Lily Engine alpha
// 
//   Copyright (c) 2010 Clifford Jolly
//     http://cliffjolly.com
//     cliff@cliffjolly.com
// 
// ---------------------------------------------------------------------------
// 
//   This program is free software; you can redistribute it and/or modify
//   it under the terms of the GNU General Public License as published by
//   the Free Software Foundation; either version 2 of the License, or
//   (at your option) any later version.
//  
//   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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
//   USA
// -------------------------- END HEADER -------------------------------------

#include "../hacks/toolhacks.h"

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;

#include "../filesystem/filesystem.h"
#include "../string/string.h"

const char *headerMarker =
	"// -------------------------- END HEADER -------------------------------------";

// List of file we definitely do NOT WANT TO FUCK WITH THE HEADERS
// ON. Was TinyXML. But everything in "3rdparty" is excluded too.
const char *excludedFiles[256] = {
	"SDLMain.h",
	NULL
};

bool strCompareIgnoreWindowsBullshit(const string &str1, const string &str2) {

	unsigned int i = 0;
	unsigned int j = 0;

	// Go through until one of the strings ends.

	while(i < str1.size() && j < str2.size()) {

		if(str1[i] == '\r') {
			i++;
			continue;
		}

		if(str2[j] == '\r') {
			j++;
			continue;
		}

		if(str1[i] != str2[j]) return false;

		i++;
		j++;
	}

	// Reached the end of at least one of the strings. Go through the
	// end of the other and make sure there's nothing but '\r'.

	while(i < str1.size() || j < str2.size()) {

		if(i < str1.size()) {
			if(str1[i] != '\r') return false;
			i++;
		}

		if(j < str2.size()) {
			if(str2[j] != '\r') return false;
			j++;
		}

	}

	// If we made it this far, we're good.

	return true;
}

void stripOldHeader(vector<string> &lines) {

	int headerEndLine = -1;
	bool foundHeader = false;

	for(unsigned int i = 0; i < lines.size(); i++) {
		
		if(foundHeader) {

			// Found the header, pull out extra whitespace.

			if(strCompareIgnoreWindowsBullshit(lines[i], "")) {

				headerEndLine = i;

			} else {

				// Done. Found some code.

				break;
			}

		} else if(strCompareIgnoreWindowsBullshit(lines[i], headerMarker)) {

			// Still looking for header.

			headerEndLine = i;
			foundHeader = true;
		}

	}

	if(headerEndLine != -1) {
		lines.erase(lines.begin(), lines.begin() + headerEndLine + 1);
	}

	// Attempt to unfuck all my source after this program screwed up.
	//for(unsigned int i = 0; i < lines.size(); i++) {
	//	if(strCompareIgnoreWindowsBullshit(lines[i], headerMarker)) {
	//		lines.erase(lines.begin() + i);
	//		i--;
	//	}
	//}

}

vector<string> loadLinesFromFile(const string &fileName) {

	int length;
	char *rawContents = FileSystem::loadFile(fileName, &length, true);
	vector<string> lines;
	stringTokenize(rawContents, "\n", lines, true);

	delete[] rawContents;

	return lines;
}

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

	if(argc < 2) {
		cout << "Usage: " << argv[0] << " <header file name> <source files>" << endl;
		return 1;
	}

	vector<string> headerLines = loadLinesFromFile(argv[1]);

	ostringstream headerConvertedStr;

	for(unsigned int j = 0; j < headerLines.size(); j++) {
		headerConvertedStr << "// " << headerLines[j] << endl;
	}

	for(int i = 2; i < argc; i++) {

		string fileName = argv[i];

		if(!FileSystem::fileExists(fileName)) {
			cout << "File " << fileName << " does not exist!" << endl;
			return 1;
		}

        string skipReason;

        // Check list of explicitly excluded files.
		string base = FileSystem::getBaseName(fileName);
		int k = 0;
		bool skipThisFile = false;
		while(excludedFiles[k]) {
			if(base == string(excludedFiles[k])) {
				skipThisFile = true;
                skipReason = "Explicitly excluded by name";
				break;
			}
			k++;
		}

        if(!skipThisFile) {

            // Check to make sure it's not in the "3rdparty" directory.
            string normalized = FileSystem::fixFileName(fileName);
            vector<string> fileNameParts;
            stringTokenize(normalized, "/", fileNameParts);
            const string excludedDirectory = "3rdparty";
            for(unsigned int j = 0; j < fileNameParts.size(); j++) {
                if(fileNameParts[j] == excludedDirectory) {
                    skipThisFile = true;
                    skipReason = "Third party system";
                    break;
                }
            }
        }

		if(skipThisFile) {

			cout << "Skipping " << fileName << " on purpose: " << skipReason << endl;

		} else {

			cout << "Updating " << fileName << "..." << endl;
		
			ostringstream outputStr;

			vector<string> fileLines = loadLinesFromFile(fileName);

			stripOldHeader(fileLines);

			// Add header.
			outputStr << headerConvertedStr.str();

			// Header end. (With extra line for niceness.)
			outputStr << headerMarker << endl << endl;

			for(unsigned int j = 0; j < fileLines.size(); j++) {

				// Add each line.
				outputStr << fileLines[j] << endl;
			}

			string finalOut = outputStr.str();

			//cout << outputStr.str() << endl;
			//FileSystem::renameFile(fileName, fileName + ".bak");
			FileSystem::saveFile(fileName, finalOut.c_str(), finalOut.size(), false);
		}
		
	}

	return 0;
}
