/** 
 * @file llfloaterautoreplacesettings.cpp
 * @brief Auto Replace List floater
 *
 * $LicenseInfo:firstyear=2012&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2012, 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; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * 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
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llfloaterautoreplacesettings.h"

#include "llagentdata.h"
#include "llcommandhandler.h"
#include "llfloater.h"
#include "lluictrlfactory.h"
#include "llagent.h"
#include "llpanel.h"
#include "llbutton.h"
#include "llcolorswatch.h"
#include "llcombobox.h"
#include "llview.h"
#include "llbufferstream.h"
#include "llcheckboxctrl.h"
#include "llviewercontrol.h"

#include "llui.h"
#include "llcontrol.h"
#include "llscrollingpanellist.h"
#include "llautoreplace.h"
#include "llfilepicker.h"
#include "llfile.h"
#include "llsdserialize.h"
#include "llsdutil.h"

#include "llchat.h"
#include "llinventorymodel.h"
#include "llhost.h"
#include "llassetstorage.h"
#include "roles_constants.h"
#include "llviewertexteditor.h"
#include <boost/tokenizer.hpp>

#include <iosfwd>
#include "llfloaterreg.h"
#include "llinspecttoast.h"
#include "llnotificationhandler.h"
#include "llnotificationmanager.h"
#include "llnotificationsutil.h"

// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
static LLPanelInjector<LLPanelPreferenceAutoReplaceSettings> t_pref_chat_autoreplace("panel_preference_chat_autoreplace");

LLPanelPreferenceAutoReplaceSettings::LLPanelPreferenceAutoReplaceSettings()
 : LLPanelPreference()
 , mSelectedListName("")
 , mListNames(NULL)
 , mReplacementsList(NULL)
 , mKeyword(NULL)
 , mPreviousKeyword("")
 , mReplacement(NULL)
{
}
// [/SL:KB]
//LLFloaterAutoReplaceSettings::LLFloaterAutoReplaceSettings(const LLSD& key)
// : LLFloater(key)
// , mSelectedListName("")
// , mListNames(NULL)
// , mReplacementsList(NULL)
// , mKeyword(NULL)
// , mPreviousKeyword("")
// , mReplacement(NULL)
//{
//}

//void LLFloaterAutoReplaceSettings::onClose(bool app_quitting)
//{
//	cleanUp();
//}

// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
BOOL LLPanelPreferenceAutoReplaceSettings::postBuild(void)
{
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
	LLPanelPreference::postBuild();
// [/SL:KB]

	// global checkbox for whether or not autoreplace is active
	LLUICtrl* enabledCheckbox = getChild<LLUICtrl>("autoreplace_enable");
	enabledCheckbox->setCommitCallback(boost::bind(&LLPanelPreferenceAutoReplaceSettings::onAutoReplaceToggled, this));

	// top row list creation and deletion
	getChild<LLUICtrl>("autoreplace_import_list")->setCommitCallback(boost::bind(&LLPanelPreferenceAutoReplaceSettings::onImportList,this));
	getChild<LLUICtrl>("autoreplace_export_list")->setCommitCallback(boost::bind(&LLPanelPreferenceAutoReplaceSettings::onExportList,this));
	getChild<LLUICtrl>("autoreplace_new_list")->setCommitCallback(   boost::bind(&LLPanelPreferenceAutoReplaceSettings::onNewList,this));
	getChild<LLUICtrl>("autoreplace_delete_list")->setCommitCallback(boost::bind(&LLPanelPreferenceAutoReplaceSettings::onDeleteList,this));

	// the list of keyword->replacement lists
	mListNames = getChild<LLScrollListCtrl>("autoreplace_list_name");
	mListNames->setCommitCallback(boost::bind(&LLPanelPreferenceAutoReplaceSettings::onSelectList, this));
	mListNames->setCommitOnSelectionChange(true);
	
	// list ordering
	getChild<LLUICtrl>("autoreplace_list_up")->setCommitCallback(  boost::bind(&LLPanelPreferenceAutoReplaceSettings::onListUp,this));
	getChild<LLUICtrl>("autoreplace_list_down")->setCommitCallback(boost::bind(&LLPanelPreferenceAutoReplaceSettings::onListDown,this));

	// keyword->replacement entry add / delete
	getChild<LLUICtrl>("autoreplace_add_entry")->setCommitCallback(   boost::bind(&LLPanelPreferenceAutoReplaceSettings::onAddEntry,this));
	getChild<LLUICtrl>("autoreplace_delete_entry")->setCommitCallback(boost::bind(&LLPanelPreferenceAutoReplaceSettings::onDeleteEntry,this));

	// entry edits
	mKeyword     = getChild<LLLineEditor>("autoreplace_keyword");
	mReplacement = getChild<LLLineEditor>("autoreplace_replacement");
	getChild<LLUICtrl>("autoreplace_save_entry")->setCommitCallback(boost::bind(&LLPanelPreferenceAutoReplaceSettings::onSaveEntry, this));

	// the list of keyword->replacement pairs
	mReplacementsList = getChild<LLScrollListCtrl>("autoreplace_list_replacements");
	mReplacementsList->setCommitCallback(boost::bind(&LLPanelPreferenceAutoReplaceSettings::onSelectEntry, this));
	mReplacementsList->setCommitOnSelectionChange(true);

	return true;
}

void LLPanelPreferenceAutoReplaceSettings::refresh()
{
	// get copies of the current settings that we will operate on
	mEnabled  = gSavedSettings.getBOOL("AutoReplace");
	LL_DEBUGS("AutoReplace") << ( mEnabled ? "enabled" : "disabled") << LL_ENDL;

	LLUICtrl* enabledCheckbox = getChild<LLUICtrl>("autoreplace_enable");
	enabledCheckbox->setValue(LLSD(mEnabled));

	mSettings = LLAutoReplace::getInstance()->getSettings();

	mSelectedListName.clear();
	updateListNames();
	updateListNamesControls();
	updateReplacementsList();
}
// [/SL:KB]
//BOOL LLFloaterAutoReplaceSettings::postBuild(void)
//{
//	// get copies of the current settings that we will operate on
//	mEnabled  = gSavedSettings.getBOOL("AutoReplace");
//	LL_DEBUGS("AutoReplace") << ( mEnabled ? "enabled" : "disabled") << LL_ENDL;
//
//	mSettings = LLAutoReplace::getInstance()->getSettings();
//	
//	// global checkbox for whether or not autoreplace is active
//	LLUICtrl* enabledCheckbox = getChild<LLUICtrl>("autoreplace_enable");
//	enabledCheckbox->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onAutoReplaceToggled, this));
//	enabledCheckbox->setValue(LLSD(mEnabled));
//
//	// top row list creation and deletion
//	getChild<LLUICtrl>("autoreplace_import_list")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onImportList,this));
//	getChild<LLUICtrl>("autoreplace_export_list")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onExportList,this));
//	getChild<LLUICtrl>("autoreplace_new_list")->setCommitCallback(   boost::bind(&LLFloaterAutoReplaceSettings::onNewList,this));
//	getChild<LLUICtrl>("autoreplace_delete_list")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onDeleteList,this));
//
//	// the list of keyword->replacement lists
//	mListNames = getChild<LLScrollListCtrl>("autoreplace_list_name");
//	mListNames->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSelectList, this));
//	mListNames->setCommitOnSelectionChange(true);
//	
//	// list ordering
//	getChild<LLUICtrl>("autoreplace_list_up")->setCommitCallback(  boost::bind(&LLFloaterAutoReplaceSettings::onListUp,this));
//	getChild<LLUICtrl>("autoreplace_list_down")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onListDown,this));
//
//	// keyword->replacement entry add / delete
//	getChild<LLUICtrl>("autoreplace_add_entry")->setCommitCallback(   boost::bind(&LLFloaterAutoReplaceSettings::onAddEntry,this));
//	getChild<LLUICtrl>("autoreplace_delete_entry")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onDeleteEntry,this));
//
//	// entry edits
//	mKeyword     = getChild<LLLineEditor>("autoreplace_keyword");
//	mReplacement = getChild<LLLineEditor>("autoreplace_replacement");
//	getChild<LLUICtrl>("autoreplace_save_entry")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSaveEntry, this));
//
//	// dialog termination ( Save Changes / Cancel )
//	getChild<LLUICtrl>("autoreplace_save_changes")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSaveChanges, this));
//	getChild<LLUICtrl>("autoreplace_cancel")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onCancel, this));
//
//	// the list of keyword->replacement pairs
//	mReplacementsList = getChild<LLScrollListCtrl>("autoreplace_list_replacements");
//	mReplacementsList->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSelectEntry, this));
//	mReplacementsList->setCommitOnSelectionChange(true);
//
//	center();
//
//	mSelectedListName.clear();
//	updateListNames();
//	updateListNamesControls();
//	updateReplacementsList();
//
//	return true;
//}


//void LLFloaterAutoReplaceSettings::updateListNames()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::updateListNames()
// [/SL:KB]
{
	mListNames->deleteAllItems(); // start from scratch

	LLSD listNames = mSettings.getListNames(); // Array of Strings
   
	for ( LLSD::array_const_iterator entry = listNames.beginArray(), end = listNames.endArray();
		  entry != end;
		  ++entry
		 )
	{
		const std::string& listName = entry->asString();
		mListNames->addSimpleElement(listName);
	}

	if (!mSelectedListName.empty())
	{
		mListNames->setSelectedByValue( LLSD(mSelectedListName), true );
	}
}

//void LLFloaterAutoReplaceSettings::updateListNamesControls()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::updateListNamesControls()
// [/SL:KB]
{
	if ( mSelectedListName.empty() )
	{
		// There is no selected list

		// Disable all controls that operate on the selected list
		getChild<LLButton>("autoreplace_export_list")->setEnabled(false);
		getChild<LLButton>("autoreplace_delete_list")->setEnabled(false);
		getChild<LLButton>("autoreplace_list_up")->setEnabled(false);
		getChild<LLButton>("autoreplace_list_down")->setEnabled(false);

		mReplacementsList->deleteAllItems();
	}
	else
	{
		// Enable the controls that operate on the selected list
		getChild<LLButton>("autoreplace_export_list")->setEnabled(true);
		getChild<LLButton>("autoreplace_delete_list")->setEnabled(true);
		getChild<LLButton>("autoreplace_list_up")->setEnabled(!selectedListIsFirst());
		getChild<LLButton>("autoreplace_list_down")->setEnabled(!selectedListIsLast());
	}
}

//void LLFloaterAutoReplaceSettings::onSelectList()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::onSelectList()
// [/SL:KB]
{
	std::string previousSelectedListName = mSelectedListName;
	// only one selection allowed
	LLSD selected = mListNames->getSelectedValue();
	if (selected.isDefined())
	{
		mSelectedListName = selected.asString();
		LL_DEBUGS("AutoReplace")<<"selected list '"<<mSelectedListName<<"'"<<LL_ENDL;
	}
	else
	{
		mSelectedListName.clear();
		LL_DEBUGS("AutoReplace")<<"unselected"<<LL_ENDL;
	}

	updateListNamesControls();

	if ( previousSelectedListName != mSelectedListName )
	{
		updateReplacementsList();
	}
}

//void LLFloaterAutoReplaceSettings::onSelectEntry()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::onSelectEntry()
// [/SL:KB]
{
    LLSD selectedRow = mReplacementsList->getSelectedValue();
	if (selectedRow.isDefined())
	{
		mPreviousKeyword = selectedRow.asString();
		LL_DEBUGS("AutoReplace")<<"selected entry '"<<mPreviousKeyword<<"'"<<LL_ENDL;	
		mKeyword->setValue(selectedRow);
		std::string replacement = mSettings.replacementFor(mPreviousKeyword, mSelectedListName );
		mReplacement->setValue(replacement);
		enableReplacementEntry();		
		mReplacement->setFocus(true);
	}
	else
	{
		// no entry selection, so the entry panel should be off
		disableReplacementEntry();		
		LL_DEBUGS("AutoReplace")<<"no row selected"<<LL_ENDL;
	}
}

//void LLFloaterAutoReplaceSettings::updateReplacementsList()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::updateReplacementsList()
// [/SL:KB]
{
	// start from scratch, since this should only be called when the list changes
	mReplacementsList->deleteAllItems();

	if ( mSelectedListName.empty() )
	{
		mReplacementsList->setEnabled(false);
		getChild<LLButton>("autoreplace_add_entry")->setEnabled(false);
		disableReplacementEntry();		
	}
	else
	{
		// Populate the keyword->replacement list from the selected list
		const LLSD* mappings = mSettings.getListEntries(mSelectedListName);
		for ( LLSD::map_const_iterator entry = mappings->beginMap(), end = mappings->endMap();
			  entry != end;
			  entry++
			 )
		{
			LLSD row;
			row["id"] = entry->first;
			row["columns"][0]["column"] = "keyword";
			row["columns"][0]["value"]  = entry->first;
			row["columns"][1]["column"] = "replacement";
			row["columns"][1]["value"]  = entry->second;

			mReplacementsList->addElement(row, ADD_BOTTOM);
		}

		mReplacementsList->deselectAllItems(false /* don't call commit */);
		mReplacementsList->setEnabled(true);

		getChild<LLButton>("autoreplace_add_entry")->setEnabled(true);
		disableReplacementEntry();		
	}
}

