This document provides a brief outline of the API provided by XRP, allowing
other addons to interact with RP profile data.

Please note that certain parts of the API are not currently hardened against
stupidity, as they're mostly internally used. If you give them the wrong
argument types, they can produce Lua errors or behave in unexpected ways. The
character lookup tables and profile interaction tables are hardened against
most types of stupidity, however, and should need less caution when being
interacted with.

Looking up other characters
===========================

Character data for others is stored in four metatables, xrp.units, xrp.guids,
xrp.characters, and xrp.cache.

xrp.units:
	This metatable provides access to character profile data for a specified
	unit. For instance, xrp.units.target will contain information about the
	current target (or will be nil if the target is not a player). You may
	index this for any fields, and their contents will be returned (or nil if
	no contents).

xrp.guids:
	This metatable provides access to character profile data for a specified
	GUID. Note that GetPlayerInfoByGUID() must be able to succeed on the
	specified GUID (meaning the WoW client has seen it in this session -- you
	cannot make use of a stored value from another session). As an example,
	xrp.guids[UnitGUID("player")] will contain information about the current
	player themselves (but, of course, this is better used with non-self
	targets, such as for GUIDs attached to CHAT_MSG_* events).

xrp.characters:
	This metatable provides access to character profile data for a specified
	character name. This name should be of the form Name-RealmName (though
	'-RealmName' *may* be ommitted for same-realm, it is strongly recommended
	to include it). For example, xrp.characters["Bor-WyrmrestAccord"] contains
	any profile data for the character Bor on the Wyrmrest Accord realm.

The above three metatables automatically perform requests for updated versions
of fields as appropriate. In general, there is no purpose to running any
explicit request when interacting with XRP -- just access the information
through one of the above-three tables, and it will be updated shortly.

xrp.cache:
	This metatable provides the same access as the xrp.characters metatable,
	but it explicitly does not request new data. This should generally not be
	used, but is useful in cases where you explicitly want cached data, or are
	certain that a request for updated fields would fail.

All of the above tables can be indexed for MSP field names (such as NA for
roleplay name, GC for toon class, HI for character history, etc.), but pairs()
may not be used on them currently. If you absolutely require a full dump of
all available fields for a character, you may call the profile as a function,
but this is strongly discouraged. Supporting a specific set of fields and
indexing each of them individually is recommended.

Reacting to incoming profile data
=================================

Incoming profile data is provided in several ways, but all is hooked through
the use of xrp:HookEvent(). This function takes two arguments: the first is
the name of the event you wish to hook (listed later), and the second is the
function to call with the event-specific arguments when the event occurs.
There is no way to unhook an event currently (though this may be added later).

Events:

All of the following events provide a first argument of the name-with-realm
of the character for whom the event is firing.

	- MSP_RECEIVE: Fires when a complete profile, including updated data, has
	  been received and processed. Any new data is immediately available
	  through any of the character tables.

	- MSP_NOCHANGE: Fires when a receive is completed which provides no
	  updated profile data for a character.

	- MSP_FIELD: Fires when a new or updated field is received (including
	  incomplete receives -- this fires as data is incoming). This provides
	  a second argument with the name of the MSP field which has just been
	  updated. This is likely to fire multiple times in quick succession as
	  each newly-updated field is processed, and indicates the new field data
	  is immediately avaialble in the character tables.

	- MSP_CHUNK: Fires when a profile data chunk is received. This does not
	  indicate any field processing has taken place, simply that data is
	  currently incoming. It provides one or two additional arguments: the
	  first is the incoming chunk number (counting from the first message
	  received in that batch), and the second is, only if available, the
	  total number of expected incoming chunks.

	- MSP_FAIL: Fires when profile data is not being requested or cannot be
	  received for a number of reasons. It provides an extra argument which
	  indicates the reason for the failure, which can be any of the following:
		- faction: Indicates the character is not on the same faction.
		- offline: Indicates the character is offline.
		- nomsp: Indicates the character likely does not have an MSP-enabled
		  addon active.

In general, MSP_RECEIVE and MSP_FIELD are the most useful events to hook, as
the other events are mainly only useful if you are implementing a full viewer
to replace xrp_viewer.

