
/*
 * jwm-menu generator
 * copyright Israel Dahl 2015
 * GPL3 license
 * 
 * But whoso keepeth his word,
 * in him verily is the love of God perfected:
 * hereby know we that we are in him.
 * 
 * 1John2:5 KJV Public Domain
 * 
 */

/*
TODO
pugixml...
add global var vector for changed files.
Then check if is cached and then add in via pugixml the new entry. into the right place (how?)
This should cut regen time down significantly...
*/

#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <list>
#include <sys/stat.h>
#include <sys/types.h>
#include <algorithm>
#include <float.h>
#include <sstream>
#include <float.h>
#include <dirent.h>
#include <sys/stat.h>
#include <langinfo.h>
#include "../include/common.hpp"
#include "../include/pugixml.hpp"

//global variables
std::string MENU_CACHE_FILE;
std::string MENU_TO_MERGE;
bool RELOAD;
bool USECOMMENTS;
// this variable helps me know how deep I am in the menu :D
bool INCEPTION;
bool MERGE_inception;
bool ONLY_UNALLOCATED;
int MERGEFILES;
int MERGEMENUS;
//pugi
pugi::xml_document doc;
pugi::xml_document cache;
//vector
std::vector<std::string> MENU_NAMES;
std::vector<pugi::xml_node> MENU_NODES;
std::vector<std::string> DESKTOP_DIRS;
std::vector<std::string> MERGE_DIRS;
std::vector<std::string> DIRECTORY_FILES;
std::vector<std::string> CURRENT_CATEGORIES;
std::vector<std::string> NOT_CATEGORIES;
std::vector<std::string> NOTtheseFiles;
std::vector<std::string> PATHS;
//list
std::list<std::string> DESKTOP_FILES;
//modification time
struct tm *timer_result;
struct stat stat_structure;

//functions
//string vectors
std::vector<std::string> xdgmenufiles();
std::vector<std::string> theseChangedFiles(std::string dirToOpen);
std::vector<std::string> changedFiles();
std::vector<std::string> categoryDirs();
std::vector<std::string> addMergeDirs(std::vector<std::string> directoryFiles);
std::vector<std::string> CheckVectorAndRemove(std::vector<std::string> VectorToCheck, std::string thingToRemove);
//string list
std::list <std::string> get_desktop_files();
//c strings
std::string getStatFile();
std::string getCacheFile();
std::string getDDItem(std::string directory, std::string lineToGet);
std::string getDDName(std::string directory);
std::string chopTAG(std::string line);
std::string loop_desktopfiles(std::string categoryToGet,std::string dirToOpen);
std::string grep(std::string args, std::string filename);
std::string get_language_based_line(std::string name,std::string filename);
std::string get_name(std::string filename);
std::string get_comment(std::string filename);
std::string make_menu();
std::string make_menu_xdg(std::string prefix);
std::string remove_percentage(std::string line);
std::string exec_line(std::string filename);
std::string icon_line(std::string filename);
std::string name_line(std::string filename);
std::string cat_line(std::string filename);
std::string makeXDGmenu(std::vector<std::string> cats,std::vector<std::string> dirs);
std::string whichMenu(std::string prefix);
std::string getCacheDir();
//boolean
bool checkCache();
bool checkCacheDirStat(std::string dirname,std::string statFilename);
bool load(std::string filename);
bool load();
bool no_display(std::string filename);
bool not_showin(std::string filename);
bool only_show(std::string filename);
bool terminal(std::string filename);
bool updateMenu();
bool useComments();
bool matchesAnyRule(std::string filename, pugi::xml_node rule);
bool matchesALLRules(std::string filename, pugi::xml_node rule);
//void
void test();
void outXML(std::string message);
void writeOut(std::string MSG);
void readCacheFile();
void Included(pugi::xml_node SUB, pugi::xml_node RETURN);

//bool
bool file_name(pugi::xml_node NODE, std::string filename);
bool make_submenu(pugi::xml_node SUB, pugi::xml_node RETURN);
bool make_menu_xdg(std::string infile,std::string outfile);
bool LayoutMaker(pugi::xml_node Layout,pugi::xml_node RETURN);
//TODO make pugixml menu
int main(int argc, char* argv[]) {
	bool isCached=checkCache();
	RELOAD=false;
	INCEPTION=false;
	MERGE_inception=false;
	ONLY_UNALLOCATED=false;
	MERGEMENUS=0;
	MERGEFILES=0;
	PATHS=linuxcommon::split_paths("PATH","/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:");
	USECOMMENTS=useComments();
	MENU_CACHE_FILE=getCacheFile();
	std::string arg;
	if(argc>0){
		if(argv[1]!=NULL){
			arg=argv[1];
			//outXML("ARG="+arg);
			std::string argstring="<!-- ";
			argstring+=argv[0];
			argstring+=" Program Argument:"+arg+"-->";
			//writeOut(argstring);
			if(arg.compare("--reload")==0){
				arg="jwm-";
			}
			if(arg.compare("--test")==0){
				test();
				return 0;
			}
			//if(linuxcommon::test_file(arg)){
				
		//	}
			RELOAD=true;
		}
	}
	else{arg="jwm-";}
	//outXML(MENU_CACHE_FILE);
	if(!RELOAD && isCached && linuxcommon::test_file(MENU_CACHE_FILE.c_str())){
		//get cached file
		readCacheFile();
		return 0;
	}
	else{
		std::string result = make_menu_xdg(arg);
		writeOut("<?xml version=\"1.0\"?>\n<JWM>\n"+result+"</JWM>");
	}
	return 0;
}
bool compare_nocase (const std::string& first, const std::string& second){
	unsigned int i=0;
	while ( (i<first.length()) && (i<second.length()) ){
		if (tolower(first[i])<tolower(second[i])) return true;
		else if (tolower(first[i])>tolower(second[i])) return false;
		++i;
	}
	return ( first.length() < second.length() );
}
bool checkCacheDirStat(std::string dirname,std::string statFilename){
	if(dirname.compare("")==0)return true;
	std::string uniqueFilename=dirname;
	uniqueFilename=uniqueFilename.erase(0,1);
	unsigned int found = uniqueFilename.find("/");
	if(found<uniqueFilename.length()){
		uniqueFilename=uniqueFilename.erase(found,std::string::npos);
	}
	else{
		uniqueFilename="usr";
	}
	statFilename+="-";
	statFilename+=uniqueFilename;
	unsigned int founddirname = dirname.rfind('/');
    if(founddirname != dirname.length()-1){dirname+="/";}
	dirname+="applications/";
	if(!linuxcommon::test_dir(dirname))return true;
	bool res = false;
	char datestring[256];
	stat(dirname.c_str(), &stat_structure);
	timer_result = gmtime(&(stat_structure.st_mtime));
	strftime(datestring, sizeof(datestring), nl_langinfo(D_T_FMT), timer_result);
	if(linuxcommon::test_file(statFilename.c_str())){
	  //get previous date
	  std::string line;
	  std::string currentTime;
	  std::ifstream thisfile(statFilename.c_str(), std::ifstream::in);
      if(thisfile.is_open()){
          while (getline(thisfile,line)){
              currentTime=line;
              if(currentTime.compare(datestring)==0){ res=true;}
          }
      }
     
	}
	if(statFilename.compare("")!=0){
		std::ofstream myfile;
		//outXML(statFilename);
		myfile.open (statFilename.c_str());
		myfile << datestring;
		myfile.close();
		std::string outfile=statFilename+".old";
		std::ifstream source(statFilename.c_str(),std::ios::binary);
		std::ofstream dest(outfile.c_str(),std::ios::binary);
		dest << source.rdbuf();
	}
	return res;
}
bool checkCache(){
	std::string statFilename = getStatFile();
	MENU_CACHE_FILE=getCacheFile();
	char datestring[256];
	bool isCached = false;
	std::vector<std::string> uniqueDirs = linuxcommon::desktop_paths();
	std::string testPATH ="/usr/share/applications";
	for( std::vector<std::string>::iterator iter = uniqueDirs.begin();
		iter!=uniqueDirs.end();
		++iter){
		testPATH = *iter;
		bool prevCach=isCached;
		isCached=checkCacheDirStat(testPATH,statFilename);

		//if( (prevCach != isCached ) && (isCached) ){
//isCached=false;}
	}
	if(!linuxcommon::test_file(MENU_CACHE_FILE.c_str())){isCached=false;}
	return isCached;
}
std::vector<std::string> changedFiles(){
	std::vector<std::string> tmpVec;
	std::string testDirFile;
	std::vector<std::string> dirs = linuxcommon::desktop_paths();
	for( std::vector<std::string>::iterator itr = dirs.begin();
		itr!=dirs.end();
		++itr){
		testDirFile = *itr;
		std::vector<std::string> veryTMPvec = theseChangedFiles(testDirFile);
		tmpVec=linuxcommon::join_string_vectors(tmpVec,veryTMPvec);
	}
	return linuxcommon::sort_array(tmpVec);
}
std::vector<std::string> theseChangedFiles(std::string dirToOpen){
	DIR *dir = NULL;
	struct dirent *entryPointer = NULL;
	std::string result,tester,fullpath;
	dir = opendir(dirToOpen.c_str());
	std::vector<std::string> tmpVec;
	if (dir!=NULL){
		while ((entryPointer=readdir(dir)) != NULL){
			if ((entryPointer->d_type == DT_REG)&&(entryPointer->d_name[0] != '.')){
				fullpath = entryPointer->d_name;
				result=dirToOpen+fullpath;
				tester=dirToOpen+fullpath;
				unsigned period = result.rfind(".");
				bool isDESKTOP = false;
				if(result.compare("")!=0){
					if(period<result.length()){
						std::string testDesktop = result.substr(period+1,std::string::npos);
						if(testDesktop.compare("desktop")==0){isDESKTOP = true;}
					}
				//make a line if it is a desktop
					if(isDESKTOP){
						tmpVec.push_back(result);
					}
				}
			}
		}
	}
	return tmpVec;
}
bool updateMenu(){
	std::vector<std::string> changed=changedFiles();
	std::string fileName=getCacheFile();
	if(!doc.load_file( fileName.c_str() )){
        if(!linuxcommon::test_file(fileName.c_str())){
            linuxcommon::echo_error("The file: "+fileName+" was not found.");
            return false;
        }
    }
    std::string result;
    std::string NAME,ICON,EXEC,COMMENT,CAT;
    for( std::vector<std::string>::iterator it = changed.begin();
		it!=changed.end();
		++it){
		result=*it;
		if( (no_display(result)) || !(only_show(result)) || (not_showin(result)) ){
               //outXML(result);
		}
		else{
			NAME=name_line(result);
			NAME=linuxcommon::quote_xml(NAME);
			ICON=icon_line(result);
			ICON=linuxcommon::quote_xml(ICON);
			EXEC=exec_line(result);
			EXEC=linuxcommon::quote_xml(EXEC);
			CAT=cat_line(result);
			EXEC=linuxcommon::quote_xml(EXEC);
			if(USECOMMENTS){
				COMMENT=get_comment(result);
				COMMENT==linuxcommon::quote_xml(COMMENT);
			}
			//JWM->Menu->label="cat"
		}
	}
	return doc.save_file( fileName.c_str() );
}
bool load(){
	std::string fileName=getCacheFile();
	return load(fileName);
}
bool load(std::string filename){
	if(filename.compare("")==0){
		outXML("file does not exist and cannot be loaded");
		return false;
	}
	if(!doc.load_file( filename.c_str() )){
        if(!linuxcommon::test_file(filename.c_str())){
            outXML("The file: "+filename+" was not found.");
            return false;
        }
    }
    return true;
}
void readCacheFile(){
	std::string Filename=getCacheFile();
	if(Filename.compare("")==0){return;}
	std::string line;
	std::string currentTime;
	std::ifstream thisfile(Filename.c_str(), std::ifstream::in);
	if(thisfile.is_open()){
		while (getline(thisfile,line)){
			std::cout<<line<<std::endl;
		}
	}
}
std::string getCacheDir(){
	std::string cacheFile;
	const char* xdgcache =  getenv("XDG_CACHE_HOME");
	if(xdgcache==NULL){
		std::string homie = linuxcommon::home_path();
		if(homie.compare("")==0){return "";}
		else{
			std::string temp = homie;
			temp+=".cache";
			cacheFile=temp;
		}
	}
	else{
		cacheFile=xdgcache;
	}
    if(cacheFile.compare("")==0){return "";}
    if(!linuxcommon::test_dir(cacheFile)){mkdir(cacheFile.c_str(),0600);}
    unsigned int found = cacheFile.rfind('/');
    if(found != cacheFile.length()-1){cacheFile+="/";}
    return 	cacheFile;
}
std::string getStatFile(){
	std::string cacheFile=getCacheDir();
	if(cacheFile.compare("")==0){return "";}
    cacheFile+="appmod";
	return cacheFile;	
}
std::string getCacheFile(){
	std::string cacheFile=getCacheDir();
	if(cacheFile.compare("")==0){return "";}
    cacheFile+="jwm-menu.cache";
	return cacheFile;
}
void outXML(std::string message){
	//#ifndef QUIET_ERROR
	std::cout<<"<!--"<<message<<"-->"<<std::endl;
	//#endif
}
	