//void LLFloaterAutoReplaceSettings::enableReplacementEntry()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::enableReplacementEntry()
// [/SL:KB]
{
	LL_DEBUGS("AutoReplace")<<LL_ENDL;
	mKeyword->setEnabled(true);
	mReplacement->setEnabled(true);
	getChild<LLButton>("autoreplace_save_entry")->setEnabled(true);
	getChild<LLButton>("autoreplace_delete_entry")->setEnabled(true);
}

//void LLFloaterAutoReplaceSettings::disableReplacementEntry()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::disableReplacementEntry()
// [/SL:KB]
{
	LL_DEBUGS("AutoReplace")<<LL_ENDL;
	mPreviousKeyword.clear();
	mKeyword->clear();
	mKeyword->setEnabled(false);
	mReplacement->clear();
	mReplacement->setEnabled(false);
	getChild<LLButton>("autoreplace_save_entry")->setEnabled(false);
	getChild<LLButton>("autoreplace_delete_entry")->setEnabled(false);
}

// called when the global settings checkbox is changed
//void LLFloaterAutoReplaceSettings::onAutoReplaceToggled()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::onAutoReplaceToggled()
// [/SL:KB]
{
	// set our local copy of the flag, copied to the global preference in onOk
	mEnabled = childGetValue("autoreplace_enable").asBoolean();
	LL_DEBUGS("AutoReplace")<< "autoreplace_enable " << ( mEnabled ? "on" : "off" ) << LL_ENDL;
}

