
/*
 * places-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
 * 
 */

#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 "../include/common.hpp"
#include "../include/pugixml.hpp"
////////////////////////////////////////////////////////GLOBAL VARIABLES
//global variable used to track current depth
unsigned int tempDepth;
//Are we printing debug info?
bool DEBUG;
// the home directory
std::string home;
// the filename we write out to
std::string PLACES_FILENAME;
//Global document
pugi::xml_document doc;

///////////////////////////////////////////////////////////////FUNCTIONS

//UNSIGNED INT
//convert our CLI arg to a number
unsigned int convert(const char* num);
//read the config file and get the levels deep we will go
unsigned int submenuDepth();

//INT
//basically do both make_places() and make_gtk_places()
int make_full_menu();
// read the gtk config files for places
int make_gtkplaces();
// simple home directory for a 'none of the above' situation
int make_home();
// kinda lame but use the CLI xdg tools to get some directories
int make_places();
int usage();
///BOOLEAN
//check for files related to bookmarks, etc..
bool check_files();
//test directories
bool testDir(std::string dirToTest);
//test executable things
bool testEXEC(std::string execToTest);
// set the submenu depth (how many levels deep must we go?)
bool setSubmenuDepth(unsigned int value);

//VOID
//print a message to stdout with XML quoting (useful for debugging return values!!)
void outXML(std::string message);

//STRING
// a blank JWM file in case nothing exists already
std::string default_JWM();
//fix a directory for XDG open
std::string fixDirForOPEN(std::string input);
//get our temp filename
std::string getCacheFilename();
//get the file that has submenu depth
std::string getConfigFile();
//get a line from a file
std::string get_line(std::string filename, std::string line);
//replace things (like sed on the CLI)
std::string sed(std::string input, std::string remove, std::string replace);

//PUGI
//add a <Menu> node
pugi::xml_node addMenu(std::string icon, std::string name, std::string dir,pugi::xml_node parentnode);
//add a <Program> node
pugi::xml_node addProgram(std::string icon, std::string name, std::string dir,pugi::xml_node parentnode);
// add a SFTP entry
pugi::xml_node addSFTP(std::string icon, std::string name, std::string dir,pugi::xml_node parentnode);
//look in a directory and decide (based on levels deep) if we are making a Menu or Program node
pugi::xml_node make_submenu(std::string dirToOpen, std::string whatName, std::string whatIcon,pugi::xml_node myNode);
//make a trash node (the user's trash can) and return it or NULL
pugi::xml_node make_trash(pugi::xml_node basenode);


