/**
 * @file llfloateravatarrendersettings.cpp
 * @brief Shows the list of avatars with non-default rendering settings
 *
 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2017, 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 "llfloateravatarrendersettings.h"

#include "llagent.h"
#include "llavatarnamecache.h"
#include "llfloateravatarpicker.h"
#include "llfiltereditor.h"
#include "llfloaterreg.h"
#include "llnamelistctrl.h"
#include "llnotificationsutil.h"
#include "llmenugl.h"
#include "lltrans.h"
#include "llviewerobjectlist.h"
#include "llvoavatar.h"

class LLSettingsContextMenu : public LLListContextMenu

{
public:
    LLSettingsContextMenu(LLFloaterAvatarRenderSettings* floater_settings)
        :   mFloaterSettings(floater_settings)
    {}
protected:
    LLContextMenu* createMenu()
    {
        LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
        LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
        registrar.add("Settings.SetRendering", boost::bind(&LLFloaterAvatarRenderSettings::onCustomAction, mFloaterSettings, _2, mUUIDs.front()));
        enable_registrar.add("Settings.IsSelected", boost::bind(&LLFloaterAvatarRenderSettings::isActionChecked, mFloaterSettings, _2, mUUIDs.front()));
        LLContextMenu* menu = createFromFile("menu_avatar_rendering_settings.xml");

        return menu;
    }

    LLFloaterAvatarRenderSettings* mFloaterSettings;
};

class LLAvatarRenderMuteListObserver : public LLMuteListObserver
{
    /* virtual */ void onChange()  { LLFloaterAvatarRenderSettings::setNeedsUpdate();}
};

static LLAvatarRenderMuteListObserver sAvatarRenderMuteListObserver;

LLFloaterAvatarRenderSettings::LLFloaterAvatarRenderSettings(const LLSD& key)
:   LLFloater(key),
	mAvatarSettingsList(NULL),
	mNeedsUpdate(false)
{
    mContextMenu = new LLSettingsContextMenu(this);
    LLRenderMuteList::getInstance()->addObserver(&sAvatarRenderMuteListObserver);
    mCommitCallbackRegistrar.add("Settings.AddNewEntry", boost::bind(&LLFloaterAvatarRenderSettings::onClickAdd, this, _2));
}

LLFloaterAvatarRenderSettings::~LLFloaterAvatarRenderSettings()
{
    delete mContextMenu;
    LLRenderMuteList::getInstance()->removeObserver(&sAvatarRenderMuteListObserver);
}

BOOL LLFloaterAvatarRenderSettings::postBuild()
{
    LLFloater::postBuild();
    mAvatarSettingsList = getChild<LLNameListCtrl>("render_settings_list");
    mAvatarSettingsList->setRightMouseDownCallback(boost::bind(&LLFloaterAvatarRenderSettings::onAvatarListRightClick, this, _1, _2, _3));
    mAvatarSettingsList->setAlternateSort();
    getChild<LLFilterEditor>("people_filter_input")->setCommitCallback(boost::bind(&LLFloaterAvatarRenderSettings::onFilterEdit, this, _2));

	return TRUE;
}

void LLFloaterAvatarRenderSettings::draw()
{
    if(mNeedsUpdate)
    {
        updateList();
        mNeedsUpdate = false;
    }

    LLFloater::draw();
}

void LLFloaterAvatarRenderSettings::onAvatarListRightClick(LLUICtrl* ctrl, S32 x, S32 y)
{
    LLNameListCtrl* list = dynamic_cast<LLNameListCtrl*>(ctrl);
    if (!list) return;
    list->selectItemAt(x, y, MASK_NONE);
    uuid_vec_t selected_uuids;

    if(list->getCurrentID().notNull())
    {
        selected_uuids.push_back(list->getCurrentID());
        mContextMenu->show(ctrl, selected_uuids, x, y);
    }
}

void LLFloaterAvatarRenderSettings::onOpen(const LLSD& key)
{
    updateList();
}

void LLFloaterAvatarRenderSettings::updateList()
{
    mAvatarSettingsList->deleteAllItems();
    LLAvatarName av_name;
    LLNameListCtrl::NameItem item_params;
    for (std::map<LLUUID, S32>::iterator iter = LLRenderMuteList::getInstance()->sVisuallyMuteSettingsMap.begin(); iter != LLRenderMuteList::getInstance()->sVisuallyMuteSettingsMap.end(); iter++)
    {
        item_params.value = iter->first;
        LLAvatarNameCache::get(iter->first, &av_name);
        if(!isHiddenRow(av_name.getCompleteName()))
        {
            item_params.columns.add().value(av_name.getCompleteName()).column("name");
            std::string setting = getString(iter->second == 1 ? "av_never_render" : "av_always_render");
            item_params.columns.add().value(setting).column("setting");
            S32 mute_date = LLRenderMuteList::getInstance()->getVisualMuteDate(iter->first);
            item_params.columns.add().value(createTimestamp(mute_date)).column("timestamp").alt_value(std::to_string(mute_date));
            mAvatarSettingsList->addNameItemRow(item_params);
        }
    }
}