// called when the List Up button is pressed
//void LLFloaterAutoReplaceSettings::onListUp()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::onListUp()
// [/SL:KB]
{
	S32 selectedRow = mListNames->getFirstSelectedIndex();
	LLSD selectedName = mListNames->getSelectedValue().asString();

	if ( mSettings.increaseListPriority(selectedName) )
	{
		updateListNames();
		updateListNamesControls();
	}
	else
	{
		LL_WARNS("AutoReplace")
			<< "invalid row ("<<selectedRow<<") selected '"<<selectedName<<"'"
			<<LL_ENDL;
	}
}

// called when the List Down button is pressed
//void LLFloaterAutoReplaceSettings::onListDown()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::onListDown()
// [/SL:KB]
{
	S32 selectedRow = mListNames->getFirstSelectedIndex();
	std::string selectedName = mListNames->getSelectedValue().asString();

	if ( mSettings.decreaseListPriority(selectedName) )
	{
		updateListNames();
		updateListNamesControls();
	}
	else
	{
		LL_WARNS("AutoReplace")
			<< "invalid row ("<<selectedRow<<") selected '"<<selectedName<<"'"
			<<LL_ENDL;
	}
}

// called when the Delete Entry button is pressed
//void LLFloaterAutoReplaceSettings::onDeleteEntry()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::onDeleteEntry()
// [/SL:KB]
{
    LLSD selectedRow = mReplacementsList->getSelectedValue();
	if (selectedRow.isDefined())
	{	
		std::string keyword = selectedRow.asString();
		mReplacementsList->deleteSelectedItems(); // delete from the control
		mSettings.removeEntryFromList(keyword, mSelectedListName); // delete from the local settings copy
		disableReplacementEntry(); // no selection active, so turn off the buttons
	}
}