////////////////////////////////////////////////////////////////////////////////////////////////////string
std::string grep(std::string args, std::string filename) {
  ///Return the FIRST match of the 'args' from a file
  // this is like  line=`grep $args $filename` that only returns one line
      std::string line=linuxcommon::grep(args,filename);
      if(line.find("[Desktop Action")<line.length()){return "";}
      return line;
}
std::string get_comment(std::string filename){
	std::string name="Comment";
	return get_language_based_line(name,filename);
}
std::string get_name(std::string filename){
	std::string name="Name";
	return get_language_based_line(name,filename);
}
std::string get_language_based_line(std::string name,std::string filename){
	std::string tryGet,tempstr;
	std::string mylang;
	const char* thisLang= getenv("LANGUAGE");
	if(thisLang==NULL){
		const char* myLANG = getenv("LANG");
		if(myLANG !=NULL){
			mylang=myLANG;
			unsigned int found = mylang.find('.');
			if(found < mylang.length()){
				mylang = mylang.erase(found,std::string::npos);
			}
			tempstr=name;
			tempstr+="[";
			tempstr+=mylang;
			tempstr+="]=";
			tryGet=linuxcommon::get_line_with_equal(filename,tempstr);
		}
	}
	else{
		mylang=thisLang;
		tempstr=name;
		tempstr+="[";
		tempstr+=mylang;
		tempstr+="]=";
		tryGet=linuxcommon::get_line_with_equal(filename,tempstr);
	}
	if( (tryGet.compare("")==0) && (mylang.compare("")!=0) ){
		unsigned int dash = mylang.find('_');
		if(dash<mylang.length()){
			mylang = mylang.erase(dash,std::string::npos);
			tempstr=name;
			tempstr+="[";
			tempstr+=mylang;
		tempstr+="]=";
		tryGet=linuxcommon::get_line_with_equal(filename,tempstr);
	}
  }
  if (tryGet.compare("")==0){
    tryGet=linuxcommon::get_line_with_equal(filename,name);
  }
  return tryGet;
}
std::list <std::string> get_desktop_files(){
	std::list<std::string> DESKTOPS;
	DIR *dir = NULL;
	struct dirent *entryPointer = NULL;
	std::string dirToOpen,fullpath,result,tester;
	//TODO loop in ALL directories!!
	for( std::vector<std::string>::iterator it=DESKTOP_DIRS.begin();it!=DESKTOP_DIRS.end();++it){
		dirToOpen=*it;
		dirToOpen+="applications/";
		//outXML("Dir To Open:"+dirToOpen);
		dir = opendir(dirToOpen.c_str());
		if (dir!=NULL){
			while ((entryPointer=readdir(dir)) != NULL){
				if ((entryPointer->d_type == DT_REG)&&(entryPointer->d_name[0] != '.')){
					fullpath = entryPointer->d_name;
					result=dirToOpen+fullpath;
					tester=dirToOpen+fullpath;
					unsigned period = result.rfind(".");
					bool isDESKTOP = false;
					if(result.compare("")!=0){
						if(period<result.length()){
							std::string testDesktop = result.substr(period+1,std::string::npos);
							if(testDesktop.compare("desktop")==0){isDESKTOP = true;}
						}
					//make a line if it is a desktop
						if(isDESKTOP){
							if( (no_display(result)) || !(only_show(result)) || (not_showin(result)) ){
                        //outXML(result);
							}
							else{
								//outXML(result);
								DESKTOPS.push_back(result);}
						} //isDesktop
					}//result !empty
				}//dirent is file
			}//dirent !NULL
		}//directory !NULL
	}
	closedir(dir);
	DESKTOPS.unique();
	DESKTOPS.sort(compare_nocase);
	return DESKTOPS;
}
std::string loop_desktopfiles(std::string categoryToGet,std::string dirToOpen){
	std::string category,MenuEntry,EXEC,ICON,NAME,termie,tester,result,fullpath,returnCAT,COMMENT;
	std::list <std::string> DESKTOPS;
		//dirent
	DIR *dir = NULL;
	struct dirent *entryPointer = NULL;
	dir = opendir(dirToOpen.c_str());
	//int
	if (dir!=NULL){
		while ((entryPointer=readdir(dir)) != NULL){
			if ((entryPointer->d_type == DT_REG)&&(entryPointer->d_name[0] != '.')){
				fullpath = entryPointer->d_name;
				result=dirToOpen+fullpath;
				tester=dirToOpen+fullpath;
				unsigned period = result.rfind(".");
				bool isDESKTOP = false;
				if(result.compare("")!=0){
					if(period<result.length()){
						std::string testDesktop = result.substr(period+1,std::string::npos);
						if(testDesktop.compare("desktop")==0){isDESKTOP = true;}
					}
				//make a line if it is a desktop
				if(isDESKTOP){
					if( (no_display(result)) || !(only_show(result)) || (not_showin(result)) ){
                        //outXML(result);
					}
					else{
						NAME=name_line(result);
						NAME=linuxcommon::quote_xml(NAME);
						ICON=icon_line(result);
						ICON=linuxcommon::quote_xml(ICON);
						EXEC=exec_line(result);
						EXEC=linuxcommon::quote_xml(EXEC);
						if(USECOMMENTS){
							COMMENT=get_comment(result);
							COMMENT==linuxcommon::quote_xml(COMMENT);
						}
						if(COMMENT.compare("")!=0){
							MenuEntry="\t\t<Program label=\""+NAME+"\" tooltip=\""+COMMENT+" \"icon=\""+ICON+"\">"+EXEC+"</Program>\n";
						}
						else{MenuEntry="\t\t<Program label=\""+NAME+"\" icon=\""+ICON+"\">"+EXEC+"</Program>\n";}				
					//else{MenuEntry="\t\t<Program label=\""+NAME+"\" icon=\""+ICON+"\">"+EXEC+"</Program>\n";}
					category=cat_line(result);
					//outXML(category);
					//outXML(result);
					if( category.compare(categoryToGet)==0){DESKTOPS.push_back(MenuEntry);}
				}//nodisplay/notshow//onlyshow
			} //isDesktop
          }//result !empty
       }//dirent is file
     }//dirent !NULL
	}//directory !NULL
	closedir(dir);
	DESKTOPS.unique();
	DESKTOPS.sort(compare_nocase);
	for( std::list<std::string>::iterator it=DESKTOPS.begin();it!=DESKTOPS.end();++it){
		std::string tempentry=*it;
		if(tempentry.compare("")!=0){returnCAT+=tempentry;}
	}
 // outXML(returnCAT);
  return returnCAT;
}

