#region Arthea License
/***********************************************************************
* Arthea MUD by R. Jennings (2007) http://arthea.googlecode.com/ *
* By using this code you comply with the Artistic and GPLv2 Licenses. *
***********************************************************************/
#endregion
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Xml.Serialization;
using Arthea.Connections;
using Arthea.Connections.Players;
using Arthea.Continents;
using Arthea.Continents.Areas;
using Arthea.Continents.Areas.Characters;
using Arthea.Continents.Areas.Items;
using Arthea.Continents.Areas.Rooms;
using Arthea.Creation.Attributes;
namespace Arthea.Creation
{
/// <summary>
/// Implements On Line Creation methods
/// </summary>
public class Olc
{
#region [rgn] Fields (4)
private const BindingFlags bindingFlags = BindingFlags.IgnoreCase
| BindingFlags.Instance
| BindingFlags.NonPublic;
private readonly Connection conn;
private readonly object editing;
private FieldInfo fieldInfo;
#endregion [rgn]
#region [rgn] Constructors (1)
/// <summary>
/// Initializes a new instance of the <see cref="Olc"/> class.
/// </summary>
/// <param name="connection">The connection.</param>
/// <param name="obj">The obj.</param>
public Olc(Connection connection, object obj)
{
conn = connection;
editing = obj;
}
#endregion [rgn]
#region [rgn] Methods (11)
// [rgn] Public Methods (9)
/// <summary>
/// Creates a new object for editing given an object type.
/// </summary>
/// <param name="player">the player doing the editing.</param>
/// <param name="type">the type of object to create.</param>
/// <param name="argument">additional arguments</param>
public static void Create(Player player, Type type, String argument)
{
switch (type.Name)
{
case "Room":
Room.Create(player, argument);
break;
case "ItemIndex":
ItemIndex.Create(player, argument);
break;
case "Help":
Help.Create(player, argument);
break;
case "Area":
Area.Create(player, argument);
break;
case "ScriptCode":
CharIndex.Create(player, argument);
break;
case "Social":
Social.Create(player, argument);
break;
case "Continent":
Continent.Create(player, argument);
break;
default:
player.WriteLine("Unable to create a {0}.", type.Name.ToLower());
break;
}
}
/// <summary>
/// Shows available commands for a players editor.
/// </summary>
public void DisplayCommands()
{
FieldInfo[] fields = GetAllFields(editing.GetType(), false);
string[] names = new string[fields.Length];
for (int i = 0; i < fields.Length; i++)
names[i] = fields[i].Name;
Columns.Show(conn.Player, 4, 10, names);
}
/// <summary>
/// Edits a field for an object begin edited by a player.
/// </summary>
/// <param name="line">the field and value.</param>
/// <returns>true if a field matching argument was found.</returns>
public bool Edit(String line)
{
String argument = new String(line);
String arg = argument.FirstArg();
if (!arg || arg == "show")
{
Show();
return true;
}
if (arg == "done")
{
conn.Editing = null;
return true;
}
if (arg == "?")
{
DisplayCommands();
return true;
}
if (arg == "create")
{
Create(conn.Player, editing.GetType(), argument);
return true;
}
fieldInfo = GetField(editing.GetType(), arg);
if (fieldInfo == null)
{
return false;
}
if (EnterStringEditor())
{
return true;
}
if (!argument)
{
conn.WriteLine("Set {0} to what?", FieldToWords(fieldInfo.Name));
return true;
}
new OlcField(editing, fieldInfo).Edit(conn.Player, argument);
return true;
}
/// <summary>
/// Formats a field name into human readable form.
/// </summary>
/// <param name="name">the (field) name</param>
/// <returns>the name formated</returns>
public static string FieldToWords(string name)
{
StringBuilder buf = new StringBuilder();
CharEnumerator c = name.GetEnumerator();
if (!c.MoveNext())
return name;
buf.Append(char.ToUpper(c.Current));
while (c.MoveNext())
{
if (char.IsUpper(c.Current))
{
buf.Append(" ");
}
buf.Append(c.Current);
}
return buf.ToString();
}
/// <summary>
/// Gets all properties.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="toShow"><c>true</c> if we are using fields to display values.</param>
/// <returns>an array of editable fields</returns>
public static FieldInfo[] GetAllFields(Type type, bool toShow)
{
List<FieldInfo> fields = new List<FieldInfo>(type.GetFields(bindingFlags));
Type baseType = type.BaseType;
while (baseType != null)
{
fields.AddRange(baseType.GetFields(bindingFlags));
baseType = baseType.BaseType;
}
fields.RemoveAll(delegate(FieldInfo f) { return IgnoreField(f, toShow); });
return fields.ToArray();
}
/// <summary>
/// Gets a field by name from a type.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="arg">The arg.</param>
/// <returns>a fieldinfo object</returns>
public static FieldInfo GetField(Type type, String arg)
{
foreach (FieldInfo info in GetAllFields(type, false))
{
if (arg.IsPrefixOf(info.Name))
return info;
}
return null;
}
/// <summary>
/// Shows all fields and values for a players editor.
/// </summary>
public void Show()
{
foreach (FieldInfo info in GetAllFields(editing.GetType(), true))
{
conn.WriteLine("{0}: {1}", FieldToWords(info.Name),
info.GetValue(editing));
}
}
/// <summary>
/// Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
/// </returns>
public override string ToString()
{
return editing.GetType().Name + "Edit";
}
/// <summary>
/// Takes a human readable word and reformats it into a field name.
/// </summary>
/// <param name="name">the (field) name</param>
/// <returns>a field name</returns>
public static string WordsToField(string name)
{
StringBuilder buf = new StringBuilder();
CharEnumerator c = name.GetEnumerator();
if (!c.MoveNext())
return name;
buf.Append(char.ToLower(name[0]));
while (c.MoveNext())
{
if (c.Current == ' ')
{
if (!c.MoveNext())
break;
buf.Append(char.ToUpper(c.Current));
}
else
{
buf.Append(c.Current);
}
}
return buf.ToString();
}
// [rgn] Private Methods (2)
private bool EnterStringEditor()
{
if (fieldInfo.GetValue(editing) is string)
{
foreach (object attr in fieldInfo.GetCustomAttributes(true))
{
if (attr is TextEdit)
{
string obj = fieldInfo.GetValue(editing) as string;
conn.Composing = new StringEditor().Append(conn, obj);
return true;
}
}
}
return false;
}
/// <summary>
/// Checks a fields attributes to see if it should be ignored.
/// </summary>
/// <param name="info">the field info</param>
/// <param name="show">is the method being called from Olc.Show</param>
/// <returns>true if the field should be ignored</returns>
private static bool IgnoreField(ICustomAttributeProvider info, bool show)
{
foreach (object attr in info.GetCustomAttributes(true))
{
if (attr is EditIgnore || attr is XmlIgnoreAttribute ||
(attr is EditShow && !show))
{
return true;
}
}
return false;
}
#endregion [rgn]
}
}