// called when the Import List button is pressed
//void LLFloaterAutoReplaceSettings::onImportList()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::onImportList()
// [/SL:KB]
{
//	LLFilePicker& picker = LLFilePicker::instance();
//	if( picker.getOpenFile( LLFilePicker::FFLOAD_XML) )
// [SL:KB] - Patch: Control-FilePicker | Checked: 2013-03-14 (Catznip-3.4)
	LLFilePicker::getOpenFile(LLFilePicker::FFLOAD_XML, 
		boost::bind(&LLPanelPreferenceAutoReplaceSettings::onImportListCallback, this, _1));
}

void LLPanelPreferenceAutoReplaceSettings::onImportListCallback(const std::string& filepath)
{
	if (!filepath.empty())
// [/SL:KB]
	{
		llifstream file;
// [SL:KB] - Patch: Control-FilePicker | Checked: 2013-03-14 (Catznip-3.4)
		file.open(filepath.c_str());
// [/SL:KB]
//		file.open(picker.getFirstFile().c_str());
		LLSD newList;
		if (file.is_open())
		{
			LLSDSerialize::fromXMLDocument(newList, file);
		}
		file.close();

		switch ( mSettings.addList(newList) )
		{
		case LLAutoReplaceSettings::AddListOk:
			mSelectedListName = LLAutoReplaceSettings::getListName(newList);
			
			updateListNames();
			updateListNamesControls();
			updateReplacementsList();
			break;

		case LLAutoReplaceSettings::AddListDuplicateName:
			{
				std::string newName = LLAutoReplaceSettings::getListName(newList);
				LL_WARNS("AutoReplace")<<"name '"<<newName<<"' is in use; prompting for new name"<<LL_ENDL;
				LLSD newPayload;
				newPayload["list"] = newList;
				LLSD args;
				args["DUPNAME"] = newName;
	
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
				LLNotificationsUtil::add("RenameAutoReplaceList", args, newPayload,
										 boost::bind(&LLPanelPreferenceAutoReplaceSettings::callbackListNameConflict, this, _1, _2));
// [/SL:KB]
//				LLNotificationsUtil::add("RenameAutoReplaceList", args, newPayload,
//										 boost::bind(&LLFloaterAutoReplaceSettings::callbackListNameConflict, this, _1, _2));
			}
			break;

		case LLAutoReplaceSettings::AddListInvalidList:
			LLNotificationsUtil::add("InvalidAutoReplaceList");
			LL_WARNS("AutoReplace") << "imported list was invalid" << LL_ENDL;

			mSelectedListName.clear();
			updateListNames();
			updateListNamesControls();
			updateReplacementsList();
			break;

		default:
			LL_ERRS("AutoReplace") << "invalid AddListResult" << LL_ENDL;

		}
		
	}
	else
	{
		LL_DEBUGS("AutoReplace") << "file selection failed for import list" << LL_ENDL;
	}		
}