std::string make_menu(){
	std::string MenuEntry,NAME,ICON,EXEC,CATS,TERMIE,AV,DEV,ED,GAME,ART,NET,OFF,SCI,SET,SYS,ACC,OTH,WINE,CHROME,category,testPATH;
	std::string dirToOpen = "/usr/share/applications/";
	std::string pathToGet = "/applications/";
	//"/.local/share/desktop-directories"
	std::string fullpath, result, name, icon, exec, tester, cat;
	///Localization Directory files
	//TODO use other menus if available
	std::string DIR_EXT = ".directory";
	std::string INTRO = "jwm";
	std::string iconEQ = "Icon=";
	std::string MENU;
	std::string fallbackIcon = "applications-";
	//TODO xdg dirs
	std::string DD = "/usr/share/desktop-directories";
	std::vector<std::string> dirVector = categoryDirs();
	for( std::vector<std::string>::iterator it = dirVector.begin();
		it!=dirVector.end();
		++it){
		DD=*it;
		//outXML(DD);
		if (DD.compare("")==0){return "\t<Program label=\"Could not find Desktop Directories\" icon=\"error\">xterm -e 'locate desktop-directories'</Program>\n";}
		
		//Accessories
		std::string A_NAME,A_ICON;
		std::string accessories_FILE = DD + "/" + INTRO + "-accessories" + DIR_EXT;
		if(linuxcommon::test_file(accessories_FILE.c_str()) ){
			A_NAME = get_name(accessories_FILE);
			A_ICON = linuxcommon::get_line_with_equal(accessories_FILE,iconEQ);
		}
		if(A_NAME.compare("")==0){A_NAME = "Accessories";}
		if(A_ICON.compare("")==0){A_ICON = fallbackIcon + "accessories";}
		
		//Games
		std::string games_FILE = DD + "/" + INTRO + "-games" + DIR_EXT;
		std::string GAME_NAME,GAME_ICON;
		if(linuxcommon::test_file(games_FILE.c_str()) ){
			GAME_NAME = get_name(games_FILE);
			GAME_ICON = linuxcommon::get_line_with_equal(games_FILE,iconEQ);
		}
		if(GAME_NAME.compare("")==0){GAME_NAME = "Games";}
		if(GAME_ICON.compare("")==0){GAME_ICON = fallbackIcon + "games";}
		
		//Graphics
		std::string graphics_FILE = DD + "/" + INTRO + "-graphics" + DIR_EXT;
		std::string G_NAME,G_ICON;
		if(linuxcommon::test_file(graphics_FILE.c_str()) ){
			G_NAME = get_name(graphics_FILE);
			G_ICON = linuxcommon::get_line_with_equal(graphics_FILE,iconEQ);
		}
		if(G_NAME.compare("")==0){G_NAME = "Graphics";}
		if(G_ICON.compare("")==0){G_ICON = fallbackIcon + "graphics";}
		
		//AudioVideo
		std::string multimedia_FILE = DD + "/" + INTRO + "-multimedia" + DIR_EXT;
		std::string M_NAME, M_ICON;
		if(linuxcommon::test_file(multimedia_FILE.c_str()) ){
			M_NAME = get_name(multimedia_FILE);
			M_ICON = linuxcommon::get_line_with_equal(multimedia_FILE,iconEQ);
		}
		if(M_NAME.compare("")==0){M_NAME = "Multimedia";}
		if(M_ICON.compare("")==0){M_ICON = fallbackIcon + "multimedia";}
		
		//Network
		std::string network_FILE = DD + "/" + INTRO + "-network" + DIR_EXT;
		std::string I_NAME,I_ICON;
		if(linuxcommon::test_file(network_FILE.c_str()) ){
			I_NAME = get_name(network_FILE);
			I_ICON = linuxcommon::get_line_with_equal(network_FILE,iconEQ);
		}
		if(I_NAME.compare("")==0){I_NAME = "Internet";}
		if(I_ICON.compare("")==0){I_ICON = fallbackIcon + "internet";}
		
		//Office
		std::string office_FILE = DD + "/" + INTRO + "-office" + DIR_EXT;
		std::string O_NAME,O_ICON;
		if( linuxcommon::test_file(office_FILE.c_str()) ){
			O_NAME = get_name(office_FILE);
			O_ICON = linuxcommon::get_line_with_equal(office_FILE,iconEQ);
		}
		if(O_NAME.compare("")==0){O_NAME = "Office";}
		if(O_ICON.compare("")==0){O_ICON = fallbackIcon + "office";}
		
		//Other?
		std::string other_FILE = DD + "/" + INTRO + "-other" + DIR_EXT;
		std::string OTHER_NAME,OTHER_ICON;
		if(linuxcommon::test_file(other_FILE.c_str()) ){
			OTHER_NAME = get_name(other_FILE);
			OTHER_ICON = linuxcommon::get_line_with_equal(other_FILE,iconEQ);
		}
		if(OTHER_NAME.compare("")==0){OTHER_NAME = "Other";}
		if(OTHER_ICON.compare("")==0){OTHER_ICON = fallbackIcon + "other";}
	
		//System
		std::string system_FILE = DD + "/" + INTRO + "-system" + DIR_EXT;
		std::string SYS_NAME,SYS_ICON;
		if(linuxcommon::test_file(system_FILE.c_str()) ){
			SYS_NAME = get_name(system_FILE);
			SYS_ICON = linuxcommon::get_line_with_equal(system_FILE,iconEQ);
		}
		if(SYS_NAME.compare("")==0){SYS_NAME = "System";}
		if(SYS_ICON.compare("")==0){SYS_ICON = fallbackIcon + "system";}
	
		//Settings
		std::string settings_FILE = DD + "/" + INTRO + "-settings" + DIR_EXT;
		std::string SETT_NAME,SETT_ICON;
		if(linuxcommon::test_file(settings_FILE.c_str()) ){
			SETT_NAME = get_name(settings_FILE);
			SETT_ICON = linuxcommon::get_line_with_equal(settings_FILE,iconEQ);
		}
		if(SETT_NAME.compare("")==0){SETT_NAME = "Settings";}
		if(SETT_ICON.compare("")==0){SETT_ICON = "preferences-desktop";}
	
		//Development
		std::string development_FILE = DD + "/" + INTRO + "-development" + DIR_EXT;
		std::string D_NAME,D_ICON;
		if(linuxcommon::test_file(development_FILE.c_str()) ){
			D_NAME = get_name(development_FILE);
			D_ICON = linuxcommon::get_line_with_equal(development_FILE,iconEQ);
		}
		if(D_NAME.compare("")==0){D_NAME = "Development";}
		if(D_ICON.compare("")==0){D_ICON = fallbackIcon + "development";}
		
		//Education
		std::string education_FILE = DD + "/" + INTRO + "-education" + DIR_EXT;
		std::string E_NAME,E_ICON;
		if(linuxcommon::test_file(education_FILE.c_str()) ){
			E_NAME = get_name(education_FILE);
			E_ICON = linuxcommon::get_line_with_equal(education_FILE,iconEQ);	
		}
		if(E_NAME.compare("")==0){E_NAME = "Education";}
		if(E_ICON.compare("")==0){E_ICON = fallbackIcon + "science";}
		//Wine
		std::string wine_NAME,wine_ICON;
		std::string wine_FILE = DD + "/wine" + DIR_EXT;
		if(linuxcommon::test_file(wine_FILE.c_str()) ){
			wine_NAME = get_name(wine_FILE);
			wine_ICON = linuxcommon::get_line_with_equal(wine_FILE,iconEQ);
		}
		if(wine_NAME.compare("")==0){wine_NAME = "Wine";}
		if(wine_ICON.compare("")==0){wine_ICON = fallbackIcon + "accessories";}
		
		//Chrome
		std::string chrome_NAME,chrome_ICON;
		std::string chrome_FILE = DD + "/chrome-apps" + DIR_EXT;
		if(linuxcommon::test_file(chrome_FILE.c_str()) ){
			chrome_NAME = get_name(chrome_FILE);
			chrome_ICON = linuxcommon::get_line_with_equal(chrome_FILE,iconEQ);
		}
		if(chrome_NAME.compare("")==0){chrome_NAME = "Chrome Apps";}
		if(chrome_ICON.compare("")==0){chrome_ICON = fallbackIcon + "accessories";}
		
		std::vector<std::string> uniqueDirs = linuxcommon::desktop_paths();
		unsigned int found = 0;
		//initialize directory reading variables to NULL
		DIR *dir = NULL;
		for( std::vector<std::string>::iterator it = uniqueDirs.begin();
			it!=uniqueDirs.end();
			++it){
        //get the string equvalent for the integer representation if of the xdg path
        // something like
        /*
        1=/usr/share/
        2=/usr/local/share
        etc...
        */
			testPATH = *it;
		//make sure this isn't blank
			if(testPATH.compare("")!=0){
			//look to see if we have a / at the end... remove it if we do...
				found = testPATH.rfind('/');
				if (found == testPATH.length()-1){testPATH=testPATH.substr(0,testPATH.length()-1);}
			//see if there is a pathToGet directory
				dirToOpen = testPATH + pathToGet;
				dir = opendir(dirToOpen.c_str());
				if (dir!=NULL){
				//outXML(dirToOpen);
					AV+=loop_desktopfiles("AudioVideo",dirToOpen);
					DEV+=loop_desktopfiles("Development",dirToOpen);
					ED+=loop_desktopfiles("Education",dirToOpen);
					GAME+=loop_desktopfiles("Game",dirToOpen);
					ART+=loop_desktopfiles("Graphics",dirToOpen);
					NET+=loop_desktopfiles("Network",dirToOpen);
					OFF+=loop_desktopfiles("Office",dirToOpen);
					SCI+=loop_desktopfiles("Science",dirToOpen);
					SET+=loop_desktopfiles("Settings",dirToOpen);
					SYS+=loop_desktopfiles("System",dirToOpen);
					ACC+=loop_desktopfiles("Utility",dirToOpen);		
				}
				closedir(dir);
			}// testPath not empty
		}//vector of directories
		if(ACC.compare("")!=0){MENU+="\t<Menu label=\""+A_NAME+"\" icon=\""+A_ICON +"\" height=\"0\">\n"+ACC+"\n\t</Menu>\n";}
		if(ED.compare("")!=0){MENU+="\t<Menu label=\""+E_NAME+"\" icon=\""+E_ICON +" \" height=\"0\">\n"+ED+"\n\t</Menu>\n";}
		if(NET.compare("")!=0){MENU+="\t<Menu label=\""+I_NAME+"\" icon=\""+I_ICON +" \" height=\"0\">\n"+NET+"\n\t</Menu>\n";}
		if(OFF.compare("")!=0){MENU+="\t<Menu label=\""+O_NAME+"\" icon=\""+O_ICON +"\" height=\"0\">\n"+OFF+"\n\t</Menu>\n";}
		if(GAME.compare("")!=0){MENU+="\t<Menu label=\""+GAME_NAME+"\" icon=\""+GAME_ICON +"\" height=\"0\">\n"+GAME+"\n\t</Menu>\n";}
		if(ART.compare("")!=0){MENU+="\t<Menu label=\""+G_NAME+"\" icon=\""+G_ICON +" \" height=\"0\">\n"+ART+"\n\t</Menu>";}
		if(AV.compare("")!=0){MENU+="\t<Menu label=\""+M_NAME+"\" icon=\""+M_ICON + " \" height=\"0\">\n"+AV+"\n\t</Menu>\n";}
		if(DEV.compare("")!=0){MENU+="\t<Menu label=\""+D_NAME+"\" icon=\""+D_ICON + " \" height=\"0\">\n"+DEV+"\n\t</Menu>\n";}
		if(SCI.compare("")!=0){MENU+="\t<Menu label=\""+OTHER_NAME+"\" icon=\""+OTHER_ICON + " \" height=\"0\">\n"+SCI+"\n\t</Menu>\n";}
		if(SET.compare("")!=0){MENU+="\t<Menu label=\""+SETT_NAME+"\" icon=\""+SETT_ICON + " \" height=\"0\">\n"+SET+"\n\t</Menu>\n";}
		if(SYS.compare("")!=0){MENU+="\t<Menu label=\""+SYS_NAME+"\" icon=\""+SYS_ICON + " \" height=\"0\">\n"+SYS+"\n\t</Menu>";}
	}//desktop directory vector
	return MENU;
}//make_menu
std::string remove_percentage(std::string line){
    if(line.compare("")==0){return line;}
    unsigned int percentfind=0;
    std::string tempstring;
    percentfind=line.find(" %",0);
    if(percentfind>line.length()){return line;}
    unsigned int semifind=line.find(";",percentfind);
  //  #if 0
    bool andis=false;
    bool semiis=false;
    if(semifind<line.length()){
		semiis=true;
	}
    unsigned int andfind=line.find("&",percentfind);
    if(andfind<line.length()){
		andis=true;
	}
	if(andis && semiis){
		if(andfind<semifind){
			percentfind=line.find(" %",0);
			if(percentfind<line.length()){tempstring=line.erase(percentfind, andfind);}
		}
		else{tempstring=line.erase(percentfind, semifind);}
	}
	else if(andis){
		andfind=line.find("&",percentfind);
		percentfind=line.find(" %",0);
		if(percentfind<line.length()){tempstring=line.erase(percentfind, andfind);}
	}
	else if(semiis){
		semifind=line.find(";",percentfind);
		percentfind=line.find(" %",0);
		if(percentfind<line.length()){tempstring=line.erase(percentfind, semifind);}
	}
	else{
		percentfind=line.find(" %",0);
		if(percentfind<line.length()){tempstring=line.erase(percentfind, 3);}
	}
	//#endif
	//tempstring=line.erase(percentfind, 3);
	return tempstring;
}
std::string exec_line(std::string filename) {
	std::string execline= linuxcommon::get_line_with_equal(filename,"Exec=");
	if(execline.compare("")==0){execline= linuxcommon::get_line_with_equal(filename,"TryExec=");}
	execline=remove_percentage(execline);
	if(terminal(filename)){
		std::string myterm=linuxcommon::term_out("which x-terminal-emulator || which xterm");
		execline=myterm + " -e " + execline;
	}
	return execline;
}

