//
//
//

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

#include <windows.h>
#include <tlhelp32.h>

namespace Raym
{

DEFINE_STATIC_MUTEX(mutex_);

static Workspace *sharedWorkspace_ = NULL;

Workspace::Workspace()
{
    DebugLog2("Workspace::Workspace()");
}

Workspace::~Workspace()
{
    DebugLog2("Workspace::~Workspace()");
}

Workspace *Workspace::sharedWorkspace()
{
    mutex_.lock();

    if (sharedWorkspace_ == NULL)
    {
        sharedWorkspace_ = new Workspace();
        sharedWorkspace_->init()->autorelease(true);
    }

    mutex_.unlock();

    return sharedWorkspace_;
}

Array *Workspace::runningApplications()
{
    DebugLog2("Workspace::runningApplications()");

    Array *result = Array::arrayWithCapacity(0);

    Dictionary *tmpDict1 = Dictionary::dictionaryWithCapacity(0);

    //
    // 1回目：通常アプリ
    //

    // パイプ生成
    Pipe *pipe = Pipe::alloc()->init();

    // タスク生成
    Task *task = Task::alloc()->init();
    task->setLaunchPath(String::stringWithUTF8String("tasklist"));

    // 引数設定
    Array *args = Array::arrayWithCapacity(0);
    args->addObject(String::stringWithUTF8String("/v"));
    args->addObject(String::stringWithUTF8String("/fo"));
    args->addObject(String::stringWithUTF8String("csv"));
    task->setArguments(args);

    // 標準出力設定
    task->setStandardOutput(pipe->fileHandleForWriting());
    //task->setStandardError(pipe->fileHandleForWriting());

    // タスク実行
    task->launch();

    // 読み込み
    FileInputStream *fis = FileInputStream::fileInputStream(pipe->fileHandleForReading());

    bool header = true;
    while (true)
    {
        String *line = fis->readLine();
        if (line == NULL)
        {
            break;
        }
        if (header)
        {
            // 1行目はヘッダ
            header = false;
        }
        else
        {
            // 2行目以降
            Array *list = line->componentsSeparatedByString("\",\"");
            if ((list != NULL) && (list->count() == 9))
            {
                // RunningApplication用の情報を収集
                Dictionary *tmpDict2 = Dictionary::dictionaryWithCapacity(0);
                tmpDict2->setString(((String *)list->objectAtIndex(0))->substringFromIndex(1), RunningApplication::KEY_IMAGE);
                tmpDict2->setObject(list->objectAtIndex(4), RunningApplication::KEY_MEMORY);
                tmpDict2->setObject(list->objectAtIndex(5), RunningApplication::KEY_STATUS);
                tmpDict2->setObject(list->objectAtIndex(6), RunningApplication::KEY_USER);
                tmpDict2->setObject(list->objectAtIndex(7), RunningApplication::KEY_CPU);

                // PIDをキーにして保持
                tmpDict1->setObject(tmpDict2, (String *)list->objectAtIndex(1));
            }
        }
    }

    // タスク終了
    task->terminate();
    task->release();

    // パイプ破棄
    pipe->release();

    //
    // 2回目：ストアアプリ
    //

    // パイプ生成
    pipe = Pipe::alloc()->init();

    // タスク生成
    task = Task::alloc()->init();
    task->setLaunchPath(String::stringWithUTF8String("tasklist"));

    // 引数設定
    args = Array::arrayWithCapacity(0);
    args->addObject(String::stringWithUTF8String("/v"));
    args->addObject(String::stringWithUTF8String("/fo"));
    args->addObject(String::stringWithUTF8String("csv"));
    args->addObject(String::stringWithUTF8String("/apps"));
    task->setArguments(args);

    // 標準出力設定
    task->setStandardOutput(pipe->fileHandleForWriting());
    //task->setStandardError(pipe->fileHandleForWriting());

    // タスク実行
    task->launch();

    // 読み込み
    fis = FileInputStream::fileInputStream(pipe->fileHandleForReading());

    header = true;
    while (true)
    {
        String *line = fis->readLine();
        if (line == NULL)
        {
            break;
        }
        if (header)
        {
            // 1行目はヘッダ
            header = false;
        }
        else
        {
            // 2行目以降

            Array *list = line->componentsSeparatedByString("\",\"");
            if ((list != NULL) && (list->count() == 10))
            {
                Dictionary *tmpDict2 = tmpDict1->dictionaryForKey((String *)list->objectAtIndex(1));
                if (tmpDict2 != NULL)
                {
                    // 同一PIDがある場合

                    // ステータスを更新
                    if (!((String *)list->objectAtIndex(5))->isEqualToString("Running"))
                    {
                        tmpDict2->setString("Interrupted", RunningApplication::KEY_STATUS);
                    }

                    // パッケージを追加
                    String *tmpStr = (String *)list->objectAtIndex(9);
                    tmpDict2->setString(tmpStr->substringToIndex(tmpStr->length() - 1), RunningApplication::KEY_PACKAGE);
                }
            }
        }
    }

    // タスク終了
    task->terminate();
    task->release();

    // パイプ破棄
    pipe->release();

    Array *keys = tmpDict1->allKeys();
    for (uint idx = 0; idx < keys->count(); ++idx)
    {
        int pid = ((String *)keys->objectAtIndex(idx))->intValue();
        Dictionary *tmpDict2 = tmpDict1->dictionaryForKey((String *)keys->objectAtIndex(idx));

        RunningApplication *ra = RunningApplication::alloc()->initWithPID(pid, tmpDict2);
        result->addObject(ra);
        ra->release();
    }
    return result;
}

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

} // Raym