//void LLFloaterAutoReplaceSettings::onNewList()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::onNewList()
// [/SL:KB]
{
	LLSD payload;
	LLSD emptyList;
	LLAutoReplaceSettings::createEmptyList(emptyList);
	payload["list"] = emptyList;
    LLSD args;
	
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
	LLNotificationsUtil::add("AddAutoReplaceList", args, payload,
							 boost::bind(&LLPanelPreferenceAutoReplaceSettings::callbackNewListName, this, _1, _2));
// [/SL:KB]
//	LLNotificationsUtil::add("AddAutoReplaceList", args, payload,
//							 boost::bind(&LLFloaterAutoReplaceSettings::callbackNewListName, this, _1, _2));
}

//bool LLFloaterAutoReplaceSettings::callbackNewListName(const LLSD& notification, const LLSD& response)
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
bool LLPanelPreferenceAutoReplaceSettings::callbackNewListName(const LLSD& notification, const LLSD& response)
// [/SL:KB]
{
	LL_DEBUGS("AutoReplace")<<"called"<<LL_ENDL;
	
	LLSD newList = notification["payload"]["list"];

	if ( response.has("listname") && response["listname"].isString() )
	{
		std::string newName = response["listname"].asString();
		LLAutoReplaceSettings::setListName(newList, newName);

		switch ( mSettings.addList(newList) )
		{
		case LLAutoReplaceSettings::AddListOk:
			LL_INFOS("AutoReplace") << "added new list '"<<newName<<"'"<<LL_ENDL;
			mSelectedListName = newName;
			updateListNames();
			updateListNamesControls();
			updateReplacementsList();
			break;

		case LLAutoReplaceSettings::AddListDuplicateName:
			{
				LL_WARNS("AutoReplace")<<"name '"<<newName<<"' is in use; prompting for new name"<<LL_ENDL;
				LLSD newPayload;
				newPayload["list"] = notification["payload"]["list"];
				LLSD args;
				args["DUPNAME"] = newName;
	
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
				LLNotificationsUtil::add("RenameAutoReplaceList", args, newPayload,
										 boost::bind(&LLPanelPreferenceAutoReplaceSettings::callbackListNameConflict, this, _1, _2));
// [/SL:KB]
//				LLNotificationsUtil::add("RenameAutoReplaceList", args, newPayload,
//										 boost::bind(&LLFloaterAutoReplaceSettings::callbackListNameConflict, this, _1, _2));
			}
			break;

		case LLAutoReplaceSettings::AddListInvalidList:
			LLNotificationsUtil::add("InvalidAutoReplaceList");

			mSelectedListName.clear();
			updateListNames();
			updateListNamesControls();
			updateReplacementsList();
			break;

		default:
			LL_ERRS("AutoReplace") << "invalid AddListResult" << LL_ENDL;
		}
	}
	else
	{
		LL_ERRS("AutoReplace") << "adding notification response" << LL_ENDL;
	}
	return false;
}