std::string icon_line(std::string filename) {
  std::string icon = linuxcommon::get_line_with_equal(filename,"Icon=");
  //outXML("icon:"+icon+"::");
  if ( icon.compare("")==0){return "application-default-icon";}
  return icon;
}

std::string name_line(std::string filename) {
  std::string base_lang,result,strlang,strlanguage,startbase,NAME,LOCALNAME,LOCALEND;
  NAME="Name";
  LOCALNAME="Name[";
  LOCALEND="]=";
  unsigned int underscore = 0;
  char* lang = getenv("LANG");
  char* language = getenv("LANGUAGE");
  if (lang!=NULL){
	strlang = lang;
    result=linuxcommon::get_line_with_equal(filename,(LOCALNAME+ strlanguage + LOCALEND));

    if(result.compare("")!=0){return result;}
    base_lang=strlanguage;
  }
  else{
    if (language!=NULL){
		strlanguage =language;
        unsigned int dot = 0;
        dot=strlang.find('.');
        if(dot<strlang.length()){
			startbase=strlang.erase(dot,strlang.length());
			result=linuxcommon::get_line_with_equal(filename, (LOCALNAME+ startbase + LOCALEND));

			if(result.compare("")!=0){return result;}
			base_lang=startbase;
		}
		else{return linuxcommon::get_line_with_equal(filename,"Name=");}
     }
     else{return linuxcommon::get_line_with_equal(filename,"Name=");}
  }

  underscore=base_lang.find('_');
  if(underscore<base_lang.length()){
	base_lang=base_lang.erase(underscore,base_lang.length());
	result=linuxcommon::get_line_with_equal( filename,(LOCALNAME+ base_lang + LOCALEND));
	if(result.compare("")!=0){return result;}
  }
  return linuxcommon::get_line_with_equal(filename,"Name=");
}
std::string cat_line(std::string filename){
	std::string AV,DEV,ED,GAME,ART,NET,OFF,SCI,SET,SYS,ACC,OTH,WINE,CHROME,category,CAT;
	AV = "AudioVideo";
	DEV = "Development";
	ED = "Education";
	GAME = "Game";
	ART = "Graphics";
	NET = "Network";
	OFF = "Office";
	SCI = "Science";
	SET = "Settings";
	SYS = "System";
	ACC = "Utility";
	WINE= "Wine";
	OTH = "Other";
	CHROME = "Chrome Apps";
	std::string temp1,temp2;
	unsigned int found;
	std::string catline = linuxcommon::get_line_with_equal(filename,"Categories=");
	/*unsigned int chromefind = filename.find("chrome");
	if (chromefind < filename.length()){return CHROME;}*/
	if (catline.compare("")==0){return OTH;}
	temp2=catline;
	found = temp2.find(';');
	if(found>temp2.length()){return catline;}
	std::string thisCAT="";
	for(unsigned int i = 0; i<catline.length();i++){
		found = temp2.find(';');
		if(found < temp2.length()){
			temp2=temp2.erase(found,temp2.length());
			temp1 = catline.erase(0,found+1);
			category=temp2;
			temp2=temp1;
			if( category.compare(AV)==0){thisCAT=AV;}
			else if( category.compare(DEV)==0){thisCAT=DEV;}
			else if( category.compare(DEV)==0){thisCAT=DEV;}
			else if( category.compare(ED)==0){thisCAT=ED;}
			else if( category.compare(GAME)==0){thisCAT=GAME;}
			else if( category.compare(ART)==0){thisCAT=ART;}
			else if( category.compare(NET)==0){thisCAT=NET;}
			else if( category.compare(OFF)==0){thisCAT=OFF;}
			else if( category.compare(SCI)==0){thisCAT=SCI;}
			else if( category.compare(SET)==0){thisCAT=SET;}
			else if( category.compare(SYS)==0){thisCAT=SYS;}
			else if( category.compare(ACC)==0){thisCAT=ACC;}
			else if( category.compare(WINE)==0){thisCAT=WINE;}
			else{
				if(thisCAT.compare("")==0){thisCAT=OTH;}
			}
		}
	}
	return thisCAT; //category;
}
std::string chopTAG(std::string line){
	unsigned int tLen=line.find('>');
	std::string temp = line;
	temp=temp.erase(0,tLen+1);
	tLen=temp.find('<');
	temp=temp.erase(tLen,std::string::npos);	
	return temp;
}
std::string getDDName(std::string directory){
	std::vector<std::string> uniqueDirs = linuxcommon::desktop_paths();
	std::string testPATH,line;
	unsigned int found = 0;
	DIR *dirent = NULL;
	for( std::vector<std::string>::iterator it = uniqueDirs.begin();
		it!=uniqueDirs.end();
		++it){
			
		testPATH = *it;
		//make sure this isn't blank
		if(testPATH.compare("")!=0){
			//look to see if we have a / at the end... remove it if we do...
			found = testPATH.rfind('/');
			if (found == testPATH.length()-1){testPATH=testPATH.substr(0,testPATH.length()-1);}
			std::string tempdirName=testPATH;
			tempdirName+="/desktop-directories/";
			dirent = opendir(tempdirName.c_str());
			if (dirent!=NULL){
				tempdirName+=directory;
			}
			if(get_name(tempdirName).compare("")!=0){line=get_name(tempdirName);}
			closedir(dirent);
			
		}
	}
	line=linuxcommon::quote_xml(line);
	return line;
}
std::string getDDItem(std::string directory, std::string lineToGet){
	std::vector<std::string> uniqueDirs = linuxcommon::desktop_paths();
	std::string testPATH,line;
	unsigned int found = 0;
	DIR *dirent = NULL;
	for( std::vector<std::string>::iterator it = uniqueDirs.begin();
		it!=uniqueDirs.end();
		++it){
			
		testPATH = *it;
		//make sure this isn't blank
		if(testPATH.compare("")!=0){
			//look to see if we have a / at the end... remove it if we do...
			found = testPATH.rfind('/');
			if (found == testPATH.length()-1){testPATH=testPATH.substr(0,testPATH.length()-1);}
			std::string tempdirName=testPATH;
			tempdirName+="/desktop-directories/";
			dirent = opendir(tempdirName.c_str());
			if (dirent!=NULL){
				tempdirName+=directory;
				if(linuxcommon::get_line_with_equal(tempdirName,lineToGet).compare("")!=0){line=linuxcommon::get_line_with_equal(tempdirName,lineToGet);}
			}
		}
	}
	line==linuxcommon::quote_xml(line);
	return line;
}

std::string makeXDGmenu(std::vector<std::string> cats,std::vector<std::string> dirs){
	std::string MENU,menuTest,this_ICON,this_NAME,this_Exec, desktopTest,testDirFile,testPATH;
	std::string dirToOpen = "/usr/share/applications/";
	std::string pathToGet = "/applications/";
	std::string iconEQ = "Icon=";
	std::string DESKTOPS;
    for( std::vector<std::string>::iterator itr = dirs.begin();
		itr!=dirs.end();
		++itr){
		testDirFile = *itr;
		if(getDDName(testDirFile).compare("")!=0){this_NAME = getDDName(testDirFile);}
		if(getDDItem(testDirFile,iconEQ).compare("")!=0){this_ICON = getDDItem(testDirFile,iconEQ);}
		for( std::vector<std::string>::iterator it = cats.begin();
		it!=cats.end();
		++it){
			
			std::vector<std::string> uniqueDirs = linuxcommon::desktop_paths();
			unsigned int found = 0;
			unsigned int foundDesk = 0;
			unsigned int foundMENU = 0;
			//initialize directory reading variables to NULL
			std::string CATS=*it;
			DIR *dirent = NULL;
			for( std::vector<std::string>::iterator iter = uniqueDirs.begin();
				iter!=uniqueDirs.end();
				++iter){
				testPATH = *iter;
				//make sure this isn't blank
				if(testPATH.compare("")!=0){
					//look to see if we have a / at the end... remove it if we do...
					found = testPATH.rfind('/');
					if (found == testPATH.length()-1){testPATH=testPATH.substr(0,testPATH.length()-1);}
					//see if there is a pathToGet directory
					dirToOpen = testPATH + pathToGet;
					dirent = opendir(dirToOpen.c_str());
					if (dirent!=NULL){
						//Does the menu file have icon and name?
						if( (this_ICON.compare("")!=0)&&(this_NAME.compare("")!=0) ){
							std::string tempTEST;
							//test the loop of the files for this category
							desktopTest=loop_desktopfiles(CATS,dirToOpen);
							//Is this entry already there?
							foundMENU=MENU.find(desktopTest);
							if( foundMENU>MENU.length() ){
								tempTEST=desktopTest;
								std::string OLDdesktop=DESKTOPS;
								DESKTOPS+=desktopTest;
								//make sure we have something new here
								if(DESKTOPS.length()>tempTEST.length()){
									//add it
									DESKTOPS=OLDdesktop+"\t<Separator/>\n"+desktopTest;
								}
							}
						}
					}
				}
			}//desktop file path vector
			unsigned int menuFind=0;
			menuFind=MENU.find(this_NAME);
			if(menuFind>MENU.length()){
				if(DESKTOPS.compare("")!=0){
					MENU+="\t<Menu label=\""+this_NAME+"\" icon=\""+this_ICON +"\" height=\"0\">\n"+DESKTOPS+"\t</Menu>\n";
				}
			}
			DESKTOPS.clear();
		}//categories vector
	}//dirs vector
	return MENU;
}
////////////////////////////////////////////////////////////////////////////////////////////////////BOOL


