/**
 * @file llpanelexperiencelog.cpp
 * @brief llpanelexperiencelog
 *
 * $LicenseInfo:firstyear=2014&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2014, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */


#include "llviewerprecompiledheaders.h"
#include "llpanelexperiencelog.h"

#include "llexperiencelog.h"
#include "llexperiencecache.h"
#include "llbutton.h"
#include "llscrolllistctrl.h"
#include "llcombobox.h"
#include "llspinctrl.h"
#include "llcheckboxctrl.h"
#include "llfloaterreg.h"
#include "llfloaterreporter.h"
#include "llinventoryfunctions.h"


#define BTN_PROFILE_XP "btn_profile_xp"
#define BTN_REPORT_XP "btn_report_xp"

static LLPanelInjector<LLPanelExperienceLog> register_experiences_panel("experience_log");


LLPanelExperienceLog::LLPanelExperienceLog(  )
    : mEventList(NULL)
    , mPageSize(25)
    , mCurrentPage(0)
{
    buildFromFile("panel_experience_log.xml");
}

bool LLPanelExperienceLog::postBuild()
{
    LLExperienceLog* log = LLExperienceLog::getInstance();
    mEventList = getChild<LLScrollListCtrl>("experience_log_list");
    mEventList->setCommitCallback(boost::bind(&LLPanelExperienceLog::onSelectionChanged, this));
    mEventList->setDoubleClickCallback( boost::bind(&LLPanelExperienceLog::onProfileExperience, this));

    getChild<LLButton>("btn_clear")->setCommitCallback(boost::bind(&LLExperienceLog::clear, log));
    getChild<LLButton>("btn_clear")->setCommitCallback(boost::bind(&LLPanelExperienceLog::refresh, this));

    getChild<LLButton>(BTN_PROFILE_XP)->setCommitCallback(boost::bind(&LLPanelExperienceLog::onProfileExperience, this));
    getChild<LLButton>(BTN_REPORT_XP )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onReportExperience, this));
    getChild<LLButton>("btn_notify"  )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onNotify, this));
    getChild<LLButton>("btn_next"    )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onNext, this));
    getChild<LLButton>("btn_prev"    )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onPrev, this));

    LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("notify_all");
    check->set(log->getNotifyNewEvent());
    check->setCommitCallback(boost::bind(&LLPanelExperienceLog::notifyChanged, this));


    LLSpinCtrl* spin = getChild<LLSpinCtrl>("logsizespinner");
    spin->set(log->getMaxDays());
    spin->setCommitCallback(boost::bind(&LLPanelExperienceLog::logSizeChanged, this));

    mPageSize = log->getPageSize();
    refresh();
    mNewEvent = LLExperienceLog::instance().addUpdateSignal(boost::bind(&LLPanelExperienceLog::refresh, this));
    return true;
}

LLPanelExperienceLog* LLPanelExperienceLog::create()
{
    return new LLPanelExperienceLog();
}