void LLFloaterAvatarRenderSettings::onFilterEdit(const std::string& search_string)
{
    std::string filter_upper = search_string;
    LLStringUtil::toUpper(filter_upper);
    if (mNameFilter != filter_upper)
    {
        mNameFilter = filter_upper;
        mNeedsUpdate = true;
    }
}

bool LLFloaterAvatarRenderSettings::isHiddenRow(const std::string& av_name)
{
    if (mNameFilter.empty()) return false;
    std::string upper_name = av_name;
    LLStringUtil::toUpper(upper_name);
    return std::string::npos == upper_name.find(mNameFilter);
}

static LLVOAvatar* find_avatar(const LLUUID& id)
{
    LLViewerObject *obj = gObjectList.findObject(id);
    while (obj && obj->isAttachment())
    {
        obj = (LLViewerObject *)obj->getParent();
    }

    if (obj && obj->isAvatar())
    {
        return (LLVOAvatar*)obj;
    }
    else
    {
        return NULL;
    }
}


void LLFloaterAvatarRenderSettings::onCustomAction (const LLSD& userdata, const LLUUID& av_id)
{
    const std::string command_name = userdata.asString();

    S32 new_setting = 0;
    if ("default" == command_name)
    {
        new_setting = S32(LLVOAvatar::AV_RENDER_NORMALLY);
    }
    else if ("never" == command_name)
    {
        new_setting = S32(LLVOAvatar::AV_DO_NOT_RENDER);
    }
    else if ("always" == command_name)
    {
        new_setting = S32(LLVOAvatar::AV_ALWAYS_RENDER);
    }

    setAvatarRenderSetting(av_id, new_setting);
}


bool LLFloaterAvatarRenderSettings::isActionChecked(const LLSD& userdata, const LLUUID& av_id)
{
    const std::string command_name = userdata.asString();

    S32 visual_setting = LLRenderMuteList::getInstance()->getSavedVisualMuteSetting(av_id);
    if ("default" == command_name)
    {
        return (visual_setting == S32(LLVOAvatar::AV_RENDER_NORMALLY));
    }
    else if ("never" == command_name)
    {
        return (visual_setting == S32(LLVOAvatar::AV_DO_NOT_RENDER));
    }
    else if ("always" == command_name)
    {
        return (visual_setting == S32(LLVOAvatar::AV_ALWAYS_RENDER));
    }
    return false;
}

void LLFloaterAvatarRenderSettings::setNeedsUpdate()
{
    LLFloaterAvatarRenderSettings* instance = LLFloaterReg::getTypedInstance<LLFloaterAvatarRenderSettings>("avatar_render_settings");
    if(!instance) return;
    instance->mNeedsUpdate = true;
}

void LLFloaterAvatarRenderSettings::onClickAdd(const LLSD& userdata)
{
    const std::string command_name = userdata.asString();
    S32 visual_setting = 0;
    if ("never" == command_name)
    {
        visual_setting = S32(LLVOAvatar::AV_DO_NOT_RENDER);
    }
    else if ("always" == command_name)
    {
        visual_setting = S32(LLVOAvatar::AV_ALWAYS_RENDER);
    }

    LLView * button = findChild<LLButton>("plus_btn", TRUE);
    LLFloater* root_floater = gFloaterView->getParentFloater(this);
    LLFloaterAvatarPicker * picker = LLFloaterAvatarPicker::show(boost::bind(&LLFloaterAvatarRenderSettings::callbackAvatarPicked, this, _1, visual_setting),
                                                                    FALSE, TRUE, FALSE, root_floater->getName(), button);

    if (root_floater)
    {
        root_floater->addDependentFloater(picker);
    }
}

void LLFloaterAvatarRenderSettings::callbackAvatarPicked(const uuid_vec_t& ids, S32 visual_setting)
{
    if (ids.empty()) return;
    if(ids[0] == gAgentID)
    {
        LLNotificationsUtil::add("AddSelfRenderExceptions");
        return;
    }
    setAvatarRenderSetting(ids[0], visual_setting);
}

void LLFloaterAvatarRenderSettings::setAvatarRenderSetting(const LLUUID& av_id, S32 new_setting)
{
    LLVOAvatar *avatarp = find_avatar(av_id);
    if (avatarp)
    {
        avatarp->setVisualMuteSettings(LLVOAvatar::VisualMuteSettings(new_setting));
    }
    else
    {
        LLRenderMuteList::getInstance()->saveVisualMuteSetting(av_id, new_setting);
    }
}

BOOL LLFloaterAvatarRenderSettings::handleKeyHere(KEY key, MASK mask )
{
    BOOL handled = FALSE;

    if (KEY_DELETE == key)
    {
        setAvatarRenderSetting(mAvatarSettingsList->getCurrentID(), (S32)LLVOAvatar::AV_RENDER_NORMALLY);
        handled = TRUE;
    }
    return handled;
}

std::string LLFloaterAvatarRenderSettings::createTimestamp(S32 datetime)
{
    std::string timeStr;
    LLSD substitution;
    substitution["datetime"] = datetime;

    timeStr = "["+LLTrans::getString ("TimeMonth")+"]/["
                 +LLTrans::getString ("TimeDay")+"]/["
                 +LLTrans::getString ("TimeYear")+"]";

    LLStringUtil::format (timeStr, substitution);
    return timeStr;
}