bool no_display(std::string filename) {
  std::string result = linuxcommon::get_line_with_equal(filename,"NoDisplay=");
  if(result.compare("")==0){
    return false;
  }
  std::transform(result.begin(),result.end(),result.begin(),::tolower);
  if (result.compare("true")==0){return true;}
  else{return false;}

  return false;
}
bool useComments(){
    std::string jwmVersion = "jwm -v";// | grep JWM |sed 's/ by.*//' |sed 's/JWM v//'";
	std::string version = linuxcommon::term_out(jwmVersion);
	version=linuxcommon::remove_cruft(version,"JWM v");
	
	unsigned int found=0;
	found=version.find(" by");
	if(found<version.length()){
		version=version.erase(found,std::string::npos);
	}
	std::string newTagVersion = "2.3.3";
    if(version.compare(newTagVersion)==0){return true;}
    int newTagVersionMajor = 2, newTagVersionMinor = 3, revno = 3;
    int dot1 = version.find('.');
    int dot2 = version.rfind('.');
    std::string major = version.substr(0,dot1);
    std::string minor = version.substr(dot1+1,dot2);
    std::string rev = version.substr(dot2+1,std::string::npos);
    int majorVersion = linuxcommon::convert_string_to_number(major.c_str());
    int minorVersion = linuxcommon::convert_string_to_number(minor.c_str());
    int revVersion = linuxcommon::convert_string_to_number(rev.c_str());
    //std::cout<<"Version:"<<majorVersion<<"."<<minorVersion<<"."<<revVersion<<std::endl;
    if (majorVersion > newTagVersionMajor){return true;}
    if(majorVersion < newTagVersionMajor){return false;}
    if(minorVersion >= newTagVersionMinor){
		if(revVersion>=revno){return true;}
	}
    return false;
}
bool only_show(std::string filename) {
  const char* desktop = getenv("XDG_CURRENT_DESKTOP");
  if(desktop==NULL){desktop="JWM";}
  const char* desktop_session = getenv("DESKTOP_SESSION");
  if(desktop_session==NULL){desktop_session="JWM";}
  std::string result = linuxcommon::get_line_with_equal_after_header("Desktop Entry",filename,"OnlyShowIn=");
  unsigned int found = 0;
  if(result.compare("")==0){
  //Only show in line doesn't exist
    return true;
  }
  //compare lower case words only
  std::transform(result.begin(),result.end(),result.begin(),::tolower);

  std::string temp1,temp2;
  temp2=result;

  for(unsigned int i = 0; i<result.length();i++){
    found = temp2.find(';');
    if(found < temp2.length()){
      temp2=temp2.erase(found,temp2.length());
      temp1 = result.erase(0,found+1);
      if (desktop !=NULL){
        if (temp2.compare(desktop)==0){return true;}
      }
      if (desktop_session !=NULL){
        if(temp2.compare(desktop_session)==0){return true;}
      }
      if (temp2.compare("unity")==0){return false;}
      temp2=temp1;
     }
     else{
		if (temp2.compare(desktop)==0){return true;}
		if (temp2.compare(desktop_session)==0){return true;}
     }
  }
  return false;
}
bool terminal(std::string filename) {
  std::string result = linuxcommon::get_line_with_equal(filename,"Terminal=");
  if(result.compare("")==0){
  //Only show in line doesn't exist
    return false;
  }
  //compare lower case words only
  std::transform(result.begin(),result.end(),result.begin(),::tolower);
  if(result.find("true")<result.length()){return true;}
  return false;
}
bool not_showin(std::string filename) {
  char* desktop = getenv("XDG_CURRENT_DESKTOP");
  char* desktop_session = getenv("DESKTOP_SESSION");
  std::string result = linuxcommon::get_line_with_equal(filename,"NotShowIn=");
  unsigned int found = 0;
  if(result.compare("")==0){
    return false;
  }
  std::transform(result.begin(),result.end(),result.begin(),::tolower);
  std::string temp1,temp2;
  temp2=result;
  for(unsigned int i = 0; i<result.length();i++){
    found = temp2.find(';');
    if(found < temp2.length()){
      temp2=temp2.erase(found,temp2.length());
      temp1 = result.erase(0,found+1);
    if (desktop !=NULL){
      if (temp2.compare(desktop)==0){
      return true;
      }
    }
    if (desktop_session !=NULL){
      if (temp2.compare(desktop_session)==0){
      return true;
      }
    }
      temp2=temp1;
    }
  }
  return false;
}

////////////////////////////////////////////////////////////////////////////////////////////////////String Vectors

std::string whichMenu(std::string prefix){
//$XDG_CONFIG_DIRS/menus/${XDG_MENU_PREFIX}applications.menu
	std::string apps="applications.menu";
	const char* XDG_MENU_PREFIX=getenv("XDG_MENU_PREFIX");
	if(XDG_MENU_PREFIX==NULL){
		XDG_MENU_PREFIX="jwm-";
	}
	std::string menuNAME=XDG_MENU_PREFIX;
	menuNAME+=apps;
	if(prefix.compare("")!=0){
		if(linuxcommon::test_file(prefix)){menuNAME=prefix;}
		else{
			if(prefix.find(".menu")<prefix.length() ){menuNAME=prefix;}
			else{
				if(prefix.find(apps)>prefix.length() ){
					prefix+=apps;
					menuNAME=prefix;
				}
			}
		}
	}
	std::string testPATH;
	std::string FALLBACKmenuNAME = "lxde-"+apps;
	std::string jwmmenuNAME="jwm-"+apps;
	std::vector<std::string> MENUS=xdgmenufiles();
	bool arg,jwm,lxde;
	arg=false;
	jwm=false;
	lxde=false;
	std::string argM,jwmM,lxdeM;
	for( std::vector<std::string>::iterator it = MENUS.begin();
		it!=MENUS.end();
		++it){
		testPATH = *it;
		if(prefix.compare("")!=0){
			//outXML("prefix sent in");
			if(testPATH.find(FALLBACKmenuNAME)<testPATH.length()){lxdeM=testPATH;lxde=true;}
			if(testPATH.find(jwmmenuNAME)<testPATH.length()){jwmM=testPATH;jwm=true;}
			if(testPATH.find(menuNAME)<testPATH.length()){argM=testPATH;arg=true;}
		}
		else{
			//outXML("NO PREFIX");
			if(testPATH.find(jwmmenuNAME)<testPATH.length()){return testPATH;}
			if(testPATH.find(menuNAME)<testPATH.length()){argM=testPATH;arg=true;}
			if(testPATH.find(FALLBACKmenuNAME)<testPATH.length()){lxdeM=testPATH;lxde=true;}
		}
	}
	if(arg){return argM;}
	if(jwm){return jwmM;}
	if(lxde){return lxdeM;}
	return "";
}

void menumaker(){
	std::string tmp=  make_menu_xdg("jwm-");
	return;
}
bool file_name(pugi::xml_node NODE,std::string filename){
	if(filename.compare("")==0){return false;}
	if(!NODE){return false;}
	outXML("bool file_name(std::string "+filename+")");
	std::string fname;
	pugi::xml_node temp;
	fname = linuxcommon::look_for_desktop_file(filename);
	if(fname.compare("")==0){return false;}
	if(!NOT_CATEGORIES.empty()){
		std::string tempCat=linuxcommon::get_line_with_equal(fname,"Categories");
		std::vector<std::string> catty =linuxcommon::delimiter_vector_from_string(tempCat,";");
		for(std::vector<std::string>::iterator itn=NOT_CATEGORIES.begin();itn!=NOT_CATEGORIES.end();++itn){
			std::string Cat=*itn;
			outXML("DON'T USE::"+Cat);
			if(linuxcommon::look_for_string_in_vector(catty,Cat)){
				outXML("DON'T USE::Found:"+Cat+" in:"+fname);
				return false;
			}
		}
	}
	//outXML("Found filename="+fname);
	std::string NAME=get_name(fname);
	std::string EXEC=exec_line(fname);
	std::string ICON=icon_line(fname);
	std::string TOOLTIP=get_comment(fname);
	if(EXEC.compare("")==0){return false;}
	//outXML("NAME="+NAME+"\nEXEC="+EXEC+"\nICON="+ICON+"\nTOOLTIP="+TOOLTIP);
	if(NAME.compare("")==0){NAME=EXEC;}
	if(TOOLTIP.compare("")==0){TOOLTIP=EXEC;}
	temp=NODE.append_child("Program");
	temp.append_child(pugi::node_pcdata).set_value(EXEC.c_str());
	pugi::xml_attribute ATTRI = temp.append_attribute("label");
	ATTRI.set_value(NAME.c_str());
	ATTRI = temp.append_attribute("icon");
	ATTRI.set_value(ICON.c_str());
	if(USECOMMENTS){
		ATTRI=temp.append_attribute("tooltip");
		ATTRI.set_value(TOOLTIP.c_str());
	}
	return true;
}

std::string dirFileFullPath(std::string fileName){
	//Find the name in the file!
	std::string filename=linuxcommon::find_xdg_config_dir_subdir("menus");
	filename+=fileName;
	if(linuxcommon::test_file(filename)){return filename;}
	return "";
}