// callback for the RenameAutoReplaceList notification
//bool LLFloaterAutoReplaceSettings::callbackListNameConflict(const LLSD& notification, const LLSD& response)
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
bool LLPanelPreferenceAutoReplaceSettings::callbackListNameConflict(const LLSD& notification, const LLSD& response)
// [/SL:KB]
{
	LLSD newList = notification["payload"]["list"];
	std::string listName = LLAutoReplaceSettings::getListName(newList);
	
	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
	switch ( option )
	{
	case 0:
		// Replace current list
		if ( LLAutoReplaceSettings::AddListOk == mSettings.replaceList(newList) )
		{
			LL_INFOS("AutoReplace") << "replaced list '"<<listName<<"'"<<LL_ENDL;
			mSelectedListName = listName;
			updateListNames();
			updateListNamesControls();
			updateReplacementsList();
		}
		else
		{
			LL_WARNS("AutoReplace")<<"failed to replace list '"<<listName<<"'"<<LL_ENDL;
		}
		break;

	case 1:
		// Use New Name
		LL_INFOS("AutoReplace")<<"option 'use new name' selected"<<LL_ENDL;
		callbackNewListName(notification, response);
		break;

	default:
		LL_ERRS("AutoReplace")<<"invalid selected option "<<option<<LL_ENDL;
	}

	return false;
}

//void LLFloaterAutoReplaceSettings::onDeleteList()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::onDeleteList()
// [/SL:KB]
{
	std::string listName = mListNames->getSelectedValue().asString();
	if ( ! listName.empty() )
	{
		if ( mSettings.removeReplacementList(listName) )
		{
			LL_INFOS("AutoReplace")<<"deleted list '"<<listName<<"'"<<LL_ENDL;
			mReplacementsList->deleteSelectedItems();   // remove from the scrolling list
			mSelectedListName.clear();
			updateListNames();
			updateListNamesControls();
			updateReplacementsList();
		}
		else
		{
			LL_WARNS("AutoReplace")<<"failed to delete list '"<<listName<<"'"<<LL_ENDL;
		}
	}
	else
	{
		LL_DEBUGS("AutoReplace")<<"no list selected for delete"<<LL_ENDL;
	}
}

//void LLFloaterAutoReplaceSettings::onExportList()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::onExportList()
// [/SL:KB]
{
	std::string listName=mListNames->getFirstSelected()->getColumn(0)->getValue().asString();
//	const LLSD* list = mSettings.exportList(listName);
	std::string listFileName = listName + ".xml";
//	LLFilePicker& picker = LLFilePicker::instance();
//	if( picker.getSaveFile( LLFilePicker::FFSAVE_XML, listFileName) )
// [SL:KB] - Patch: Control-FilePicker | Checked: 2013-03-14 (Catznip-3.4)
	LLFilePicker::getSaveFile(LLFilePicker::FFSAVE_XML, listFileName,  boost::bind(&LLPanelPreferenceAutoReplaceSettings::onExportListCallback, this, listName, _1));
}

void LLPanelPreferenceAutoReplaceSettings::onExportListCallback(const std::string& listName, const std::string& filepath)
{
	if (!filepath.empty())
// [/SL:KB]
	{
		llofstream file;
// [SL:KB] - Patch: Control-FilePicker | Checked: 2013-03-14 (Catznip-3.4)
		file.open(filepath.c_str());
		const LLSD* list = mSettings.exportList(listName);
// [/SL:KB]
//		file.open(picker.getFirstFile().c_str());
		LLSDSerialize::toPrettyXML(*list, file);
		file.close();
	}
}