void LLPanelExperienceLog::refresh()
{
    S32 selected = mEventList->getFirstSelectedIndex();
    mEventList->deleteAllItems();
    const LLSD events = LLExperienceLog::instance().getEvents();

    if(events.size() == 0)
    {
        mEventList->setCommentText(getString("no_events"));
        return;
    }

    setAllChildrenEnabled(false);

    LLSD item;
    bool waiting = false;
    LLUUID waiting_id;

    unsigned int itemsToSkip = mPageSize*mCurrentPage;
    unsigned int items = 0;
    bool moreItems = false;
    LLSD events_to_save = events;
    if (events.isMap() && events.size() != 0)
    {
        LLSD::map_const_iterator day = events.endMap();
        do
        {
            --day;
            const LLSD& dayArray = day->second;

            std::string date = day->first;
            if(!LLExperienceLog::instance().isNotExpired(date))
            {
                events_to_save.erase(day->first);
                continue;
            }
            unsigned int size = static_cast<unsigned int>(dayArray.size());
            if(itemsToSkip > size)
            {
                itemsToSkip -= size;
                continue;
            }
            if(items >= mPageSize && size > 0)
            {
                moreItems = true;
                break;
            }
            for(int i = static_cast<int>(dayArray.size()) - itemsToSkip - 1; i >= 0; i--)
            {
                if(items >= mPageSize)
                {
                    moreItems = true;
                    break;
                }
                const LLSD event = dayArray[i];
                LLUUID id = event[LLExperienceCache::EXPERIENCE_ID].asUUID();
                const LLSD& experience = LLExperienceCache::instance().get(id);
                if(experience.isUndefined()){
                    waiting = true;
                    waiting_id = id;
                }
                if(!waiting)
                {
                    item["id"] = event;

                    LLSD& columns = item["columns"];
                    columns[0]["column"] = "time";
                    columns[0]["value"] = day->first+event["Time"].asString();
                    columns[1]["column"] = "event";
                    columns[1]["value"] = LLExperienceLog::getPermissionString(event, "ExperiencePermissionShort");
                    columns[2]["column"] = "experience_name";
                    columns[2]["value"] = experience[LLExperienceCache::NAME].asString();
                    columns[3]["column"] = "object_name";
                    columns[3]["value"] = event["ObjectName"].asString();
                    mEventList->addElement(item);
                }
                ++items;
            }
        } while (day != events.beginMap());
    }
    LLExperienceLog::getInstance()->setEventsToSave(events_to_save);
    if(waiting)
    {
        mEventList->deleteAllItems();
        mEventList->setCommentText(getString("loading"));
        LLExperienceCache::instance().get(waiting_id, boost::bind(&LLPanelExperienceLog::refresh, this));
    }
    else
    {
        setAllChildrenEnabled(true);

        mEventList->setEnabled(true);
        getChild<LLButton>("btn_next")->setEnabled(moreItems);
        getChild<LLButton>("btn_prev")->setEnabled(mCurrentPage>0);
        getChild<LLButton>("btn_clear")->setEnabled(mEventList->getItemCount()>0);
        if(selected<0)
        {
            selected = 0;
        }
        mEventList->selectNthItem(selected);
        onSelectionChanged();
    }
}

void LLPanelExperienceLog::onProfileExperience()
{
    LLSD event = getSelectedEvent();
    if(event.isDefined())
    {
        LLFloaterReg::showInstance("experience_profile", event[LLExperienceCache::EXPERIENCE_ID].asUUID(), true);
    }
}

void LLPanelExperienceLog::onReportExperience()
{
    LLSD event = getSelectedEvent();
    if(event.isDefined())
    {
        LLFloaterReporter::showFromExperience(event[LLExperienceCache::EXPERIENCE_ID].asUUID());
    }
}

void LLPanelExperienceLog::onNotify()
{
    LLSD event = getSelectedEvent();
    if(event.isDefined())
    {
        LLExperienceLog::instance().notify(event);
    }
}

void LLPanelExperienceLog::onNext()
{
    mCurrentPage++;
    refresh();
}

void LLPanelExperienceLog::onPrev()
{
    if(mCurrentPage>0)
    {
        mCurrentPage--;
        refresh();
    }
}

void LLPanelExperienceLog::notifyChanged()
{
    LLExperienceLog::instance().setNotifyNewEvent(getChild<LLCheckBoxCtrl>("notify_all")->get());
}

void LLPanelExperienceLog::logSizeChanged()
{
    int value = (int)(getChild<LLSpinCtrl>("logsizespinner")->get());
    LLExperienceLog::instance().setMaxDays(value);
    refresh();
}

void LLPanelExperienceLog::onSelectionChanged()
{
    bool enabled = (1 == mEventList->getNumSelected());
    getChild<LLButton>(BTN_REPORT_XP)->setEnabled(enabled);
    getChild<LLButton>(BTN_PROFILE_XP)->setEnabled(enabled);
    getChild<LLButton>("btn_notify")->setEnabled(enabled);
}

LLSD LLPanelExperienceLog::getSelectedEvent()
{
    LLScrollListItem* item = mEventList->getFirstSelected();
    if(item)
    {
        return item->getValue();
    }
    return LLSD();
}