void Category(std::string Cat, pugi::xml_node RETURN){
	if(Cat.compare("")==0)return;
	if(!RETURN)return;
	outXML("void Category(std::string "+Cat+", pugi::xml_node RETURN)");
	int iter=0;
	for( std::list<std::string>::iterator it=DESKTOP_FILES.begin();it!=DESKTOP_FILES.end();++it){
		std::string tempentry=*it;
		std::string tempCat=linuxcommon::get_line_with_equal(tempentry,"Categories");
		std::vector<std::string> catty =linuxcommon::delimiter_vector_from_string(tempCat,";");
		
		if(linuxcommon::look_for_string_in_vector(catty,Cat)){
			outXML("Category:"+tempCat+"\nFound:"+Cat);
			if(!file_name(RETURN,tempentry)){
				//outXML("Failed to process:"+tempentry);
			}
			else{
				//outXML("found category:"+Cat+" in:"+tempentry);
				//Remove desktop file from list??
				
				it=DESKTOP_FILES.erase(it);//it);
			}
		}
		iter++;
	}
}
void Category(std::vector<std::string> Cats, pugi::xml_node RETURN){
	if(Cats.empty())return;
	if(!RETURN)return;
	outXML("void Category(std::vector<std::string> Cats, pugi::xml_node RETURN)");
	std::list<std::string>::iterator it=DESKTOP_FILES.begin();//it!=DESKTOP_FILES.end();++it){
	while(it!=DESKTOP_FILES.end()){
		std::string tempentry=*it;
		bool WORKEDout=false;
		std::string tempCat=linuxcommon::get_line_with_equal(tempentry,"Categories");
		std::vector<std::string> catty =linuxcommon::delimiter_vector_from_string(tempCat,";");		
		for( std::vector<std::string>::iterator itera=Cats.begin();itera!=Cats.end();++itera){
			std::string Cat=*itera;			
			if(linuxcommon::look_for_string_in_vector(catty,Cat)){
				if(!file_name(RETURN,tempentry)){outXML("Failed to process:"+tempentry);}
				else{
					outXML("found category:"+Cat+" in:"+tempentry);
					WORKEDout=true;
				}
			}
		}
		if(WORKEDout){it=DESKTOP_FILES.erase(it);}
		else{++it;}
	}
	outXML("End of Category");
}
void Excluded(pugi::xml_node SUB, pugi::xml_node RETURN){
	if(!SUB)return;
	if(!RETURN)return;
	std::vector <std::string> NOTlist;
	std::vector <std::string> YESlist;
	pugi::xml_node Layout;
	for(Layout=SUB.first_child();Layout;Layout=Layout.next_sibling()){
		std::string namer=Layout.name();
		std::string val=Layout.text().as_string();
		if(namer.compare("Filename")==0){
			if(!file_name(RETURN,val)){
				//outXML("Skipping="+val);
			}
		}
		if(namer.compare("Category")==0){
			Category(val,RETURN);
		}
		//these can hold category or filename
		for(std::list<std::string>::iterator it=DESKTOP_FILES.begin();it!=DESKTOP_FILES.end();++it){
			std::string tempentry=*it;
			if(namer.compare("All")==0){
				YESlist.push_back(tempentry);
			}
			if(namer.compare("Not")==0){
				if(matchesAnyRule(tempentry,Layout)){
					NOTlist.push_back(tempentry);
				}
				else{YESlist.push_back(tempentry);}
			}
			if(namer.compare("And")==0){
				if(matchesALLRules(tempentry,Layout)){
					YESlist.push_back(tempentry);
				}
				else{NOTlist.push_back(tempentry);}
			}
			if(namer.compare("Or")==0){
				if(matchesAnyRule(tempentry,Layout)){
					YESlist.push_back(tempentry);
				}
				else{NOTlist.push_back(tempentry);}
			}
		}
	}
	//TODO check not list and Yes list to remove from Not list
	for(std::vector<std::string>::iterator it=NOTlist.begin();it!=NOTlist.end();++it){
		std::string fileName=*it;
		if(linuxcommon::test_file(fileName)){
			pugi::xml_node tmp=RETURN.append_child("Program");
			std::string numero, icon,tooltip,exec;		
			exec=exec_line(fileName);
			if(exec.compare("")!=0){
				numero=get_name(fileName);
				icon=icon_line(fileName);
				if(icon.compare("")==0){icon="application-default-icon";}
				if(numero.compare("")==0){numero=exec;}
				tmp.append_attribute("label")=numero.c_str();
				tmp.append_attribute("icon")=icon.c_str();
				if(USECOMMENTS){
					tooltip=get_comment(fileName);
					if(tooltip.compare("")==0){tooltip=numero;}
					tmp.append_attribute("tooltip")=tooltip.c_str();
				}
				tmp.append_child(pugi::node_pcdata).set_value(exec.c_str());
			}
		}		
	}
}
bool matchesAnyRule(std::string filename, pugi::xml_node rule){
	for(pugi::xml_node ruleNode=rule.first_child();ruleNode;ruleNode=ruleNode.next_sibling()){
		std::string Name=ruleNode.name();
		std::string Value=ruleNode.text().as_string();
		if(Name.compare("Category")){
			std::string cat=cat_line(filename);
			if(cat.compare(Value)==0){return true;}
		}
		if(Name.compare("Filename")){if(filename.compare(Value)==0){return true;}}
		
	}
	return false;
}
bool matchesALLRules(std::string filename, pugi::xml_node rule){
	for(pugi::xml_node ruleNode=rule.first_child();ruleNode;ruleNode=ruleNode.next_sibling()){
		std::string Name=ruleNode.name();
		std::string Value=ruleNode.text().as_string();
		if(Name.compare("Category")){
			std::string cat=cat_line(filename);
			if(cat.compare(Value)!=0){return false;}
		}
		if(Name.compare("Filename")){
			if(filename.compare(Value)!=0){return false;}
		}
	}
	return true;
}
void ANDProcessor(pugi::xml_node SUB, pugi::xml_node RETURN){
	outXML("ANDProcessor");
	if(!SUB)return;
	if(!RETURN)return;
	pugi::xml_node Layout;
	std::vector<std::string> theseCats;
	for(Layout=SUB.first_child();Layout;Layout=Layout.next_sibling()){
		std::string namer=Layout.name();
		outXML("AND->"+namer);
		std::string val=Layout.text().as_string();
		if(namer.compare("Filename")==0){
			if(!file_name(RETURN,val)){
				//outXML("Skipping="+val);
			}
		}
		if(namer.compare("Not")==0){
			for(pugi::xml_node tmp=Layout.first_child();tmp;tmp=tmp.next_sibling()){
				std::string namer2=tmp.name();
				std::string val2=tmp.text().as_string();
				outXML("AND->"+namer+"->"+namer2+"="+val2);
				if(namer2.compare("Filename")==0){
					NOTtheseFiles.push_back(val2);
				}
				if(namer2.compare("Category")==0){
					outXML("Not this Category:"+val2);
					NOT_CATEGORIES.push_back(val2);
				}
			}
		}
		if(namer.compare("Category")==0){
			theseCats.push_back(val);
			outXML("AND adding:"+val);
			CURRENT_CATEGORIES.push_back(val);
			//Category(val,RETURN);
		}
	}
	Category(theseCats,RETURN);
}
void OrProcessor(pugi::xml_node SUB, pugi::xml_node RETURN){
	outXML("OrProcessor");
	if(!SUB)return;
	if(!RETURN)return;
	pugi::xml_node Layout;
	std::vector<std::string> theseCats;
	for(Layout=SUB.first_child();Layout;Layout=Layout.next_sibling()){
		std::string namer=Layout.name();
		std::string val=Layout.text().as_string();
		if(namer.compare("Filename")==0){
			if(!file_name(RETURN,val)){
				//outXML("Skipping="+val);
			}
		}
		if(namer.compare("Category")==0){
			theseCats.push_back(val);
			outXML("OR adding:"+val);
			CURRENT_CATEGORIES.push_back(val);
			//Category(val,RETURN);
		}
	}
	Category(theseCats,RETURN);
}

