/*
 * Copyright (c) 2011 Paulo Zanoni
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include <cstdlib>
#include <cstring>
#include <iostream>

#include "XDGBasedir.h"
#include "XDGUtils.h"

// XXX: spec mentions these directories, but hardcodes /etc and /usr in the
//      specification of default directories to be used! Fix spec?
#ifndef SYSCONFDIR
#define SYSCONFDIR "/etc"
#endif
#ifndef DATADIR
#define DATADIR "/usr/share"
#endif

std::string XDGBasedir::getVariable(XDGVariables var)
{
    const char *varName;
    switch(var) {
	case XDG_DATA_HOME:
	    varName = "XDG_DATA_HOME";
	    break;
	case XDG_CONFIG_HOME:
	    varName = "XDG_CONFIG_HOME";
	    break;
	case XDG_DATA_DIRS:
	    varName = "XDG_DATA_DIRS";
	    break;
	case XDG_CONFIG_DIRS:
	    varName = "XDG_CONFIG_DIRS";
	    break;
	case XDG_CACHE_HOME:
	    varName = "XDG_CACHE_HOME";
	    break;
	case XDG_RUNTIME_DIR:
	    varName = "XDG_RUNTIME_DIR";
	    break;
	default:
	    std::cerr << "Error: undefined variable!\n";
	    return "";
    }

    char *varValue = getenv(varName);

    if (varValue)
	return varValue;

    char *home = NULL;
    if (var == XDG_DATA_HOME || var == XDG_CONFIG_HOME ||
	var == XDG_CACHE_HOME) {
	home = getenv("HOME");
	if (!home) {
	    std::cerr << "Error: $HOME is not set!\n";
	    return "";
	}
    }

    std::string ret;
    switch(var) {
	case XDG_DATA_HOME:
	    ret = std::string(home) + "/.local/share";
	    break;
	case XDG_CONFIG_HOME:
	    ret = std::string(home) + "/.config";
	    break;
	case XDG_DATA_DIRS:
	    ret = "/usr/local/share/:/usr/share/";
	    break;
	case XDG_CONFIG_DIRS:
	    // XXX: spec doesn't mention $sysconfdir here!
	    ret = "/etc/xdg";
	    break;
	case XDG_CACHE_HOME:
	    ret = std::string(home) + "/.cache";
	    break;
	case XDG_RUNTIME_DIR:
	    // "If $XDG_RUNTIME_DIR is not set applications should fall back to
	    // a replacement directory with similar capabilities and print a
	    // warning message"
	    std::cout << "Warning: XDG_RUNTIME_DIR not set\n";
	    return "";
    }
    return ret;
}

bool XDGBasedir::validRuntimeDir()
{
    // XXX: check the spec! there are a lot of things to validate here
    return true;
}

std::list<std::string> XDGBasedir::findFile(const char *fileName,
					    const std::string& userDir,
					    const std::string& systemDirs)
{
    std::list<std::string> ret;

    ret.push_back(std::string(userDir + '/' + fileName));

    char *path = strdup(systemDirs.c_str());
    char *tokStr, *tokPtr;
    ITERATE_STRTOK_R(path, ":", &tokPtr, tokStr) {
	std::string fullPath(std::string(tokStr) + '/' + fileName);
	if (XDGUtils::fileExists(fullPath.c_str()))
	    ret.push_back(fullPath);
    }
    free(path);

    return ret;
}

std::list<std::string> XDGBasedir::findDataFile(const char *fileName)
{
    return findFile(fileName, getVariable(XDG_DATA_HOME),
		    getVariable(XDG_DATA_DIRS));
}

std::list<std::string> XDGBasedir::findConfigFile(const char *fileName)
{
    return findFile(fileName, getVariable(XDG_CONFIG_HOME),
		    getVariable(XDG_CONFIG_DIRS));
}

