/*---------------------------------------------------------*\
| AutoStart-Linux.cpp                                       |
|                                                           |
|   Autostart implementation for Linux                      |
|                                                           |
|   This file is part of the OpenRGB project                |
|   SPDX-License-Identifier: GPL-2.0-or-later               |
\*---------------------------------------------------------*/

#include <fstream>
#include <iostream>
#include <sstream>
#include <unistd.h>
#include <linux/limits.h>
#include "AutoStart-Linux.h"
#include "LogManager.h"
#include "filesystem.h"

AutoStart::AutoStart(std::string name)
{
    InitAutoStart(name);
}

bool AutoStart::DisableAutoStart()
{
    std::error_code autostart_file_remove_errcode;
    bool            success                         = false;

    /*-----------------------------------------------------*\
    | Check if the filename is valid                        |
    \*-----------------------------------------------------*/
    if(autostart_file != "")
    {
        /*-------------------------------------------------*\
        | If file doesn't exist, disable is successful      |
        \*-------------------------------------------------*/
        if(!filesystem::exists(autostart_file))
        {
            success = true;
        }
        /*-------------------------------------------------*\
        | Otherwise, delete the file                        |
        \*-------------------------------------------------*/
        else
        {
            success = filesystem::remove(autostart_file, autostart_file_remove_errcode);

            if(!success)
            {
                LOG_ERROR("[AutoStart] An error occurred removing the auto start file.");
            }
        }
    }
    else
    {
        LOG_ERROR("[AutoStart] Could not establish correct autostart file path.");
    }

    return(success);
}

bool AutoStart::EnableAutoStart(AutoStartInfo autostart_info)
{
    bool        success                             = false;

    /*-----------------------------------------------------*\
    | Check if the filename is valid                        |
    \*-----------------------------------------------------*/
    if(autostart_file != "")
    {
        std::string     desktop_file                = GenerateDesktopFile(autostart_info);
        std::ofstream   autostart_file_stream(autostart_file, std::ios::out | std::ios::trunc);

        /*-------------------------------------------------*\
        | Error out if the file could not be opened         |
        \*-------------------------------------------------*/
        if(!autostart_file_stream)
        {
            LOG_ERROR("[AutoStart] Could not open %s for writing.", autostart_file.c_str());
            success = false;
        }
        /*-------------------------------------------------*\
        | Otherwise, write the file                         |
        \*-------------------------------------------------*/
        else
        {
            autostart_file_stream << desktop_file;
            autostart_file_stream.close();
            success = !autostart_file_stream.fail();

            if (!success)
            {
                LOG_ERROR("[AutoStart] An error occurred writing the auto start file.");
            }
        }
    }
    else
    {
        LOG_ERROR("[AutoStart] Could not establish correct autostart file path.");
    }

    return(success);
}

bool AutoStart::IsAutoStartEnabled()
{
    /*-----------------------------------------------------*\
    | Check if the filename is valid                        |
    \*-----------------------------------------------------*/
    if(autostart_file != "")
    {
        return(filesystem::exists(autostart_file));
    }
    else
    {
        return(false);
    }
}

std::string AutoStart::GetExePath()
{
    /*-----------------------------------------------------*\
    | Create the OpenRGB executable path                    |
    \*-----------------------------------------------------*/
    char exepath[ PATH_MAX ];

    ssize_t count = readlink("/proc/self/exe", exepath, PATH_MAX);

    return(std::string(exepath, (count > 0) ? count : 0));
}

/*---------------------------------------------------------*\
| Linux AutoStart Implementation                            |
| Private Methods                                           |
\*---------------------------------------------------------*/

std::string AutoStart::GenerateDesktopFile(AutoStartInfo autostart_info)
{
    /*-----------------------------------------------------*\
    | Generate a .desktop file from the AutoStart           |
    | parameters                                            |
    \*-----------------------------------------------------*/
    std::stringstream fileContents;

    fileContents << "[Desktop Entry]"                               << std::endl;
    fileContents << "Categories="        << autostart_info.category << std::endl;
    fileContents << "Comment="           << autostart_info.desc     << std::endl;
    fileContents << "Icon="              << autostart_info.icon     << std::endl;
    fileContents << "Name="              << GetAutoStartName()      << std::endl;
    fileContents << "StartupNotify=true"                            << std::endl;
    fileContents << "Terminal=false"                                << std::endl;
    fileContents << "Type=Application"                              << std::endl;

    /*-----------------------------------------------------*\
    | Add the executable path and arguments                 |
    \*-----------------------------------------------------*/
    fileContents << "Exec="              << autostart_info.path;

    if (autostart_info.args != "")
    {
        fileContents << " " << autostart_info.args;
    }

    fileContents << std::endl;

    return(fileContents.str());
}

void AutoStart::InitAutoStart(std::string name)
{
    std::string autostart_dir;

    autostart_name = name;

    /*-----------------------------------------------------*\
    | Get home and config paths                             |
    \*-----------------------------------------------------*/
    const char *xdg_config_home = getenv("XDG_CONFIG_HOME");
    const char *home = getenv("HOME");

    /*-----------------------------------------------------*\
    | Determine where the autostart .desktop files are      |
    | kept                                                  |
    \*-----------------------------------------------------*/
    if(xdg_config_home != NULL)
    {
        autostart_dir = xdg_config_home;
        autostart_dir = autostart_dir + "/autostart/";
    }
    else if(home != NULL)
    {
        autostart_dir = home;
        autostart_dir = autostart_dir + "/.config/autostart/";
    }

    /*-----------------------------------------------------*\
    | Check if the filename is valid                        |
    \*-----------------------------------------------------*/
    if(autostart_dir != "")
    {
        std::error_code ec;

        bool success = true;

        if(!filesystem::exists(autostart_dir))
        {
            success = filesystem::create_directories(autostart_dir, ec);
        }

        if(success)
        {
            autostart_file = autostart_dir + autostart_name + ".desktop";
        }
    }
}