void NOTProcessor(pugi::xml_node SUB){
	if(!SUB)return;
	pugi::xml_node Layout;
	std::vector<std::string> theseCats;
	for(Layout=SUB.first_child();Layout;Layout=Layout.next_sibling()){
		std::string namer=Layout.name();
		std::string val=Layout.text().as_string();
		if(namer.compare("Filename")==0){
			NOTtheseFiles.push_back(val);
		}
		if(namer.compare("Category")==0){
			outXML("Not this category:"+val);
			NOT_CATEGORIES.push_back(val);
			
		}
	}
}
std::vector<std::string> CheckVectorAndRemove(std::vector<std::string> VectorToCheck, std::string thingToRemove){
	std::vector<std::string> TEMPvector=VectorToCheck;
	std::vector<std::string>::iterator it = find (TEMPvector.begin(), TEMPvector.end(), thingToRemove);
	if (it != TEMPvector.end()){
		TEMPvector.erase(it);
		return TEMPvector;
	}
	return TEMPvector;
}
void Included(pugi::xml_node SUB, pugi::xml_node RETURN){
	//outXML("Included");
	NOTtheseFiles.clear();
	if(!SUB)return;
	if(!RETURN)return;
	std::vector <std::string> YESlist;
	std::copy( YESlist.begin(), YESlist.end(), std::back_inserter( DESKTOP_FILES ) );
	pugi::xml_node Layout;
	pugi::xml_node NAMEnode=SUB.parent();
	NAMEnode=NAMEnode.child("Name");
	std::string tmpCater=NAMEnode.name();
	std::vector<std::string> theseFiles;
	for(Layout=SUB.first_child();Layout;Layout=Layout.next_sibling()){
		std::string namer=Layout.name();
		std::string val=Layout.text().as_string();
		if(namer.compare("Or")==0){
			OrProcessor(Layout,RETURN);
		}
		if(namer.compare("Filename")==0){
			if(!file_name(RETURN,val)){
				//outXML("Skipping="+val);
			}
		}
		if(namer.compare("Category")==0){
			outXML("Included:"+val);
			CURRENT_CATEGORIES.push_back(val);
			//theseCats.push_back(val);
		}
		//these can hold category or filename
		if(namer.compare("And")==0){
			ANDProcessor(Layout,RETURN);
		}
		if(namer.compare("Not")==0){
			NOTProcessor(Layout);
		}
		
	}
	if(CURRENT_CATEGORIES.empty()){CURRENT_CATEGORIES.push_back(tmpCater);}
	
	if(!NOTtheseFiles.empty()){
		for(std::vector<std::string>::iterator itn=NOTtheseFiles.begin();itn!=NOTtheseFiles.end();++itn){
			YESlist=CheckVectorAndRemove(YESlist,*itn);
		}
	}
	//TODO check not list and Yes list to remove from yes list
	for(std::vector<std::string>::iterator it=YESlist.begin();it!=YESlist.end();++it){
		outXML("Yes List!");
		std::string fileName=*it;
		std::string cat=cat_line(fileName);
		std::vector<std::string> tmpCAT=linuxcommon::delimiter_vector_from_string(cat,";");
		if(!NOT_CATEGORIES.empty()){
			for(std::vector<std::string>::iterator itn=NOT_CATEGORIES.begin();itn!=NOT_CATEGORIES.end();++itn){
				if(!linuxcommon::look_for_string_in_vector(tmpCAT,*itn)){
					for(std::vector<std::string>::iterator itera=CURRENT_CATEGORIES.begin();itera!=CURRENT_CATEGORIES.end();++itera){
						std::string category=*itera;
						if(linuxcommon::look_for_string_in_vector(tmpCAT,category)){
							pugi::xml_node tmp=RETURN.append_child("Program");
							std::string numero, icon,tooltip,exec;
							exec=exec_line(fileName);
							if(exec.compare("")!=0){
								numero=get_name(fileName);
								icon=icon_line(fileName);
								if(icon.compare("")==0){icon="application-default-icon";}
								if(numero.compare("")==0){numero=exec;}
								tmp.append_attribute("label")=numero.c_str();
								tmp.append_attribute("icon")=icon.c_str();
								if(USECOMMENTS){
									tooltip=get_comment(fileName);
									if(tooltip.compare("")==0){tooltip=numero;}
									tmp.append_attribute("tooltip")=tooltip.c_str();
								}
								tmp.append_child(pugi::node_pcdata).set_value(exec.c_str());
							}
						}
					}
				}
			}
		}
	}
}
bool make_submenu(pugi::xml_node SUB, pugi::xml_node RETURN){
	//outXML("make_submenu");
	if(!SUB)return false;
	if(!RETURN)return false;
	if(MERGE_inception){return false;}
	pugi::xml_node OnlyUnallocated,Layout;
	std::string DIR_FILE,NAME,ICON,TOOLTIP;
	if(!INCEPTION)CURRENT_CATEGORIES.clear();
	NAME=SUB.child("Name").text().as_string();
	TOOLTIP=NAME;
	ICON="application-default-icon";
	if(DIRECTORY_FILES.empty()){DIRECTORY_FILES=categoryDirs();}
	if(SUB.child("Directory")){
		std::string fileNoPath=SUB.child("Directory").text().as_string();
		
		DIR_FILE=linuxcommon::test_file_in_vector_path(fileNoPath,DIRECTORY_FILES);	
		//outXML("**********************"+fileNoPath+":"+DIR_FILE);
		if(DIR_FILE.compare("")!=0){
			TOOLTIP=get_comment(DIR_FILE);
			NAME=get_name(DIR_FILE);
			ICON=icon_line(DIR_FILE);	
		}
	}
	RETURN=RETURN.append_child("Menu");
	RETURN.append_attribute("label")=NAME.c_str();
	RETURN.append_attribute("icon")=ICON.c_str();
	outXML("make_submenu:"+NAME);
	if(SUB.child("Include")){
		Included(SUB.child("Include"),RETURN);
	}
	if(SUB.child("Separator")){RETURN.append_child("Separator");}
	if(SUB.child("Filename")){
		std::string val=SUB.child("Filename").text().as_string();
		if(!file_name(RETURN,val)){
			//outXML("Skipping="+val);
		}
	}
	
	if(SUB.child("Layout")){
		if(!LayoutMaker(SUB.child("Layout"),RETURN)){return false;}
	}
	if(SUB.child("MergeFile")){
		//TODO
	}
	if(SUB.child("OnlyUnallocated")){
		//how do I do this for a middle Other??
		for( std::list<std::string>::iterator it=DESKTOP_FILES.begin();it!=DESKTOP_FILES.end();++it){
			std::string tempentry=*it;
			if(!file_name(RETURN,tempentry)){
				outXML("Failed to process:"+tempentry);
			}
			
		}
	}
	RETURN=RETURN.parent();
	return true;
}
void test(){
	if(!make_menu_xdg("/etc/xdg/menus/xfce-applications.menu","/home/israeldahl/temp.xml")){
		outXML("FAILED!!!");
		menumaker();
	}
}
std::vector<std::string> DefaultCategories(){
	std::string d1="Utility";
	std::string d2="Games";
	std::string d3="Graphics";
	std::string d4="AudioVideo";
	std::string d5="Settings";
	std::string d6="System";
	std::string d7="Other";
	std::vector<std::string> DEFAULT;
	DEFAULT.push_back(d1);
	DEFAULT.push_back(d2);
	DEFAULT.push_back(d3);
	DEFAULT.push_back(d4);
	DEFAULT.push_back(d5);
	DEFAULT.push_back(d6);
	DEFAULT.push_back(d7);
	return DEFAULT;
}
void resetMergeTypes(){
	MERGEMENUS=0;
	MERGEFILES=0;
}
bool Merge(pugi::xml_node MergeNode, pugi::xml_node RETURN){
	// if we don't have any more menu nodes, get out!!!
	if(MENU_NODES.empty()){return false;}
	/* We NEED to prevent getting lost in the dream world here...
	 * So, lets check for some crazy inception stuff
	 * 
	 * doc (Our loaded Document)
	 *   Menu (The main Menu XML element)
	 *      Menu (A category Menu)
	 *        Layout
	 *          Merge (Uh oh... this is getting inception-y)
	 */
	 //This should be doc->Menu->Layout->Merge
	pugi::xml_node inceptionNode=MergeNode.parent().parent();
	if(inceptionNode!=doc.child("Menu")){
		MERGE_inception=true;
	}
	else{MERGE_inception=false;}
	std::string mergetype=MergeNode.attribute("type").as_string();
	/* Find out what type of merge we are doing...
	 * 
	 * from freedesktop.org:
	 * type="menus"|"files"|"all"
	 * menus - all sub-menus that are not explicitly mentioned should be inserted in alphabetical order of their visual caption at this point
	 * files - all desktop entries contained in this menu that are not explicitly mentioned should be inserted in alphabetical order of their visual caption at this point.
	 * all -a mix of all sub-menus and all desktop entries that are not explicitly mentioned should be inserted in alphabetical order of their visual caption at this point.
	 */
	
	//outXML("Merge Menus type:"+mergetype);
	
	//If it is menus
	if(mergetype.compare("menus")==0){
		MERGEMENUS=1;
		//if we don't have merge files yet set it to -1 to avoid bring in ALL files just yet.
		if(MERGEFILES==0){MERGEFILES=-1;}
	}
	if(mergetype.compare("files")==0){
		MERGEFILES=1;
		// we can run merge files now after merge menus if merge type=menus exists as well
		if(MERGEMENUS==0){MERGEMENUS=-1;}
	}
	if(mergetype.compare("all")==0){
		MERGEMENUS=1;
		MERGEFILES=1;
	}
	if(MERGEMENUS==1){
		/* Menu
		 *   Name <--- THIS = comp
		 *   Layout
		 *     Merge <-- THIS = MergeNode
		 */
		std::string comp=MergeNode.parent().parent().child("Name").text().as_string();
		bool EVERYTHING=false;
		if(MergeNode.parent().parent()==doc.child("Menu")){
			EVERYTHING=true;
		}
		outXML("Merging Menus");
		std::vector<pugi::xml_node>::iterator iter = MENU_NODES.begin();
		std::string BAIL;
		while(iter!=MENU_NODES.end()){
			NOT_CATEGORIES.clear();
			pugi::xml_node tmp=*iter;
			std::string numero=tmp.child("Name").text().as_string();
			if(numero.compare(BAIL)==0){return false;}
			if(EVERYTHING){
				BAIL=numero;
				make_submenu(tmp,RETURN);
				outXML("'EVERYTHING' Erasing:"+numero);
				iter=MENU_NODES.erase(iter);
			}
			else{
				std::string category;
				//outXML("Menu:"+numero);
				if(comp.compare(numero)==0){
					outXML("Found menu!! = "+numero);
					iter=MENU_NODES.erase(iter);
					
					return make_submenu(tmp,RETURN);
				}
				else{++iter;}
			}
				
		}
		if(EVERYTHING){
			CURRENT_CATEGORIES.clear();
			MENU_NODES.clear();
			return true;
		}
	}
	else if((MERGEMENUS!=-1)&&(MERGEFILES==1)){
		outXML("Merging Files");
		for( std::list<std::string>::iterator it=DESKTOP_FILES.begin();it!=DESKTOP_FILES.end();++it){
			std::string tempentry=*it;
			if(!file_name(RETURN,tempentry)){outXML("Failed to process:"+tempentry);}
		}
		return false;
	}
	else{return false;}
	return false;
}
bool LayoutMaker(pugi::xml_node Layout, pugi::xml_node RETURN){
	if(!Layout){return false;}
	if(!RETURN){return false;}
	outXML("bool LayoutMaker(pugi::xml_node Layout, pugi::xml_node RETURN)");
	MERGEFILES=0;
	MERGEMENUS=0;
	if(!Layout.child("Merge")){return false;}
	INCEPTION=true;
	NOT_CATEGORIES.clear();
	for(Layout=Layout.first_child();Layout;Layout=Layout.next_sibling()){
		std::string namer=Layout.name();
		std::string val=Layout.text().as_string();
		if(namer.compare("Separator")==0){RETURN.append_child("Separator");}
		else if(namer.compare("Filename")==0){
			//outXML("Layout Filename");
			if(!file_name(RETURN,val)){
				//outXML("Skipping="+val);
			}
		}
		if(namer.compare("Menuname")==0){
			//outXML("Menuname");
			int it=0;
			for( std::vector<std::string>::iterator iter = MENU_NAMES.begin();
			iter!=MENU_NAMES.end();
			++iter){
				std::string testPATH = *iter;
				//outXML("Menu Name="+testPATH+" Trying to find:"+val);
				if(testPATH.compare(val)==0){
					outXML("Menuname found:"+testPATH);
					if(MENU_NODES.empty()){return false;}
					pugi::xml_node currentmenu_node=MENU_NODES[it];
					//RETURN=RETURN.parent();
					int count=0;
					for(std::vector<pugi::xml_node>::iterator item=MENU_NODES.begin();item!=MENU_NODES.end();++item){
						if(count==it){
							//outXML("Erasing node...");
							MERGE_inception=false;
							currentmenu_node=*item;
							if(!make_submenu(currentmenu_node,RETURN)){outXML("Did not make Menuname Menu for:"+val);}
							item=MENU_NODES.erase(item);
							break;
						}
						count++;
					}
					//else{RETURN=RETURN.parent();}
					
					
				//make_submenu
				}
				it++;
			}
			
		/* [show_empty="true"|"false"]
		 * [inline="true"|"false"]
		 * [inline_limit="integer"]
		 * [inline_header="true"|"false"]
		 * [inline_alias="true"|"false"]
		 * 
		*/
		}
		if(namer.compare("Merge")==0){
			if(!Merge(Layout,RETURN)){outXML("Didn't work out");}
			else{return true;}
		}
	}
	INCEPTION=false;
	CURRENT_CATEGORIES.clear();
	NOT_CATEGORIES.clear();
	return true;
}
bool make_menu_xdg(std::string infile,std::string outfile){
	//outXML("bool make_menu_xdg(std::string "+infile+",std::string "+outfile+")");
	if(!linuxcommon::test_file(infile)){return false;}
	if(outfile.compare("")==0){return false;}
	pugi::xml_node node,SUB,Layout,RETURN, DIRdirs, menuNameNode, APPdirs;
	//outXML("LOAD:"+infile);
	pugi::xml_parse_result result = doc.load_file(infile.c_str());
	if(!result){
		std::cout << "<!--Load result: " << result.description() << "\nError offset: " << result.offset <<"-->"<< std::endl;
		return false;
	}
	node=doc.child("Menu");
	if(!node){return false;}
	if(cache.load(outfile.c_str())){cache.reset();}
	RETURN=cache.append_child("JWM");
	SUB=node;
	std::vector<pugi::xml_node> WAITVector;
	for(menuNameNode=node.child("Menu");menuNameNode;menuNameNode=menuNameNode.next_sibling()){
		std::string thisNAME=menuNameNode.child("Name").text().as_string();
		if(thisNAME.compare("")!=0){
			if(menuNameNode.child("OnlyUnallocated")){
				WAITVector.push_back(menuNameNode);
			}
			else{
				//outXML("Adding "+thisNAME+" menu to MENU_NODES");
				MENU_NAMES.push_back(thisNAME);
				MENU_NODES.push_back(menuNameNode);
			}
				
		}
	}
	if(!WAITVector.empty()){
		for(std::vector<pugi::xml_node>::iterator itn=WAITVector.begin();itn!=WAITVector.end();++itn){
			menuNameNode=*itn;
			std::string thisNAME=menuNameNode.child("Name").text().as_string();
			//outXML("OnlyUnAllocated adding "+thisNAME+" to the end");
			if(thisNAME.compare("")!=0){
				MENU_NAMES.push_back(thisNAME);
				MENU_NODES.push_back(menuNameNode);
			}
		}
	}
	if(node.child("DefaultAppDirs")){
		DESKTOP_DIRS=linuxcommon::desktop_paths();
	}
	for(APPdirs=node.child("AppDir");APPdirs;APPdirs=APPdirs.next_sibling()){
		std::string tmp=APPdirs.text().as_string();
		if(tmp.compare("")!=0){DESKTOP_DIRS.push_back(tmp);}
	}
	for(pugi::xml_node mergerDir=node.child("MergeDir");mergerDir;mergerDir=APPdirs.next_sibling()){
		std::string tmp=mergerDir.text().as_string();
		if(tmp.compare("")!=0){
			if(!linuxcommon::test_file(tmp)){
				std::string path=linuxcommon::get_directory_from_filename(infile);
				tmp=path+tmp;
			}
			MERGE_DIRS.push_back(tmp);
		}
	}
	if(node.child("DefaultMergeDirs")){MERGE_DIRS=addMergeDirs(MERGE_DIRS);}
	//TODO actually support merge directories
	if(node.child("DefaultDirectoryDirs")){
		std::vector<std::string> tmpVector=categoryDirs();
		DIRECTORY_FILES.insert( DIRECTORY_FILES.end(), tmpVector.begin(), tmpVector.end());
	}
	
	for(DIRdirs=node.child("DirectoryDir");DIRdirs;DIRdirs=DIRdirs.next_sibling()){
		std::string tmp=DIRdirs.text().as_string();
		if(tmp.compare("")!=0){DIRECTORY_FILES.push_back(tmp);}
	}
	
	/* IF JWM ever supports naming the tray button here...
	std::string MENU_NAME="Applications";
	pugi::xml_node temp=node.child("Directory");
	if(temp){
		std::string TEMPstring=temp.text().as_string();
		if(TEMPstring.compare("")!=0){MENU_NAME=get_name(TEMPstring);}
	}
	*/
	DESKTOP_FILES=get_desktop_files();
	if(node.child("Include")){
		Included(node.child("Include"),RETURN);
	}
	if(node.child("Layout")){
		outXML("Main Layout");
		LayoutMaker(node.child("Layout"),RETURN);
	}
	else{
		if(!make_submenu(node,RETURN)){return false;}
	}
	if(!cache.save_file(outfile.c_str())){
		outXML("FAILED TO SAVE:"+outfile);
		return false;
	}
	linuxcommon::print_file_to_stdout(outfile);
	return true;	
}
std::string make_menu_xdg(std::string prefix){
	
	std::vector<std::string> catarray;
	std::string apps="applications.menu";
	std::string menu_filename,line,JWM_MENU;
	std::vector<std::string> confdirs_array=linuxcommon::split_paths("XDG_CONFIG_DIRS","/etc/xdg:/etc/xdg/xdg-torios");
	std::string testPATH,dirToUse;
	//std::vector<std::string> MENUS=xdgmenufiles();
	std::vector<std::string> directoryFiles;
	
	//make sure this isn't blank
	std::string nO="<Name>";
	std::string mO= "<Menu>";
	std::string mC= "</Menu>";
	std::string layoutO="<Layout>";
	std::string dO="<Directory>";
	std::string iO="<Include>";
	std::string aO="<And>";
	std::string cO="<Category>";
	std::string NOT="<Not>";
	std::string NOTc="</Not>";
	std::string appdirs="<DefaultAppDirs/>";
	std::string dirdirs="<DefaultDirectoryDirs/>";
	std::string mergedirs="<DefaultMergeDirs/>";
	std::string testEntry;
	bool Include,No;
	//bool AppDirs=false;
	//bool DirDirs=false;
	Include=false;
	No=false;
	unsigned int baseMenu=0;
	std::string BASENAME,tempCat, NAME,DIRECTORY,CATEGORY;
	testPATH=whichMenu(prefix);
	//outXML("Using MENU: "+testPATH);
	if(testPATH.compare("")!=0){
		std::ifstream inputFileStrem (testPATH.c_str(), std::ifstream::in);
		if(inputFileStrem.is_open()){	
			while (getline(inputFileStrem,line)){
				unsigned int length =line.length();
				//RESET if we reach the end of a category
				if( (line.find(mO)) < length ){
					baseMenu++;
				}
				if( (line.find(mergedirs))<length ){directoryFiles=addMergeDirs(directoryFiles);}
				if( (line.find(NOT)) < length ){No=true;}
				if( (line.find(dirdirs))<length ){
						std::vector<std::string> tmpVector=categoryDirs();
						directoryFiles.insert( directoryFiles.end(), tmpVector.begin(), tmpVector.end() );
				}
				if( (line.find(mC)) < length ){
					if(baseMenu>1){
						catarray=linuxcommon::sort_array(catarray);
						directoryFiles=linuxcommon::sort_array(directoryFiles);
						unsigned int finder=0;
						testEntry=makeXDGmenu(catarray,directoryFiles);
						finder=JWM_MENU.find(testEntry);
						if(finder>JWM_MENU.length()){
							//outXML(JWM_MENU);
							JWM_MENU+=testEntry;
						}
						NAME="";
						catarray.clear();
						directoryFiles.clear();
						
					//Boolean reset
						//AppDirs=false;
						//DirDirs=false;
						Include=false;
						No=false;
					}
				}
				if (NAME.compare("")==0){
					if( (line.find(nO)) < length ){
						if(BASENAME.compare("")==0){BASENAME=chopTAG(line);}
						else{
							NAME=chopTAG(line);
							if (NAME.compare("")!=0){
								//outXML("adding Category: " + NAME);
								catarray.push_back(NAME);
							}
						}
					}
				}
				else{
					//if( (line.find(appdirs))<length ){AppDirs=true;}
					if(!Include){
						if( (line.find(dO)) < length){
							DIRECTORY=chopTAG(line);
							//outXML("adding direcotry: " + DIRECTORY);
							directoryFiles.push_back(DIRECTORY);
						}
						if( (line.find(iO)) <length){Include=true;}
					}
					else{
						if(!No){
							if( (line.find(cO)) <length ){
								CATEGORY=chopTAG(line);
								//outXML("adding Category: " + CATEGORY);
								catarray.push_back(CATEGORY);
							}
							
						}
						else{if( (line.find(NOTc)) <length ){No=false;}}
					}
				}
			}
		}
	}
	
	if(JWM_MENU.compare("")==0){return make_menu();}
	return JWM_MENU;
}

