//
//
//

#define DBG_LEVEL 0
#include <Raym/Log.h>
#include <Raym/Raym.h>

namespace Raym
{

const char *RunningApplication::KEY_IMAGE   = "Image";
const char *RunningApplication::KEY_MEMORY  = "Memory";
const char *RunningApplication::KEY_STATUS  = "Status";
const char *RunningApplication::KEY_USER    = "User";
const char *RunningApplication::KEY_CPU     = "CPU";
const char *RunningApplication::KEY_PACKAGE = "Package";

RunningApplication::RunningApplication()
{
    DebugLog2("RunningApplication:RunningApplication()");

    _pid = -1;
    _execPath = NULL;
    _memory = NULL;
    _status = NULL;
    _user = NULL;
    _cpu = NULL;
    _package = NULL;
}

RunningApplication::~RunningApplication()
{
    RELEASE(_execPath);
    RELEASE(_memory);
    RELEASE(_status);
    RELEASE(_user);
    RELEASE(_cpu);
    RELEASE(_package);

    DebugLog2("RunningApplication:~RunningApplication()");
}

RunningApplication *RunningApplication::alloc()
{
    DebugLog2("RunningApplication:alloc()");

    return new RunningApplication();
}

/*
RunningApplication *RunningApplication::initWithProcessEntry(PROCESSENTRY32 *pe)
{
    DebugLog2("RunningApplication:initWithProcessEntry()");

    char exec_name[MAX_PATH];
    char exec_path[MAX_PATH];

    memset(exec_name, 0, sizeof(exec_name));
    memset(exec_path, 0, sizeof(exec_path));

    size_t returnValue;
    if (wcstombs_s(&returnValue, exec_name, sizeof(exec_name), pe->szExeFile, _TRUNCATE) != 0)
    {
        // 変換失敗したら念のため NULL終端
        exec_name[0] = '\0';
    }

    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe->th32ProcessID);
    if (hProcess != NULL)
    {
        TCHAR exec[MAX_PATH];
        memset(exec, 0, sizeof(exec));
        DWORD len = sizeof(exec) - 1;

        if (QueryFullProcessImageName(hProcess, 0, exec, &len))
        {
            if (wcstombs_s(&returnValue, exec_path, sizeof(exec_path), exec, _TRUNCATE) != 0)
            {
                // 変換失敗したら念のため NULL終端
                exec_path[0] = '\0';
            }
        }

        //
        CloseHandle(hProcess);
    }

    _pid = pe->th32ProcessID;
    _ppid = pe->th32ParentProcessID;
    _execName = String::alloc()->initWithUTF8String(exec_name);
    DebugLog3("exec_name: %s", exec_name);
    _execPath = String::alloc()->initWithUTF8String(exec_path);
    DebugLog3("exec_path: %s", exec_path);

    return this;
}
*/

#define SET_AND_RETAIN(P1, P2)  P1 = P2; if (P1 != NULL) P1->retain();

RunningApplication *RunningApplication::initWithPID(int pid, Dictionary *dict)
{
    DebugLog2("RunningApplication::initWithPID()");

    if (dict == NULL)
    {
        release();
        return NULL;
    }

    _pid = pid;
    SET_AND_RETAIN(_memory,   dict->stringForKey(KEY_MEMORY));
    SET_AND_RETAIN(_status,   dict->stringForKey(KEY_STATUS));
    SET_AND_RETAIN(_user,     dict->stringForKey(KEY_USER));
    SET_AND_RETAIN(_cpu,      dict->stringForKey(KEY_CPU));
    SET_AND_RETAIN(_package,  dict->stringForKey(KEY_PACKAGE));

    //
    // プロセスイメージのフルパスを取得
    //
    char exec_path[MAX_PATH];
    memset(exec_path, 0, sizeof(exec_path));

    // プロセスハンドル取得
    size_t returnValue;
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    if (hProcess != NULL)
    {
        TCHAR exec[MAX_PATH];
        memset(exec, 0, sizeof(exec));
        DWORD len = sizeof(exec) - 1;

        // イメージ取得
        if (QueryFullProcessImageName(hProcess, 0, exec, &len))
        {
            // ワイド -> マルチ 変換
            if (wcstombs_s(&returnValue, exec_path, sizeof(exec_path), exec, _TRUNCATE) == 0)
            {
                // 成功
                SET_AND_RETAIN(_execPath, String::stringWithUTF8String(exec_path));
            }
        }

        // プロセスハンドル解放
        CloseHandle(hProcess);
    }

    // 取得失敗した場合はdictから設定
    if (_execPath == NULL)
    {
        SET_AND_RETAIN(_execPath, dict->stringForKey(KEY_IMAGE));
    }

    return this;
}

bool RunningApplication::isRunning()
{
    DebugLog2("RunningApplication::isRunning()");

    bool result = false;
    if (_status != NULL)
    {
        result = _status->isEqualToString("Running");
    }
    return result;
}

String *RunningApplication::executePath()
{
    DebugLog2("RunningApplication::executePath()");

    return _execPath;
}

const char *RunningApplication::className()
{
    return "RunningApplication";
}

} // Raym
