/*
===========================================================================
Copyright (C) 2015 the OpenMoHAA team

This file is part of OpenMoHAA source code.

OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.

OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/

#include "ui_local.h"
#include "../script/scriptexception.h"

Event EV_Layout_Menu
(
    "menu",
    EV_DEFAULT,
    "sffsF",
    "name width height direction motion_time",
    "Sets up the layout of the menu."
);

CLASS_DECLARATION(Listener, UILayout, NULL) {
    {&EV_Layout_Menu, &UILayout::CreateWidgetContainer},
    {NULL,            NULL                            }
};

UILayout::UILayout()
{
    BogusFunction();
    m_script   = NULL;
    m_filename = NULL;
}

UILayout::UILayout(const char *filename)
{
    BogusFunction();
    m_script   = NULL;
    m_filename = filename;

    if (filename) {
        Load(filename, true);
    }
}

void UILayout::BogusFunction(void) {}

void UILayout::CreateWidgetContainer(Event *ev)
{
    str   name;
    str   direction;
    float w, h;

    name = ev->GetString(1);

    if (!name.length()) {
        return;
    }

    w         = ev->GetFloat(2);
    h         = ev->GetFloat(3);
    direction = ev->GetString(4);

    m_currentcontainer = new UIWidgetContainer;
    m_currentcontainer->setName(name);

    if (!stricmp(direction, "from_bottom")) {
        m_currentcontainer->setDirection(D_FROM_BOTTOM);
    } else if (!stricmp(direction, "from_top")) {
        m_currentcontainer->setDirection(D_FROM_TOP);
    } else if (!stricmp(direction, "from_left")) {
        m_currentcontainer->setDirection(D_FROM_LEFT);
    } else if (!stricmp(direction, "from_right")) {
        m_currentcontainer->setDirection(D_FROM_RIGHT);
    } else {
        m_currentcontainer->setDirection(D_NONE);
    }

    if (ev->NumArgs() > 4) {
        m_currentcontainer->setMotionTime(ev->GetFloat(5));
    }

    m_currentcontainer->setAlwaysOnBottom(true);
    m_currentcontainer->InitFrame(NULL, 0, 0, w, h);
    m_currentcontainer->m_layout = this;
    m_currentwidget              = m_currentcontainer;
}

void UILayout::ProcessCommands(bool bFullLoad)
{
    const char *token;
    Event      *ev;
    UIWidget   *widget;
    str         postinclude;

    try {
        while (m_script->TokenAvailable(true)) {
            token = m_script->GetToken(true);

            if (!strcmp(token, "end.")) {
                break;
            } else if (!strcmp(token, "include")) {
                if (m_script->TokenAvailable(false)) {
                    m_scriptstack.Push(m_script);
                    Load(m_script->GetToken(false), bFullLoad);
                    m_script = m_scriptstack.Pop();
                }
            } else if (!strcmp(token, "postinclude")) {
                if (m_script->TokenAvailable(false)) {
                    token       = m_script->GetToken(false);
                    postinclude = token;
                }
            } else if (!strcmp(token, "resource")) {
                ClassDef   *cls;
                str         cl;
                const char *newname;

                token = m_script->GetToken(true);

                // find the class resource
                newname = uii.Client_TranslateWidgetName(token);
                if (!newname) {
                    newname = token;
                }

                cl = "UI";
                cl += newname;
                cls = getClass(cl);
                if (!cls) {
                    Com_Printf("Failed to find resource type '%s'\n", token);
                    break;
                }

                widget = (UIWidget *)cls->newInstance();

                token = m_script->GetToken(true);
                if (*token == '{') {
                    widget->InitFrame(m_currentcontainer, 0, 0, 128, 64, -1, "verdana-12");

                    if (m_currentcontainer->m_bVirtual) {
                        ev = new Event(EV_Layout_VirtualRes);
                        ev->AddInteger(1);
                        widget->ProcessEvent(ev);
                    }

                    token = m_script->GetToken(true);
                    while (1) {
                        if (!strcmp(token, "}")) {
                            break;
                        }

                        if (widget->ValidEvent(token)) {
                            ev = new Event(token);

                            while (m_script->TokenAvailable(false)) {
                                token = m_script->GetToken(false);
                                ev->AddToken(token);
                            }

                            widget->ProcessEvent(ev);
                        }

                        if (!m_script->TokenAvailable(true)) {
                            break;
                        }

                        token = m_script->GetToken(true);
                    }
                }
            } else {
                if (ValidEvent(token)) {
                    ev = new Event(token);

                    while (m_script->TokenAvailable(false)) {
                        token = m_script->GetToken(false);
                        ev->AddToken(token);
                    }

                    ProcessEvent(ev);
                } else if (m_currentwidget && m_currentwidget->ValidEvent(token)) {
                    ev = new Event(token);

                    while (m_script->TokenAvailable(false)) {
                        token = m_script->GetToken(false);
                        ev->AddToken(token);
                    }

                    m_currentwidget->ProcessEvent(ev);
                }
            }
        }
    } catch (ScriptException& exc) {
        uii.Sys_Printf("UI EXCEPTION : %s\n", exc.string.c_str());
    }

    // process post-includes
    if (postinclude.length()) {
        m_scriptstack.Push(m_script);
        Load(postinclude, bFullLoad);
        m_script = m_scriptstack.Pop();
    }
}

void UILayout::Load(const char *filename, bool bFullLoad)
{
    m_bLoaded = true;

    m_script = new Script;
    m_script->LoadFile(filename);

    ProcessCommands(bFullLoad);

    m_bLoaded = bFullLoad;

    delete m_script;
    m_script = NULL;
}

int UILayout::ForceLoad(void)
{
    if (m_bLoaded) {
        return 0;
    }

    Load(m_filename, true);

    return true;
}
