using System;
using System.Collections;
using System.Linq;
namespace OpenVIII
{
///
/// This holds the encoded bytes and provides implict casts to string and byte[]
///
public class FF8String : IEnumerator, IEnumerable
{
#region Fields
protected byte[] value;
private static Encoding.FF8TextEncoding encoding = new Encoding.FF8TextEncoding(Encoding.FF8TextEncodingCodepage.Create());
private int position = 0;
#endregion Fields
#region Constructors
public FF8String()
{
}
public FF8String(byte[] @value) => this.value = @value;
public FF8String(string @value) => this.value = @value != null ? encoding.GetBytes(@value) : null;
#endregion Constructors
#region Properties
public object Current => Value[position - 1];
public virtual byte[] Value { get => value; set => this.value = value; }
///
/// This is incorrect as null can be in the beginning of strings as a marker or tag.
/// But I can't figure out how to make his code leave null as null.
///
public string Value_str => encoding.GetString(Value ?? new byte[] { }).TrimEnd('\0').Replace("{End}", "");
public virtual int Length => value == null ? 0 : value.Length;
#endregion Properties
#region Indexers
public byte this[int index] => value[index];
#endregion Indexers
#region Methods
public static FF8String Combine(FF8String start, FF8String end)
{
if (end != null && end.Length > 0)
{
var combine = new byte[start.Length + end.Length];
Array.Copy(start, 0, combine, 0, start.Length);
Array.Copy(end, 0, combine, start.Length, end.Length);
return combine;
}
else
return start;
}
public static implicit operator byte[] (FF8String input) => input?.Value;
public static implicit operator FF8String(string input) => new FF8String(input);
public static implicit operator FF8String(byte[] input) => new FF8String(input);
public static implicit operator string(FF8String input) => input?.Value_str;
public static FF8String operator +(FF8String a, FF8String b)
{
if (a != null && a.Length > 0)
{
var s = a.Clone();
if (b != null && b.Length > 0)
return s.Append(b);
else
return a;
}
return b;
}
public static FF8String operator +(FF8String a, string b)
{
if (a != null && a.Length > 0)
{
if (!string.IsNullOrEmpty(b))
{
var s = a.Clone();
return s.Append(b);
}
else
return a;
}
return b;
}
public static FF8String operator +(string a, FF8String b)
{
var s = new FF8String(a);
return s.Append(b);
}
public FF8String Append(FF8String end)
{
if (Value != null && Value.Length > 0)
{
if (end != null && end.Length > 0)
{
Array.Resize(ref value, Length + end.Length);
Array.Copy(end.Value, 0, value, Length - end.Length, end.Length);
}
}
else
{
if (end != null && end.Length > 0)
{
Value = end;
}
}
return this;
}
public FF8String Clone()
{
if (Length > 0)
return new FF8String
{
value = (byte[])(value.Clone())
};
else return new FF8String();
}
public FF8String Replace(FF8String a, FF8String b)
{
if (Length > 0 && a != null && b != null && a.Length > 0 && b.Length > 0)
{
var i = 0;
do
{
i = Array.FindIndex(value, i, Length - i, x => x == a[0]);
if (i >= 0)
{
if (value.Skip(i).Take(a.Length).ToArray().SequenceEqual(a.Value))
{
var end = value.Skip(a.Length + i).ToArray();
Array.Resize(ref value, Length + b.Length - a.Length);
Array.Copy(b, 0, value, i, b.Length);
Array.Copy(end, 0, value, i + b.Length, end.Length);
i += b.Length;
}
else
{
i++;
}
}
else break;
}
while (i < Length);
}
return this;
}
public IEnumerator GetEnumerator()
{
if (Value != null && Value.Length > 0)
return this;
return null;
}
public bool MoveNext()
{
if (++position <= Length)
return true;
else
{
Reset();
return false;
}
}
public void Reset() => position = 0;
public override string ToString() => Value_str;
#endregion Methods
}
}