Reading and modifying the current public profile
================================================

The contents of the current public profile may be read from the xrp.current
table, using the same field names as MSP uses elsewhere.

The current public profile is treated somewhat specially in XRP, as the full
contents of the public profile may not completely correspond to the contents
of any single saved profile. There are three special ways that data is added or
removed from the active profile.

The base of the profile is comprised of the currently-active saved profile, but
some data is pulled from other sources. The VA (version) and VP (protocol)
fields are filled automatically from XRP's version information, and the unit-
related fields (G* fields) are automatically generated at login and cannot be
modified by the user. Certain fields may also be inherited from the "Default"
profile, if the values of those fields are empty in the currently-selected
profile (which fields are is user-set).

Finally, fields can be temporarily overriden by writing to the xrp.current
table. These overrides are stored in a SavedVariable, but are wiped if the next
login is greater than ten minutes after that character last logged out. Any
fields may be overridden, and setting the field's value to nil removes the
override. To explicitly set a field to empty, use an empty string instead ("").

The same data is also available in the xrp.selected table, but minus the
overriden fields. This can be used to check if a field has been overriden, such
as through code like "xrp.current.FC ~= xrp.selected.FC" (if this expression
evaluates to true, the FC field has been temporarily overriden). Unlike
xrp.current, this table cannot be written to.

Reading and writing saved profile data
======================================

Stored profiles are kept, by name, in xrp.profiles (and a full list of saved
profiles may be obtained by running xrp.profiles()). The profile "Default"
(localized by xrp.L["Default"]) and "Default (Old)" (localized by
xrp.L["Default (Old)"]) are treated specially for some purposes. Other named
profiles are treated without any unique treatment, regardless of name.

As with most other storage tables, reading/writing the MSP field names provides
access to the stored profile information and the ability to change the profile
data. In addition, there is an xrp.defaults[profile] table which stores the
true/false booleans for whether the named profile will inherit any empty fields from the "Default" profile or not.

Helper functions
================

Contained in xrp/core/helpers.lua are a number of useful functions that can be
used to manipulate data from XRP in helpful ways.

xrp:UnitNameWithRealm(unit):
	arguments: unit (unitID/string)
	returns: Unit name with attached realm name, including same-realm. nil is
		returned if unit is not a player or the name cannot be determined.

xrp:NameWithRealm(name, realm):
	arguments: name (string), realm (string, optional)
	returns: Returns input name if a realm name is already present, otherwise
		returns input name with specified realm name (or current realm name,
		if realm is nil or empty) attached.

xrp:NameWithoutRealm(name)
	arguments: name (string)
	returns: A name suitable for display, never having a realm name attached.
		In essence, this is similar to Ambiguate(), except it always strips
		realm names if present.

xrp:RealmNameWithSpacing(realm)
	arguments: realm (string)
	returns: Realm name with proper spacing. Currently only supports
		English-named realms. (Examples: WyrmrestAccord -> Wyrmrest Accord,
		Area52 -> Area 52, SistersofElune -> Sisters of Elune.)

xrp:StripEscapes(text)
	arguments: text (string)
	returns: Text with pipe escapes stripped or rendered non-functional.

xrp:StripPunctuation(text)
	arguments: text (string)
	returns: Text with most punctuation stripped from beginning and end of
		string. This is designed for in-line display of RP names, while
		removing attention-seeking formatting (i.e., ~~[[Name]]~~ becomes
		simply Name).

xrp:ConvertWeight(weight, units)
	arguments: weight (string), units (string)
	returns: Input weight converted, if possible, to specified units. Possible
		values for units are: "msp", "lb", and "kg". If units are not
		provided, the user-selected preferred units are used. If conversion is
		not possible, the input weight is returned untouched.

xrp:ConvertHeight(height, units)
	arguments: height (string), units (string)
	returns: Input height converted, if possible, to specified units. Possible
		values for units are: "msp", "cm", "m", and "ft". If units are not
		provided, the user-selected preferred units are used. If conversion is
		not possible, the input height is returned untouched.

xrp.L[string]
	arguments: string (string)
	returns: Localized version of input string. Note that this is called as
		a table, rather than a function. It may also be used as a local without
		issue (such as via "local L = xrp.L").