int main(int argc, char* argv[]) {
	DEBUG=false;
	PLACES_FILENAME=getCacheFilename();
	home = linuxcommon::home_path();
    if(home.compare("")==0){return 42;}
	const char* path = getenv("PATH");
    if(path==NULL){return 42;}
    std::string arg;
    std::string configFile=getConfigFile();
    unsigned int menuDepth =menuDepth =submenuDepth();
    int result=0;
    bool printNOW=false;
    if(argc>0){
		if(argv[1]!=NULL){
			arg=argv[1];
			if(arg.compare("--debug")==0){DEBUG=true;}
			else if(arg.compare("-debug")==0){DEBUG=true;}
			else if(arg.compare("--full")==0){
				result=make_full_menu();
				if(result==0){printNOW=true;}
			}
			else if(arg.compare("--gtk-places")==0){
				result=make_gtkplaces();
				if(result==0){printNOW=true;}
			}
			else if(arg.compare("--home")==0){
				result=make_home();
				if(result==0){printNOW=true;}
			}
			else if(arg.compare("--places")==0){
				result=make_places();
				if(result==0){printNOW=true;}
			}
			else if((arg.compare("--help")==0)||(arg.compare("-h")==0)||(arg.compare("-?")==0)){
				return usage();
			}
			else{
				menuDepth=convert(arg.c_str());
				setSubmenuDepth(menuDepth);
			}
		}
	}
	if(printNOW){
		linuxcommon::print_file_to_stdout(PLACES_FILENAME);
		return result;
	}
	std::string gtk3bm;
	tempDepth = menuDepth;
	const char* xdg_conf = getenv("XDG_CONFIG_HOME");
	if(xdg_conf == NULL){
		gtk3bm = home;
		gtk3bm += ".config/gtk-3.0/bookmarks";
	}
	else{
		gtk3bm = xdg_conf;
		gtk3bm += "/gtk-3.0/bookmarks";
	}
	// see what we have to make a menu with...
    if( !linuxcommon::test_file(gtk3bm.c_str()) ){
		//NO GTK bookmarks
		if(!check_files()){
			//NO XDG variables
			//outXML("HOME menu");
			result = make_home();
		}
		else{
			//XDG menu ONLY
			//outXML("XDG Places Menu");
			result = make_places();
		}
	}
	else{
		//we have gtk bookmarks
		if(!check_files()){
			//no xdg variables
			result = make_gtkplaces();
		}
		else{
			//EVERYTHING
			//outXML("XDG Places and GTK bookmarks Menu");
			result = make_full_menu();
		}
	}
    linuxcommon::print_file_to_stdout(PLACES_FILENAME);
	return result;
}
////////////////////////////////////////////////////////////UNSIGNED INT
unsigned int convert(const char* num){return linuxcommon::convert_string_to_number(num);}
unsigned int submenuDepth(){
	//this returns 0 if all else fails
	std::string configFile=getConfigFile();
	if(!linuxcommon::test_file(configFile.c_str())){return 0;}
//submenus= is our one liner for our config
	std::string submenuString=get_line(configFile,"submenus=");
	if(submenuString.compare("")==0){return 0;}
	return convert(submenuString.c_str());
}
/////////////////////////////////////////////////////////////////////INT
int make_full_menu(){
	outXML("Make FULL menu");
	unsigned int submenus=submenuDepth();
	tempDepth=submenus;
	PLACES_FILENAME=getCacheFilename();
	if(!linuxcommon::test_file(PLACES_FILENAME)){
		std::string CONTENTS=default_JWM();
		linuxcommon::save_string_to_file(CONTENTS,PLACES_FILENAME);
	}
	pugi::xml_node node;
	if(!doc.load(PLACES_FILENAME.c_str()) ){
		node=doc.append_child("JWM");
		doc.save_file(PLACES_FILENAME.c_str());
	}
	else{
		node=doc.child("JWM");//Initialize our node variable
	}
	std::string filename;
	const char* xdg_conf = getenv("XDG_CONFIG_HOME");
	std::string homer=linuxcommon::home_path();
	if(homer.compare("")==0){return -1;}
	if(xdg_conf ==NULL){
		filename = homer;
		filename += ".config/";
	}
	else{filename = xdg_conf;}
	filename += "/gtk-3.0/bookmarks";
	//check for file or simply run make_places();
	if(!linuxcommon::test_file(filename.c_str()) ){return make_places();}
	
	std::string XDG_COMM="xdg-user-dir";
	std::string DOCUMENTS=linuxcommon::term_out(XDG_COMM + " DOCUMENTS");
	std::string DOWNLOADS=linuxcommon::term_out(XDG_COMM + " DOWNLOAD");
	std::string MUSIC=linuxcommon::term_out(XDG_COMM + " MUSIC");
	std::string PICTURES=linuxcommon::term_out(XDG_COMM + " PICTURES");
	std::string VIDEOS=linuxcommon::term_out(XDG_COMM + " VIDEOS");

    std::string HOME = home;
	unsigned int length = HOME.length();
	std::string VIDEOS_NAME= VIDEOS;
	VIDEOS_NAME = VIDEOS_NAME.erase(0,length);
	std::string DOCUMENTS_NAME = DOCUMENTS;
	DOCUMENTS_NAME = DOCUMENTS_NAME.erase(0,length);
	std::string DOWNLOADS_NAME= DOWNLOADS;
	DOWNLOADS_NAME = DOWNLOADS_NAME.erase(0,length);
	std::string MUSIC_NAME= MUSIC;
	MUSIC_NAME = MUSIC_NAME.erase(0,length);
	std::string PICTURES_NAME= PICTURES;
	PICTURES_NAME = PICTURES_NAME.erase(0,length);
	
	//temporary... eventually check file for this..
	std::string HOME_NAME;
	const char* user=getenv("USER");
	if(user != NULL){
		 HOME_NAME=user;
	}
	else{
		 HOME_NAME=linuxcommon::term_out(XDG_COMM + " HOME");
		 HOME_NAME= HOME_NAME.erase(0,5);
	}
	
	std::string HOME_ICON="folder-home";
	std::string DOCUMENTS_ICON="folder-documents";
	std::string DOWNLOADS_ICON="folder-downloads";
	std::string MUSIC_ICON="folder-music";
	std::string PICTURES_ICON="folder-pictures";
	std::string VIDEOS_ICON="folder-video";
	std::string FOLDER_ICON="folder";
	std::string NET_FOLDER_ICON="network";
	pugi::xml_node BASE=node;
	//node=doc.child("JWM");
	if(homer.compare("")!=0){
		pugi::xml_node simp=addProgram(HOME_ICON,HOME_NAME,homer,node);
		if(!simp)outXML("Didn't add "+homer);
		else{node=simp;}
	}
	//Make the menu...
	unsigned int found;
	std::string comparename,whatName,line;
	std::ifstream inputFileStrem (filename.c_str(), std::ifstream::in);	
	if(inputFileStrem.is_open()){
		while (getline(inputFileStrem,line)){
			bool isSFTP=false;
			std::string tmpFIND="file:";
			found=line.find(tmpFIND);
			if(found < line.length()){
				line = line.erase(0,(found+tmpFIND.length()+2));
				comparename = line;
				found = 0;
				found = comparename.rfind('/');
				if(found < comparename.length()){
					comparename=comparename;
				}
			}
			tmpFIND="sftp:";
			unsigned int sftp=line.find(tmpFIND);
			if(sftp < line.length()){
				line=line.erase(0,(sftp+tmpFIND.length()+2));
				comparename=line;
				sftp = comparename.rfind('/');
				if(sftp < comparename.length()){
					comparename=comparename;
				}
				isSFTP=true;
			}
			whatName = line;
			found=line.find(' ');
			if(found< line.length()){
				whatName = whatName.erase(0,found+1);
				line=line.erase(found,std::string::npos);
				while ( line.find("%20")<line.length() ){
					found = line.find("%20");
					if(found < line.length() ){
						std::string temp1 = line;
						std::string temp2 = line;
						temp1 = temp1.erase(found, std::string::npos);
						temp2 = temp2.erase(0,found+3);
						line = temp1 + " " + temp2;
				  
					}
				}
			}
			unsigned int findSPACE=whatName.rfind("/");
			//node=doc.child("JWM");
			tempDepth=submenuDepth();
			if(findSPACE<whatName.length()){whatName=whatName.erase(0,findSPACE+1);}
			if( (line.compare(DOCUMENTS)==0) || (whatName.compare(DOCUMENTS_NAME)==0) ){
				pugi::xml_node tmp=make_submenu(DOCUMENTS,DOCUMENTS_NAME,DOCUMENTS_ICON,node);
				if(!tmp){
					node=BASE;
					outXML("Didn't make DOCUMENTS:"+line);}
				else{node=tmp;}
			}
			else if( (line.compare(DOWNLOADS)==0) || (whatName.compare(DOWNLOADS_NAME)==0) ){
				pugi::xml_node tmp=make_submenu( DOWNLOADS, DOWNLOADS_NAME, DOWNLOADS_ICON,node);
				if(!tmp){outXML("Didn't make DOWNLOADS:"+line);}
				else{node=tmp;}
			}
			else if( (line.compare(MUSIC)==0) || (whatName.compare(MUSIC_NAME)==0) ){
				pugi::xml_node tmp=make_submenu(MUSIC ,MUSIC_NAME, MUSIC_ICON,node);
				if(!tmp){outXML("Didn't make MUSIC:"+line);}
				else{node=tmp;}
			}
			else if( (line.compare(PICTURES)==0) || (whatName.compare(PICTURES_NAME)==0) ){
				pugi::xml_node tmp=make_submenu( PICTURES, PICTURES_NAME, PICTURES_ICON,node);
				if(!tmp){outXML("Didn't make PICTURES:"+line);}
				else{node=tmp;}
			}
			else if( (line.compare(VIDEOS)==0) || (whatName.compare(VIDEOS_NAME)==0) ){
				pugi::xml_node tmp=make_submenu(VIDEOS , VIDEOS_NAME, VIDEOS_ICON,node);
				if(!tmp){outXML("Didn't make VIDEOS:"+line);}
				else{node=tmp;}
			}
			else{
				pugi::xml_node tmp;
				if(!isSFTP){tmp=make_submenu(line,whatName,FOLDER_ICON,node);}
				else{tmp=addSFTP(NET_FOLDER_ICON, whatName, line, node);}
				
				if(!tmp){
					node=BASE;
					outXML("Didn't make BOOKMARK:"+line);
				}
				else{node=tmp;}
			}
		}
	}
	else{outXML("inputFileStream didn't open..");}
	//get parent node
	//node=doc.child("JWM");
	pugi::xml_node tmp=make_trash(node);
	if(!tmp)outXML("Didn't make trash");
	int retval=0;
	if(!doc.save_file(PLACES_FILENAME.c_str())){retval=1;}
	return retval;
}
int make_gtkplaces(){
	unsigned int submenus=submenuDepth();
	tempDepth=submenus;
	PLACES_FILENAME=getCacheFilename();
	if(!linuxcommon::test_file(PLACES_FILENAME)){
		std::string CONTENTS=default_JWM();
		linuxcommon::save_string_to_file(CONTENTS,PLACES_FILENAME);
	}
	pugi::xml_node node;
	if(!doc.load(PLACES_FILENAME.c_str()) ){
		node=doc.append_child("JWM");
		doc.save_file(PLACES_FILENAME.c_str());
	}
	else{
		node=doc.child("JWM");//Initialize our node variable
	}
	std::string HOME_ICON="folder-home";
	std::string DOCUMENTS_ICON="folder-documents";
	std::string DOWNLOADS_ICON="folder-downloads";
	std::string MUSIC_ICON="folder-music";
	std::string PICTURES_ICON="folder-pictures";
	std::string VIDEOS_ICON="folder-video";
	std::string FOLDER_ICON="folder";
	std::string NET_FOLDER_ICON="network";
	std::string line,filename,whatName;
	const char* xdg_conf = getenv("XDG_CONFIG_HOME");
	if(xdg_conf ==NULL){
		std::string temphome = linuxcommon::home_path();
		if(temphome.compare("")!=0){
			filename =temphome;
			filename+=".config";
		}
		else{return -1;}
	}
	else{filename = xdg_conf;}
	filename += "/gtk-3.0/bookmarks";
	if(!linuxcommon::test_file(filename.c_str()) ){outXML(filename+" didn't exist");return make_places();}
	else{outXML(filename + " exists");}
	unsigned int found=0;
	std::string comparename;
	std::ifstream inputFileStrem (filename.c_str(), std::ifstream::in);
	if(inputFileStrem.is_open()){
		while (getline(inputFileStrem,line)){
			bool isSFTP=false;
			std::string tmpFIND="file:";
			found=line.find(tmpFIND);
			if(found < line.length()){
				line = line.erase(0,(found+tmpFIND.length()+2));
				comparename = line;
				found = 0;
				found = comparename.rfind('/');
				if(found < comparename.length()){
					comparename=comparename;
				}
			}
			tmpFIND="sftp:";
			unsigned int sftp=line.find(tmpFIND);
			if(sftp < line.length()){
				line=line.erase(0,(sftp+tmpFIND.length()+2));
				comparename=line;
				sftp = comparename.rfind('/');
				if(sftp < comparename.length()){
					comparename=comparename;
				}
				isSFTP=true;
			}
			whatName = line;
			found=line.find(' ');
			if(found< line.length()){
				whatName = whatName.erase(0,found+1);
				line=line.erase(found,std::string::npos);
				while ( line.find("%20")<line.length() ){
					found = line.find("%20");
					if(found < line.length() ){
						std::string temp1 = line;
						std::string temp2 = line;
						temp1 = temp1.erase(found, std::string::npos);
						temp2 = temp2.erase(0,found+3);
						line = temp1 + "\\ " + temp2;
				  
					}
				}
			}
			unsigned int findSPACE=whatName.rfind("/");
			if(findSPACE<whatName.length()){whatName=whatName.erase(0,findSPACE+1);}
			if(!isSFTP){
				pugi::xml_node tmp=make_submenu(line, whatName,FOLDER_ICON,node);
				if(!tmp){outXML("Didn't make GTK SUBMENU:"+line);}
				else{node=tmp;}
			}
			else{
				pugi::xml_node tmp=addSFTP(NET_FOLDER_ICON,whatName,line,node);
				if(!tmp){outXML("Didn't make GTK SFTP entry:"+line);}
				else{node=tmp;}
			}
		}
	}
	else{outXML("inputFileStream didn't open: "+filename);}
	std::string blankname=" "; 

	pugi::xml_node tmp=make_trash(node);
	if(!tmp){outXML("Didn't make trash");}
	int retval=0;
	if(!doc.save_file(PLACES_FILENAME.c_str())){retval=1;}
	return retval;
}
int make_home(){
	unsigned int submenus=submenuDepth();
	tempDepth=submenus;
	PLACES_FILENAME=getCacheFilename();
	if(!linuxcommon::test_file(PLACES_FILENAME)){
		std::string CONTENTS=default_JWM();
		linuxcommon::save_string_to_file(CONTENTS,PLACES_FILENAME);
	}
	pugi::xml_node node;
	if(!doc.load(PLACES_FILENAME.c_str()) ){
		node=doc.append_child("JWM");
		doc.save_file(PLACES_FILENAME.c_str());
	}
	else{
		node=doc.child("JWM");//Initialize our node variable
	}
	std::string MENU,ITEM,shortname,thisdir,dirToOpen;
	DIR *dir = NULL;
    struct dirent *entryPointer = NULL;
    unsigned int finder = 0;
    unsigned int len = 0;
    //make the initial Root opener
	std::string FOLDER_OPEN_ICON = "folder-open";
	std::string FOLDER_ICON = "folder";
	dirToOpen =linuxcommon::home_path();
	if(dirToOpen.compare("")!=0){
		dir = opendir(dirToOpen.c_str());
		if (dir!=NULL){
			while ((entryPointer=readdir(dir)) != NULL){
				if ((entryPointer->d_type == DT_DIR)&&(entryPointer->d_name[0] != '.')){
					thisdir=dirToOpen;
					len = thisdir.length();
					finder = thisdir.rfind('/');
					if(finder != len){
						thisdir+="/";
					}
					thisdir+=entryPointer->d_name;
					shortname=entryPointer->d_name;
					pugi::xml_node tmp=make_submenu(thisdir,shortname,FOLDER_ICON,node);
					if(!tmp){outXML("Didn't make :"+thisdir);}

				}
			}
			closedir(dir);
		}
	}
	else{return -1;}
	int retval=0;
	if(!doc.save_file(PLACES_FILENAME.c_str())){retval=1;}
	return retval;
}
int make_places(){
	unsigned int submenus=submenuDepth();
	tempDepth=submenus;
	PLACES_FILENAME=getCacheFilename();
	if(!linuxcommon::test_file(PLACES_FILENAME)){
		std::string CONTENTS=default_JWM();
		linuxcommon::save_string_to_file(CONTENTS,PLACES_FILENAME);
	}
	pugi::xml_node node;
	if(!doc.load(PLACES_FILENAME.c_str()) ){
		node=doc.append_child("JWM");
		doc.save_file(PLACES_FILENAME.c_str());
	}
	else{
		node=doc.child("JWM");
	}
// these are all the XDG variables we want

//Not sure if we want these though... so we wont include them
#if 0
	std::string PUBLICSHARE=linuxcommon::term_out(XDG_COMM + " PUBLICSHARE");
	std::string TEMPLATES=linuxcommon::term_out(XDG_COMM + " TEMPLATES");
	std::string DESKTOP=linuxcommon::term_out(XDG_COMM + " DESKTOP");
	std::string DESKTOP_NAME= DESKTOP;
	DESKTOP_NAME = DESKTOP_NAME.erase(0,length);
	std::string PUBLICSHARE_NAME= PUBLICSHARE;
	PUBLICSHARE_NAME = PUBLICSHARE_NAME.erase(0,length);
	std::string TEMPLATES_NAME= TEMPLATES;
	TEMPLATES_NAME = TEMPLATES_NAME.erase(0,length);
#endif
	
	//This is the stuff we really want
	std::string XDG_COMM="xdg-user-dir";
	std::string DOCUMENTS=linuxcommon::term_out(XDG_COMM + " DOCUMENTS");
	std::string DOWNLOADS=linuxcommon::term_out(XDG_COMM + " DOWNLOAD");
	std::string MUSIC=linuxcommon::term_out(XDG_COMM + " MUSIC");
	std::string PICTURES=linuxcommon::term_out(XDG_COMM + " PICTURES");
	std::string VIDEOS=linuxcommon::term_out(XDG_COMM + " VIDEOS");

    std::string HOME = home;
	unsigned int length = HOME.length();
	std::string VIDEOS_NAME= VIDEOS;
	VIDEOS_NAME = VIDEOS_NAME.erase(0,length);
	std::string DOCUMENTS_NAME = DOCUMENTS;
	DOCUMENTS_NAME = DOCUMENTS_NAME.erase(0,length);
	std::string DOWNLOADS_NAME= DOWNLOADS;
	DOWNLOADS_NAME = DOWNLOADS_NAME.erase(0,length);
	std::string MUSIC_NAME= MUSIC;
	MUSIC_NAME = MUSIC_NAME.erase(0,length);
	std::string PICTURES_NAME= PICTURES;
	PICTURES_NAME = PICTURES_NAME.erase(0,length);
	
	//temporary... eventually check file for this..
	std::string HOME_NAME;
	const char* user=getenv("USER");
	if(user != NULL){
		 HOME_NAME=user;
	}
	else{
		 HOME_NAME=linuxcommon::term_out(XDG_COMM + " HOME");
		 HOME_NAME= HOME_NAME.erase(0,5);
	}
	
	std::string HOME_ICON="folder-home";
	std::string DOCUMENTS_ICON="folder-documents";
	std::string DOWNLOADS_ICON="folder-downloads";
	std::string MUSIC_ICON="folder-music";
	std::string PICTURES_ICON="folder-pictures";
	std::string VIDEOS_ICON="folder-video";
	std::string FOLDER_ICON="folder";
	//Make the menu...
	std::string MENU;
	pugi::xml_node tmp = make_submenu(HOME,HOME_NAME,HOME_ICON,node);
	if(!tmp){outXML("Didn't make : Home");}
	else{node=tmp;}
	tmp = make_submenu(DOCUMENTS,DOCUMENTS_NAME,DOCUMENTS_ICON,node);
	if(!tmp){outXML("Didn't make : Documents");}
	else{node=tmp;}
	tmp = make_submenu( DOWNLOADS, DOWNLOADS_NAME, DOWNLOADS_ICON,node);
	if(!tmp){outXML("Didn't make : Downloads");}
	else{node=tmp;}
	tmp = make_submenu(MUSIC ,MUSIC_NAME, MUSIC_ICON,node);
	if(!tmp){outXML("Didn't make : Music");}
	else{node=tmp;}
	tmp = make_submenu( PICTURES, PICTURES_NAME, PICTURES_ICON,node);
	if(!tmp){outXML("Didn't make : Pictures");}
	else{node=tmp;}
	tmp = make_submenu(VIDEOS , VIDEOS_NAME, VIDEOS_ICON,node);
	if(!tmp){outXML("Didn't make : Videos");}
	else{node=tmp;}
	tmp = make_trash(node);
	if(!tmp){outXML("Didn't make : Trash");}
	int retval=0;
	if(!doc.save_file(PLACES_FILENAME.c_str())){retval=1;}
	return retval;
}
int usage(){
	std::cout<<"PLACES MENU USAGE:\n\
\n\
OPTIONS\n\
--debug|-debug  \n\
--help|-h|-? Show this help and exit\n\
--full  do the entire full menu including bookmarks and  ~/.config/user-dirs.dirs\n\
--gtk-places  make a menu from the gtk bookmarks file\n\
--home  just make a simple home menu\n\
--places  make a simple places menu based on ~/.config/user-dirs.dirs\n\
"<<std::endl;
	return 1;
}
////////////////////////////////////////////////////////////////////BOOL
bool check_files(){
// make sure the directories exist
    std::string configDir;
	const char* xdg_conf = getenv("XDG_CONFIG_HOME");
	if(xdg_conf ==NULL){
		const char* thaConfigDir = getenv("HOME");
		if(thaConfigDir == NULL){return false;}
		configDir = thaConfigDir;
		configDir+="/.config";
	}
	else{configDir=xdg_conf;}
	if(!testDir(configDir)){linuxcommon::mkdir_p(configDir);}	
	std::string userdirsfile= configDir + "user-dirs.dirs";
	if (!linuxcommon::test_file(userdirsfile.c_str())){
	// if not see if we can make it using the CLI tool
		if ( !testEXEC("xdg-user-dirs-update")){
			outXML("xdg-user-dirs-update doesn't exist in the PATH:( Please install it");
			return false;
		}
		else{
			int sys_call=system("xdg-user-dirs-update");
			if(sys_call!=0){outXML("updating xdg user dirs failed");}
		}
		if (!testEXEC("xdg-user-dir")){
			outXML("xdg-user-dir doesn't exist in the PATH :( Please install it!");
			return false;
		}
	}
	return true;
}
//test directories
bool testDir(std::string dirToTest){return linuxcommon::test_dir(dirToTest);}
//test executable things
bool testEXEC(std::string execToTest){return linuxcommon::test_exec(execToTest);}
bool setSubmenuDepth(unsigned int value){
	std::string configFile=getConfigFile();
	std::string val=linuxcommon::convert_unsigned_to_string(value);
	val="submenus="+val;
	//make our config file have this value
	return linuxcommon::save_string_to_file(val,configFile);
}
////////////////////////////////////////////////////////////////////VOID
void outXML(std::string message){
	if(DEBUG)
	std::cout<<"<!-- "<<message<<" -->"<<std::endl;
}
//////////////////////////////////////////////////////////////////STRING
std::string default_JWM(){return "<JWM>\n<\\JWM>";}
std::string fixDirForOPEN(std::string input){
	std::string whichDir=sed(input," ","\\ ");
	whichDir=sed(whichDir,"&","\\&");
	return whichDir;
}
std::string getCacheFilename(){
	std::string configFile;
	const char* xdg_conf = getenv("XDG_CONFIG_HOME");
	if(xdg_conf == NULL){
		if(home.compare("")==0){home = linuxcommon::home_path();}
		if(home.compare("")==0){return "";}
		configFile=home;
		configFile+=".config/menus/jwm-places.xml";
	}
	else{
		configFile =  xdg_conf;
		configFile += "/menus/jwm-places.xml";
	}
	return configFile;
}
std::string getConfigFile(){
	std::string configFile;
	const char* xdg_conf = getenv("XDG_CONFIG_HOME");
	if(xdg_conf == NULL){
		if(home.compare("")==0){home = linuxcommon::home_path();}
		if(home.compare("")==0){return "";}
		configFile=home;
		configFile+=".config/menus/jwm-places.conf";
	}
	else{
		configFile =  xdg_conf;
		configFile += "/menus/jwm-places.conf";
	}
	if(!linuxcommon::test_file(configFile)){
		if(!linuxcommon::save_string_to_file("submenus=0",configFile))
			outXML("Could not create default file:"+configFile);
	}
	return configFile;
}
std::string get_line(std::string filename, std::string line){return linuxcommon::get_line_with_equal(filename,line);}
std::string sed(std::string input, std::string remove, std::string replace){return linuxcommon::sed_i(input,remove,replace);}
////////////////////////////////////////////////////////////////////PUGI
pugi::xml_node addMenu(std::string icon, std::string name, std::string dir,pugi::xml_node parentnode){
	if(!parentnode){
		outXML("No parent node sent into addMenu");
		return parentnode;
	}
	pugi::xml_node node=parentnode.append_child("Menu");
	node.append_attribute("icon")=icon.c_str();
	node.append_attribute("label")=name.c_str();
	if(name.compare("")!=0 && name.compare(" ")!=0)
		node.append_attribute("tooltip")=name.c_str();
	std::string FOLDER_OPEN_ICON = "folder-open";
	node=addProgram(FOLDER_OPEN_ICON," ",dir,node);
	//node=node.parent();
	return node;
}
pugi::xml_node addProgram(std::string icon, std::string name, std::string dir,pugi::xml_node parentnode){
	if(!parentnode){
		outXML("Parent node doesn't exist for addProgram....");
		return parentnode;
	}
	if(testDir(dir)){dir="xdg-open "+fixDirForOPEN(dir);}
	else{
		outXML(dir+" is not exactly a directory...");
		return parentnode;
	}
	pugi::xml_node node=parentnode.append_child("Program");
	node.text().set(dir.c_str());
	node.append_attribute("icon")=icon.c_str();
	node.append_attribute("label")=name.c_str();
	if(name.compare("")!=0 && name.compare(" ")!=0)
		node.append_attribute("tooltip")=name.c_str();
	if(PLACES_FILENAME.compare("")==0)PLACES_FILENAME=getCacheFilename();
	if(node.parent()){node=node.parent();}
	if(!node){
		outXML("Node didn't exist...");
		return parentnode;
	}
	return node;
}
pugi::xml_node addSFTP(std::string icon, std::string name, std::string dir,pugi::xml_node parentnode){
	if(!parentnode){
		outXML("Parent node doesn't exist for addSFTP....");
		return parentnode;
	}
	dir="xdg-open "+fixDirForOPEN(dir);
	pugi::xml_node node=parentnode.append_child("Program");
	node.text().set(dir.c_str());
	node.append_attribute("icon")=icon.c_str();
	node.append_attribute("label")=name.c_str();
	if(name.compare("")!=0 && name.compare(" ")!=0)
		node.append_attribute("tooltip")=name.c_str();
	if(PLACES_FILENAME.compare("")==0)PLACES_FILENAME=getCacheFilename();
	if(node.parent()){node=node.parent();}
	if(!node){
		outXML("Node didn't exist...");
		return parentnode;
	}
	return node;
}
pugi::xml_node make_submenu(std::string dirToOpen, std::string whatName, std::string whatIcon,pugi::xml_node myNode){
	//outXML("pugi make submenu "+dirToOpen+"," +whatName+","+whatIcon);
	if(!myNode){
		outXML("Parent node does not exist to make a submenu...");
		return myNode;
	}
	std::string MENU,ITEM,shortname,thisdir;
	DIR *dir = NULL;
    struct dirent *entryPointer = NULL;
    unsigned int finder = 0;
    unsigned int len = 0;
    //make the initial Root opener
    thisdir = dirToOpen;
    unsigned int slash=0;
    slash=whatName.rfind('/');
    unsigned int nameLen=whatName.length();
    if (slash < nameLen){
		whatName=whatName.erase(0,slash+1);
	}
	std::string forward_slash="&#47;";
	slash=0;
    slash=whatName.rfind(forward_slash);
    nameLen=whatName.length();
    if (slash < nameLen){
		whatName=whatName.erase(0,slash+1);
	}
	std::string FOLDER_ICON = "folder";
	thisdir = dirToOpen;
	std::vector<std::string> theseDIRS;
	if(dirToOpen.compare("")!=0){
		dir = opendir(dirToOpen.c_str());
		if (dir!=NULL){
			while ((entryPointer=readdir(dir)) != NULL){
				if ((entryPointer->d_type == DT_DIR)&&(entryPointer->d_name[0] != '.')){
					thisdir=dirToOpen;
					len = thisdir.length();
					finder = thisdir.rfind('/');
					if(finder != len){
						thisdir+="/";
					}
					thisdir+=entryPointer->d_name;
					theseDIRS.push_back(thisdir);//shortname=entryPointer->d_name;
					
				}
			}
			closedir(dir);
			theseDIRS=linuxcommon::sort_array(theseDIRS);
		}
		else{
			outXML("Couldn't open: "+dirToOpen);
			return myNode;
		}
		
		if(!theseDIRS.empty()){
			pugi::xml_node tmp=addMenu(whatIcon,whatName,dirToOpen,myNode);
			if(tmp){
				myNode=tmp;
				std::string testPATH;
				pugi::xml_node RESET=myNode;
				for( std::vector<std::string>::iterator iter = theseDIRS.begin();
				iter!=theseDIRS.end();
				++iter){
					testPATH = *iter;
					shortname=testPATH;
					unsigned int finder=shortname.rfind('/');
					thisdir=testPATH;
					if(finder<shortname.length()){shortname=shortname.erase(0,finder+1);}
					if(tempDepth>=1){
						tempDepth-=1;
						pugi::xml_node tmp=make_submenu(thisdir,shortname,FOLDER_ICON,myNode);
						if(!tmp){
							myNode=RESET;
							outXML("Didn't make Submenu:"+thisdir);
						}
					}
					else{
						pugi::xml_node tmp=addProgram(FOLDER_ICON,shortname,thisdir,myNode);
						if(!tmp){
							myNode=RESET;
							outXML("Didn't make Folder Opener:"+thisdir);
						}
					}
				}
			}
			tempDepth+=1;
		}
		else{
			pugi::xml_node RESET=myNode;
			pugi::xml_node tmp=addProgram(whatIcon,whatName,thisdir,myNode);
			if(!tmp){
				myNode=RESET;
				outXML("Didn't make Folder Opener:"+thisdir);
			}
		}
		myNode=myNode.parent();
	}
	return myNode;
}
pugi::xml_node make_trash(pugi::xml_node basenode){
	std::string TRASH_ICON="user-trash";
	std::string whichDir;
	std::string XDG_COMM="xdg-user-dir";
	std::string TRASH;
	pugi::xml_node node;
	TRASH=linuxcommon::home_path();
	if(TRASH.compare("")==0){return node;}
	TRASH+=".local/share/Trash/files";
	whichDir=TRASH;
	if(!testDir(whichDir)){
		if(linuxcommon::mkdir_p(whichDir)>0){return node;}
	}
	//TODO: find the name for trash somehow
	whichDir=fixDirForOPEN(whichDir);
	bool XDGmime=testEXEC("xdg-mime");
	std::string fm;
	if(XDGmime){
		fm=linuxcommon::term_out("xdg-mime query default inode/directory");
		if(fm.compare("")!=0){
			unsigned int findio=fm.find('.');
			if(findio<fm.length()){
				fm=fm.erase(findio,std::string::npos);
				fm+=" trash:///";
			}
		}
	}
	//outXML(fm);
	///TODO find filemanager if xdg-open doesn't exist...
	if(fm.compare("")==0){fm="xdg-open "+whichDir;}
	node=basenode.append_child("Program");
	node.text().set(fm.c_str());
	node.append_attribute("label")=" ";
	node.append_attribute("tootlip")=" ";
	node.append_attribute("icon")=TRASH_ICON.c_str();
	if(PLACES_FILENAME.compare("")==0)PLACES_FILENAME=getCacheFilename();
	if(node.parent()){node=node.parent();}
	if(!node){
		outXML("Node didn't exist...");
		return basenode;
	}
	return node;
	return node;
}
