using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace Superlazy { public abstract class SLEntity : IEnumerable, IComparable { public abstract bool IsNumeric { get; } public abstract bool IsValue { get; } public abstract string ID { get; } public abstract bool IsModified(string child); public abstract void EndModified(); public abstract bool HasChild(string attributeKey); internal abstract object GetObj(); internal abstract int GetInt(); internal abstract double GetDouble(); internal abstract string GetString(); internal abstract bool IsExist(); protected abstract int GetEntityHashCode(); internal static IEnumerable emptyEnumerable = Enumerable.Empty(); public abstract IEnumerator GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public SLEntity this[SLEntity attributeKey] { get { if (attributeKey.IsNullOrFalse()) { SLLog.Warn($"attributeKey shouldn't null obj {ToString()}, {ID}"); #if SERVER && LOCALTEST throw new Exception(); #endif return Empty; } return this[attributeKey.ToString()]; } set { if (attributeKey.IsNullOrFalse()) { SLLog.Warn($"attributeKey shouldn't null obj {ToString()}, {ID}"); #if SERVER && LOCALTEST throw new Exception(); #endif return; } this[attributeKey.ToString()] = value; } } public abstract SLEntity this[string attributeKey] { get; set; } public abstract SLEntity Clone(); public abstract SLEntity Link(); public abstract SLEntity Override(); public static SLEntity Empty => new SLContainer(null, null, null); public static implicit operator double(SLEntity v) { return v.GetDouble(); } public static implicit operator float(SLEntity v) { return (float)v.GetDouble(); } public static implicit operator int(SLEntity v) { return v.GetInt(); } public static implicit operator string(SLEntity v) { return v.GetString(); } public static implicit operator bool(SLEntity v) { return v != default(SLEntity) && v.IsExist(); } //public static implicit operator Vector2(SLEntity v) //{ // return new Vector2(v["X"], v["Y"]); //} public static bool operator <(SLEntity lhs, SLEntity rhs) { if (lhs == null && rhs == null) { return 0 < 0; } else if (lhs.IsNullOrFalse()) { return 0 < rhs.GetDouble(); } else if (rhs.IsNullOrFalse()) { return lhs.GetDouble() < 0; } else { return lhs.GetDouble() < rhs.GetDouble(); } } public static bool operator >(SLEntity lhs, SLEntity rhs) { if (lhs == null && rhs == null) { return 0 > 0; } else if (lhs.IsNullOrFalse()) { return 0 > rhs.GetDouble(); } else if (rhs.IsNullOrFalse()) { return lhs.GetDouble() > 0; } return lhs.GetDouble() > rhs.GetDouble(); } public static bool operator <=(SLEntity lhs, SLEntity rhs) { if (lhs == null && rhs == null) { return 0 <= 0; } else if (lhs.IsNullOrFalse()) { return 0 <= rhs.GetDouble(); } else if (rhs.IsNullOrFalse()) { return lhs.GetDouble() <= 0; } else { return lhs.GetDouble() <= rhs.GetDouble(); } } public static bool operator >=(SLEntity lhs, SLEntity rhs) { if (lhs == null && rhs == null) { return 0 >= 0; } else if (lhs.IsNullOrFalse()) { return 0 >= rhs.GetDouble(); } else if (rhs.IsNullOrFalse()) { return lhs.GetDouble() >= 0; } else { return lhs.GetDouble() >= rhs.GetDouble(); } } public static SLEntity operator +(SLEntity single) { return single; } public static SLEntity operator -(SLEntity single) { if (single.IsNullOrFalse()) { return 0; } return -single.GetDouble(); } public static SLEntity operator +(SLEntity lhs, SLEntity rhs) { if (lhs.IsNullOrFalse()) { return rhs; } if (rhs.IsNullOrFalse()) { return lhs; } if (lhs.IsNumeric && rhs.IsNumeric) return lhs.GetDouble() + rhs.GetDouble(); return lhs.ToString() + rhs.ToString(); } public static double operator +(double lhs, SLEntity rhs) { if (rhs.IsNullOrFalse()) { return lhs; } if (rhs.IsNumeric) return lhs + rhs.GetDouble(); return lhs; } public static double operator +(SLEntity lhs, double rhs) { if (lhs.IsNullOrFalse()) { return rhs; } if (lhs.IsNumeric) return lhs.GetDouble() + rhs; return rhs; } public static float operator +(float lhs, SLEntity rhs) { if (rhs.IsNullOrFalse()) { return lhs; } if (rhs.IsNumeric) return lhs + (float)rhs.GetDouble(); return lhs; } public static float operator +(SLEntity lhs, float rhs) { if (lhs.IsNullOrFalse()) { return rhs; } if (lhs.IsNumeric) return (float)lhs.GetDouble() + rhs; return rhs; } public static int operator +(SLEntity lhs, int rhs) { if (lhs.IsNullOrFalse()) { return rhs; } if (lhs.IsNumeric) return lhs.GetInt() + rhs; return rhs; } public static int operator +(int lhs, SLEntity rhs) { if (rhs.IsNullOrFalse()) { return lhs; } if (rhs.IsNumeric) return lhs + rhs.GetInt(); return lhs; } public static SLEntity operator -(SLEntity lhs, SLEntity rhs) { if (lhs.IsNullOrFalse()) { if (rhs == default(SLEntity)) return 0; return -rhs.GetDouble(); } if (rhs.IsNullOrFalse()) { return lhs; } return lhs.GetDouble() - rhs.GetDouble(); } public static double operator -(double lhs, SLEntity rhs) { if (rhs.IsNullOrFalse()) { return lhs; } if (rhs.IsNumeric) return lhs - rhs.GetDouble(); return lhs; } public static double operator -(SLEntity lhs, double rhs) { if (lhs.IsNullOrFalse()) { return -rhs; } if (lhs.IsNumeric) return lhs.GetDouble() - rhs; return -rhs; } public static float operator -(float lhs, SLEntity rhs) { if (rhs.IsNullOrFalse()) { return lhs; } if (rhs.IsNumeric) return lhs - (float)rhs.GetDouble(); return lhs; } public static float operator -(SLEntity lhs, float rhs) { if (lhs.IsNullOrFalse()) { return -rhs; } if (lhs.IsNumeric) return (float)lhs.GetDouble() - rhs; return -rhs; } public static int operator -(SLEntity lhs, int rhs) { if (lhs.IsNullOrFalse()) { return -rhs; } if (lhs.IsNumeric) return lhs.GetInt() - rhs; return rhs; } public static int operator -(int lhs, SLEntity rhs) { if (rhs.IsNullOrFalse()) { return lhs; } if (rhs.IsNumeric) return lhs - rhs.GetInt(); return lhs; } public static SLEntity operator *(SLEntity lhs, SLEntity rhs) { if (lhs.IsNullOrFalse()) { return 0; } if (rhs.IsNullOrFalse()) { return 0; } if (lhs.IsNumeric && rhs.IsNumeric) return lhs.GetDouble() * rhs.GetDouble(); return 0; } public static double operator *(double lhs, SLEntity rhs) { if (rhs.IsNullOrFalse()) { return 0; } if (rhs.IsNumeric) return lhs * rhs.GetDouble(); return 0; } public static double operator *(SLEntity lhs, double rhs) { if (lhs.IsNullOrFalse()) { return 0; } if (lhs.IsNumeric) return lhs.GetDouble() * rhs; return 0; } public static float operator *(float lhs, SLEntity rhs) { if (rhs.IsNullOrFalse()) { return 0; } if (rhs.IsNumeric) return lhs * (float)rhs.GetDouble(); return 0; } public static float operator *(SLEntity lhs, float rhs) { if (lhs.IsNullOrFalse()) { return 0; } if (lhs.IsNumeric) return (float)lhs.GetDouble() * rhs; return 0; } public static int operator *(SLEntity lhs, int rhs) { if (lhs.IsNullOrFalse()) { return 0; } if (lhs.IsNumeric) return lhs.GetInt() * rhs; return 0; } public static int operator *(int lhs, SLEntity rhs) { if (rhs.IsNullOrFalse()) { return 0; } if (rhs.IsNumeric) return lhs * rhs.GetInt(); return 0; } public static SLEntity operator /(SLEntity lhs, SLEntity rhs) { if (rhs.IsNullOrFalse()) { SLLog.Warn($"Divide by 0 {lhs?.GetDouble() ?? 0} / 0"); if (lhs.IsNullOrFalse()) return 0; else return Math.Sign(lhs.GetDouble()) * double.PositiveInfinity; } if (lhs.IsNullOrFalse()) { return 0; } if (rhs.IsNumeric == false || rhs == 0.0) { SLLog.Warn($"Divide by 0 {lhs.GetDouble()} / 0"); return Math.Sign(lhs.GetDouble()) * double.PositiveInfinity; } return lhs.GetDouble() / rhs.GetDouble(); } public static double operator /(double lhs, SLEntity rhs) { if (rhs.IsNullOrFalse()) { SLLog.Warn($"Divide by 0 {lhs} / 0"); return Math.Sign(lhs) * double.PositiveInfinity; } if (rhs.IsNumeric == false || rhs == 0.0) { SLLog.Warn($"Divide by 0 {lhs} / 0"); return Math.Sign(lhs) * double.PositiveInfinity; } return lhs / rhs.GetDouble(); } public static double operator /(SLEntity lhs, double rhs) { if (lhs.IsNullOrFalse()) { return 0; } if (rhs == 0.0) { SLLog.Warn($"Divide by 0 {lhs.GetDouble()} / 0"); return Math.Sign(lhs.GetDouble()) * double.PositiveInfinity; } return lhs.GetDouble() / rhs; } public static float operator /(float lhs, SLEntity rhs) { if (rhs.IsNullOrFalse()) { SLLog.Warn($"Divide by 0 {lhs} / 0"); return Math.Sign(lhs) * float.PositiveInfinity; } if (rhs.IsNumeric == false || rhs == 0.0) { SLLog.Warn($"Divide by 0 {lhs} / 0"); return Math.Sign(lhs) * float.PositiveInfinity; } return lhs / (float)rhs.GetDouble(); } public static float operator /(SLEntity lhs, float rhs) { if (lhs.IsNullOrFalse()) { return 0; } if (rhs == 0.0) { SLLog.Warn($"Divide by 0 {lhs.GetDouble()} / 0"); return Math.Sign(lhs.GetDouble()) * float.PositiveInfinity; } return (float)lhs.GetDouble() / rhs; } public static int operator /(int lhs, SLEntity rhs) { if (rhs.IsNullOrFalse()) { SLLog.Warn($"Divide by 0 {lhs} / 0"); return lhs > 0 ? int.MaxValue : int.MinValue; } if (rhs.IsNumeric == false || rhs == 0.0) { SLLog.Warn($"Divide by 0 {lhs} / 0"); return lhs > 0 ? int.MaxValue : int.MinValue; } return lhs / rhs.GetInt(); } public static int operator /(SLEntity lhs, int rhs) { if (lhs.IsNullOrFalse()) { return 0; } if (rhs == 0) { SLLog.Warn($"Divide by 0 {lhs.GetInt()} / 0"); return lhs.GetInt() > 0 ? int.MaxValue : int.MinValue; } return lhs.GetInt() / rhs; } public static int operator %(SLEntity lhs, SLEntity rhs) { if (lhs.IsNullOrFalse()) { return 0; } if (rhs.IsNullOrFalse()) { SLLog.Warn($"Divide by 0 {lhs} / 0"); return lhs; } return lhs.GetInt() % rhs.GetInt(); } public static int operator %(SLEntity lhs, int rhs) { if (lhs.IsNullOrFalse()) { return 0; } if (rhs == 0) { SLLog.Warn($"Divide by 0 {lhs} / 0"); return lhs; } return lhs.GetInt() % rhs; } public static int operator %(int lhs, SLEntity rhs) { if (lhs == 0) { return 0; } if (rhs.IsNullOrFalse() || rhs.GetInt() == 0) { SLLog.Warn($"Divide by 0 {lhs} / 0"); return lhs; } return lhs % rhs.GetInt(); } public static bool operator ==(SLEntity lhs, bool rhs) { if (lhs.IsNullOrFalse()) return !rhs; else return lhs.IsExist() == rhs; } public static bool operator !=(SLEntity lhs, bool rhs) { return !(lhs == rhs); } public static bool operator ==(bool lhs, SLEntity rhs) { if (rhs.IsNullOrFalse()) return !lhs; else return rhs.IsExist() == rhs; } public static bool operator !=(bool lhs, SLEntity rhs) { return !(rhs == lhs); } //public static bool operator ==(SLEntity lhs, string rhs) //{ // return (string)lhs == rhs; //} //public static bool operator !=(SLEntity lhs, string rhs) //{ // return !(lhs == rhs); //} //public static bool operator ==(string lhs, SLEntity rhs) //{ // return rhs == lhs; //} //public static bool operator !=(string lhs, SLEntity rhs) //{ // return !(rhs == lhs); //} public static bool operator ==(SLEntity lhs, int rhs) { return lhs.GetInt() == rhs; } public static bool operator !=(SLEntity lhs, int rhs) { return !(lhs == rhs); } public static bool operator ==(int lhs, SLEntity rhs) { return rhs == lhs; } public static bool operator !=(int lhs, SLEntity rhs) { return !(rhs == lhs); } public static bool operator ==(SLEntity lhs, double rhs) { return lhs.GetDouble() == rhs; } public static bool operator !=(SLEntity lhs, double rhs) { return !(lhs == rhs); } public static bool operator ==(double lhs, SLEntity rhs) { return rhs == lhs; } public static bool operator !=(double lhs, SLEntity rhs) { return !(rhs == lhs); } public static bool operator ==(SLEntity lhs, float rhs) { return lhs.GetDouble() == rhs; } public static bool operator !=(SLEntity lhs, float rhs) { return !(lhs == rhs); } public static bool operator ==(float lhs, SLEntity rhs) { return rhs == lhs; } public static bool operator !=(float lhs, SLEntity rhs) { return !(rhs == lhs); } //public static bool operator ==(SLEntity lhs, SLVector2 rhs) //{ // return lhs["X"] == rhs.X && lhs["Y"] == rhs.Y; //} //public static bool operator !=(SLEntity lhs, SLVector2 rhs) //{ // return lhs["X"] != rhs.X || lhs["Y"] != rhs.Y; //} public static bool operator ==(SLEntity lhs, SLEntity rhs) { if (ReferenceEquals(lhs, rhs))// 동일 객체 { return true; } else if (lhs is null || lhs.IsExist() == false) // 빈객체 { return rhs is null || rhs.IsExist() == false; } else if (rhs is null || rhs.IsExist() == false) { return lhs is null || lhs.IsExist() == false; } else if (lhs.IsValue && rhs.IsValue) // 값비교 { if (lhs.IsNumeric == false || rhs.IsNumeric == false) { return lhs.GetString().Equals(rhs.GetString()); } else { return lhs.GetDouble() == rhs.GetDouble(); } } else if (lhs.IsValue == false && rhs.IsValue == false) // 리스트 { var lhsCount = lhs.Count(); var rhsCount = rhs.Count(); if (lhsCount != rhsCount) { return false; } foreach (var l in lhs) { if (rhs.HasChild(l.ID) == false) { return false; } if (l != rhs[l.ID]) { return false; } } return true; } return false; } public static bool operator !=(SLEntity lhs, SLEntity rhs) { return !(lhs == rhs); } public override bool Equals(object obj) { if (obj == null) { return false; } if ((obj is SLEntity) == false) { return obj.Equals(GetObj()); } return (obj as SLEntity) == this; } public override int GetHashCode() { return GetEntityHashCode(); } public static implicit operator SLEntity(string v) { if (v == null || v == string.Empty) return Empty; else return new SLValueString(v); } public static implicit operator SLEntity(int v) { return new SLValueInt(v); } public static implicit operator SLEntity(double v) { return new SLValueDouble(v); } private static SLEntity boolTrue = new SLValueString("True"); //private static SLEntity boolFalse = new SLContainer(null, null, null); public static implicit operator SLEntity(bool v) { if (v) { if (boolTrue.ID != null) boolTrue = new SLValueString("True"); return boolTrue; } else { return new SLContainer(null, null, null); // TODO: 성능상 수정 필요 //if (boolFalse || boolFalse.ID != null) boolFalse = new SLContainer(null, null, null); //boolFalse.test = true; //return boolFalse; } } //public static implicit operator SLEntity(SLVector2 v) //{ // var ret = new SLContainer(null); // ret["X"] = v.X; // ret["Y"] = v.Y; // return ret; //} public override string ToString() { return GetString(); } public int CompareTo(SLEntity other) { if (IsValue == false || other.IsValue == false) { // TODO: 리스트 비교 필요 return GetHashCode().CompareTo(other.GetHashCode()); } if (IsNumeric && other.IsNumeric) { return GetDouble().CompareTo(other.GetDouble()); } var thisSTR = GetString(); var otherSTR = other.GetString(); return thisSTR.CompareTo(otherSTR); } internal abstract SLEntity ToChild(SLContainerBase parent, string id); internal abstract void Move(SLEntity parent, string id); public static bool Changed(SLEntity lhs, SLEntity rhs) { if (lhs is null && rhs is null) return false; if (lhs.IsNullOrFalse()) return rhs; if (rhs.IsNullOrFalse()) return lhs; if (lhs.IsValue && rhs.IsValue) { return lhs != rhs; } return false; } } }