//void LLFloaterAutoReplaceSettings::onAddEntry()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::onAddEntry()
// [/SL:KB]
{
	mPreviousKeyword.clear();
	mReplacementsList->deselectAllItems(false /* don't call commit */);
	mKeyword->clear();
	mReplacement->clear();
	enableReplacementEntry();
	mKeyword->setFocus(true);
}

//void LLFloaterAutoReplaceSettings::onSaveEntry()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::onSaveEntry()
// [/SL:KB]
{
	LL_DEBUGS("AutoReplace")<<"called"<<LL_ENDL;
	
	if ( ! mPreviousKeyword.empty() )
	{
		// delete any existing value for the key that was editted
		LL_INFOS("AutoReplace")
			<< "list '" << mSelectedListName << "' "
			<< "removed '" << mPreviousKeyword
			<< "'" << LL_ENDL;
		mSettings.removeEntryFromList( mPreviousKeyword, mSelectedListName );
	}

	LLWString keyword     = mKeyword->getWText();
	LLWString replacement = mReplacement->getWText();
	if ( mSettings.addEntryToList(keyword, replacement, mSelectedListName) )
	{
		// insert the new keyword->replacement pair
		LL_INFOS("AutoReplace")
			<< "list '" << mSelectedListName << "' "
			<< "added '" << wstring_to_utf8str(keyword)
			<< "' -> '" << wstring_to_utf8str(replacement)
			<< "'" << LL_ENDL;

		updateReplacementsList();
	}
	else
	{
		LLNotificationsUtil::add("InvalidAutoReplaceEntry");
		LL_WARNS("AutoReplace")<<"invalid entry "
							   << "keyword '" << wstring_to_utf8str(keyword)
							   << "' replacement '" << wstring_to_utf8str(replacement)
							   << "'" << LL_ENDL;
	}
}

// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::cancel()
{
	LLPanelPreference::cancel();

	cleanUp();
}
// [/SL:KB]
//void LLFloaterAutoReplaceSettings::onCancel()
//{
//	cleanUp();
//	closeFloater(false /* not quitting */);
//}

// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::apply()
{
	LLPanelPreference::apply();

	// put our local copy of the settings into the active copy
	LLAutoReplace::getInstance()->setSettings( mSettings );
	// save our local copy of the global feature enable/disable value
	gSavedSettings.setBOOL("AutoReplace", mEnabled);
	cleanUp();
}
// [/SL:KB]
//void LLFloaterAutoReplaceSettings::onSaveChanges()
//{
//	// put our local copy of the settings into the active copy
//	LLAutoReplace::getInstance()->setSettings( mSettings );
//	// save our local copy of the global feature enable/disable value
//	gSavedSettings.setBOOL("AutoReplace", mEnabled);
//	cleanUp();
//	closeFloater(false /* not quitting */);
//}

//void LLFloaterAutoReplaceSettings::cleanUp()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
void LLPanelPreferenceAutoReplaceSettings::cleanUp()
// [/SL:KB]
{

}

//bool LLFloaterAutoReplaceSettings::selectedListIsFirst()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
bool LLPanelPreferenceAutoReplaceSettings::selectedListIsFirst()
// [/SL:KB]
{
	bool isFirst = false;
	
	if (!mSelectedListName.empty())
	{
		LLSD lists = mSettings.getListNames(); // an Array of Strings
		LLSD first = lists.get(0);
		if ( first.isString() && first.asString() == mSelectedListName )
		{
			isFirst = true;
		}
	}
	return isFirst;
}

//bool LLFloaterAutoReplaceSettings::selectedListIsLast()
// [SL:KB] - Patch: Preferences-AutoReplace | Checked: 2014-03-04 (Catznip-3.6)
bool LLPanelPreferenceAutoReplaceSettings::selectedListIsLast()
// [/SL:KB]
{
	bool isLast = false;
	
	if (!mSelectedListName.empty())
	{
		LLSD last;
		LLSD lists = mSettings.getListNames(); // an Array of Strings
		for ( LLSD::array_const_iterator list = lists.beginArray(), listEnd = lists.endArray();
			  list != listEnd;
			  list++
			 )
		{
			last = *list;
		}
		if ( last.isString() && last.asString() == mSelectedListName )
		{
			isLast = true;
		}
	}
	return isLast;
}

/* TBD
mOldText = getChild<LLLineEditor>("autoreplace_old_text");
mNewText = getChild<LLLineEditor>("autoreplace_new_text");
*/
