using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using ln.objects.catalog; namespace ln.types.odb.ng { public class Document : ODBEntity { public override ODBValue Identity => new ODBGuid(ID); private Dictionary properties = new Dictionary(); public Document() :base(0x1001) { ID = Guid.NewGuid(); } public Document(Guid id) :base(0x1001) { ID = id; } public Guid ID { get; } public DateTime StorageTimeStamp { get; set; } public Document(byte[] bytes) : this(bytes, 0, bytes.Length) {} public Document(byte[] bytes,int offset,int length) :this(new Guid(bytes.Slice(offset, 16))) { int endOffset = offset + length; offset += 16; // GUID (!!!) -> this(...) int nProps = BitConverter.ToInt32(bytes, offset); offset += 4; for (int n=0;n endOffset) throw new FormatException("Document deserialization read behind end of buffer"); } public ODBEntity this[ODBEntity propName] { get { if (properties.ContainsKey(propName)) return properties[propName]; return ODBNull.Instance; } set { if (ODBNull.Instance.Equals(value)) { if (properties.ContainsKey(propName)) properties.Remove(propName); } else { properties[propName] = value; } } } public ODBEntity this[string propName] { get => this[new ODBStringValue(propName)]; set => this[new ODBStringValue(propName)] = value; } public IEnumerable Keys => properties.Keys; public bool Contains(string propName) => Contains(new ODBStringValue(propName)); public bool Contains(ODBEntity propName) { return !ODBNull.Instance.Equals(this[propName]); } public override ODBEntity Clone() { Document clone = new Document(ID); clone.StorageTimeStamp = StorageTimeStamp; foreach (ODBEntity fieldName in properties.Keys) { clone[fieldName] = this[fieldName].Clone(); } return clone; } public void CloneTo(Document target) { target.properties.Clear(); target.StorageTimeStamp = StorageTimeStamp; foreach (ODBEntity fieldName in properties.Keys) { target[fieldName] = this[fieldName].Clone(); } } public override byte[] GetStorageBytes() { MemoryStream stream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(stream); writer.Write(ID.ToByteArray()); writer.Write(properties.Count); foreach (ODBEntity propName in properties.Keys) { ODBEntity propValue = properties[propName]; propName.Write(writer); propValue.Write(writer); } return stream.ToArray(); } public override string ToString() { return String.Format("[Document ID={0} {1}]", ID.ToString(),String.Join(" ",properties.Select(kv=> String.Format("{0}={1}",kv.Key,kv.Value)))); } public override string ToTreeString(int indent) { indent += 2; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendFormat("{0} Identity={1} Count={2}", GetType().Name, Identity, properties.Count); foreach (ODBValue key in properties.Keys) { stringBuilder.AppendLine(); stringBuilder.AppendFormat("{0}{1,-32}: {2}", new String(' ', indent), key, properties[key].ToTreeString(indent)); } return stringBuilder.ToString(); } public override int GetHashCode() { return ID.GetHashCode(); } public override bool Equals(object obj) { if (Equals(GetType(), obj.GetType()) && (obj is Document)) { Document you = obj as Document; return ID.Equals(you.ID); } return false; } protected override int compare(ODBEntity e) { Document other = e as Document; ODBEntity[] keys = Keys.Union(other.Keys).ToArray(); foreach (ODBEntity key in keys) { ODBEntity mine = this[key]; ODBEntity yours = other[key]; int c = mine.CompareTo(yours); if (c != 0) return c; } return 0; } public override T As() => (T)Mapper.Default.UnmapValue(typeof(T), this); static Document() { RegisterDeserializer(0x1001, (b,o,l) => new Document(b,o,l)); } } }