std::vector<std::string> xdgmenufiles(){
		//$XDG_CONFIG_DIRS/menus/${XDG_MENU_PREFIX}applications.menu
	std::string dirToOpen = "/etc/xdg/menus/";
	std::string pathToGet = "/menus/";
	std::string testPATH,tester,result,fullpath;
	std::vector<std::string> MENUS;
    std::vector<std::string> uniqueDirs = linuxcommon::split_paths("XDG_CONFIG_DIRS","/etc/xdg:/etc/xdg/xdg-torios");
	unsigned int found = 0;
    //initialize directory reading variables to NULL
    DIR *dir = NULL;
	struct dirent *entryPointer = NULL;
   	for( std::vector<std::string>::iterator it = uniqueDirs.begin();
			it!=uniqueDirs.end();
			++it){
        //get the string equvalent for the integer representation if of the xdg path
        // something like
        /*
        1=/usr/share/
        2=/usr/local/share
        etc...
        */
		testPATH = *it;
		//make sure this isn't blank
		if(testPATH.compare("")!=0){
			//look to see if we have a / at the end... remove it if we do...
			found = testPATH.rfind('/');
			if (found == testPATH.length()-1){testPATH=testPATH.substr(0,testPATH.length()-1);}
			//see if there is a pathToGet directory
			dirToOpen = testPATH + pathToGet;
			dir = opendir(dirToOpen.c_str());
			if(dir!=NULL){
		    while ((entryPointer=readdir(dir)) != NULL){
				if ((entryPointer->d_type == DT_REG)&&(entryPointer->d_name[0] != '.')){
					fullpath = entryPointer->d_name;
					result=dirToOpen+fullpath;
					tester=dirToOpen+fullpath;
					unsigned period = result.rfind(".");
					bool isMENU = false;
					if(result.compare("")!=0){
						if(period<result.length()){
							std::string testmenu = result.substr(period+1,std::string::npos);
							if(testmenu.compare("menu")==0){isMENU = true;}
						}
						if(isMENU){
							MENUS.push_back(result); 
						} //isMENU
					}//result !empty
				}//it is a file
			}//readdir is not NULL
			}//dir!=NULL
			closedir(dir);
		}//testPath is not ""
	}//directory looper
	
	return MENUS;
}

std::vector<std::string> addMergeDirs(std::vector<std::string> directoryFiles){
	//outXML("std::vector<std::string> addMergeDirs(std::vector<std::string> directoryFiles)");
	std::string dirToOpen = "/etc/xdg/menus/applications-merged/";
	std::vector<std::string> MENUS= linuxcommon::split_paths("XDG_CONFIG_DIRS","/etc/xdg:/etc/xdg/xdg-torios");
	DIR *dir = NULL;
	struct dirent *entryPointer = NULL;
	std::string result;
	std::string fullpath="/menus/applications-merged/";
	for( std::vector<std::string>::iterator it = MENUS.begin();
		it!=MENUS.end();
		++it){
		
		dirToOpen=*it;
		dirToOpen+=fullpath;
		dir = opendir(dirToOpen.c_str());
		if (dir!=NULL){
			while ((entryPointer=readdir(dir)) != NULL){
				if ((entryPointer->d_type == DT_REG)&&(entryPointer->d_name[0] != '.')){
					result=dirToOpen;
					result += entryPointer->d_name;
					unsigned period = result.rfind(".");
					bool isMENU = false;
					if(result.compare("")!=0){
						if(period<result.length()){
							std::string testMenu = result.substr(period+1,std::string::npos);
							if(testMenu.compare("menu")==0){isMENU = true;}
						}
						if(isMENU){directoryFiles.push_back(dirToOpen);/*outXML("Merge Dir: "+dirToOpen);*/} //isMENU
					}//result !empty
				}//dirent is file
			}//dirent !NULL
		}//directory !NULL
	}
	closedir(dir);
	return directoryFiles;
}
std::vector<std::string> categoryDirs(){
	//outXML("std::vector<std::string> categoryDirs()");
	std::string DD="/desktop-directories/";
	std::string dirToOpen,testPATH;
	const char* home=getenv("HOME");
	std::vector<std::string> dirVector;
	std::vector<std::string> tmpVector;
	std::vector<std::string> returnVector;
	unsigned int found=0;
	std::string HOME;
	if(home != NULL){
		HOME=home;
	}
	std::string getdirs=HOME;
	if(HOME.compare("")!=0){
	  getdirs+="/.local/share/";
	  dirVector=linuxcommon::split_paths("XDG_DATA_HOME",getdirs.c_str());
	}
	//get the data dirs
	tmpVector=linuxcommon::split_paths("XDG_DATA_DIRS","/usr/share:/usr/local/share");
	//insert the data dirs on the data home (if it exists);
    dirVector.insert(dirVector.end(),tmpVector.begin(),tmpVector.end());
	for( std::vector<std::string>::iterator it = dirVector.begin();
		it!=dirVector.end();
		++it){
		//the current string in the vector
		testPATH = *it;
		//make sure this isn't blank
		if(testPATH.compare("")!=0){
			//look to see if we have a / at the end... remove it if we do...
			found = testPATH.rfind('/');
			if (found == testPATH.length()-1){testPATH=testPATH.substr(0,testPATH.length()-1);}
			//see if there is a pathToGet directory
			dirToOpen = testPATH + DD;
			//see if it has the desktop directories folder
			if(linuxcommon::test_dir(dirToOpen)){returnVector.push_back(dirToOpen);}
		}
	}
	return returnVector;
}
void writeOut(std::string MSG){
	std::cout<<MSG<<std::endl;
	if(!linuxcommon::save_string_to_file(MSG,MENU_CACHE_FILE)){
		outXML("File DID NOT SAVE");
	}
}
