internal D.DifferenceNode _CompareObject(object left, object right)
        {
            Func <bool, D.DifferenceNode> state = (b) => {
                return(b ? null : new D.DifferenceNode(null, left, right));
            };

            if (left == null || right == null)
            {
                return(state(left == right));
            }
            if (!left.GetType().Equals(right.GetType()))
            {
                return(state(false));
            }

            if (left is byte)
            {
                return(state(((int)(byte)left - (int)(byte)right) == 0));
            }
            if (left is int)
            {
                return(state(((int)left - (int)right) == 0));
            }
            if (left is long)
            {
                return(state(((long)left - (long)right) == 0));
            }
            if (left is float)
            {
                return(state(((float)left - (float)right).IsNearZero(1e-5f)));
            }
            //if (left is double)
            //	return state(((double)left - (double)right).IsNearZero(1e-5));
            if (left is string)
            {
                return(state(((string)left).CompareTo((string)right) == 0));
            }

            if (left is F.str)
            {
                string left_str  = (left  as F.str).ToString();
                string right_str = (right as F.str).ToString();
                return(state(left_str.CompareTo(right_str) == 0));
            }

            if (left is P.Properties)
            {
                D.DifferenceNode node = new D.DifferenceNode(null, left, right);
                D.DifferenceNode sub;

                Func <P.Properties, P.Properties> clone = (src) => {
                    P.Properties dst = new P.Properties();
                    foreach (P.Property prop in src)
                    {
                        dst.Add(prop);
                    }
                    return(dst);
                };
                P.Properties left_coll  = clone(left as P.Properties);
                P.Properties right_coll = clone(right as P.Properties);

                for (int index = 0; index < left_coll.Count; ++index)
                {
                    P.Property left_sub  = left_coll[index];
                    P.Property right_sub = _FindMatch(left_sub, right_coll);
                    if (right_sub != null)
                    {
                        right_coll.Remove(right_sub);
                    }

                    sub = _Compare(left_sub, right_sub);
                    if (sub != null)
                    {
                        string title = left_sub.PrettyName();
                        if (string.IsNullOrEmpty(title))
                        {
                            title = index.ToString();
                        }
                        sub.Title = title;
                        node.Add(sub);
                    }
                }
                for (int index = 0; index < right_coll.Count; ++index)
                {
                    P.Property right_sub = right_coll[index];
                    if (right_sub != null)
                    {
                        string name = right_sub.GetName();
                        if (_blacklisted.Contains(name))
                        {
                            continue;
                        }

                        string title = right_sub.PrettyName();
                        if (string.IsNullOrEmpty(title))
                        {
                            title = index.ToString();
                        }
                        node.Add(title, null, right_sub);
                    }
                }

                return(node.ChildCount > 0 ? node : null);
            }

            if (left is IDictionary)
            {
                D.DifferenceNode node = new D.DifferenceNode(null, left, right);
                D.DifferenceNode sub;

                Func <IDictionary, IDictionary> clone = (src) => {
                    Dictionary <object, object> dst = new Dictionary <object, object>();
                    foreach (object key in src.Keys)
                    {
                        dst.Add(key, src[key]);
                    }
                    return(dst);
                };
                IDictionary left_coll  = clone(left as IDictionary);
                IDictionary right_coll = clone(right as IDictionary);

                foreach (object key in left_coll.Keys)
                {
                    object left_sub  = left_coll[key];
                    object right_sub = null;
                    if (right_coll.Contains(key))
                    {
                        right_sub = right_coll[key];
                        right_coll.Remove(key);
                    }

                    if (right_sub == null && left_sub != null)
                    {
                        sub = new D.DifferenceNode(null, left_sub, null);
                    }
                    else if (left_sub is P.Property)
                    {
                        sub = _Compare(left_sub as P.Property, right_sub as P.Property);
                    }
                    else
                    {
                        sub = _CompareObject(left_sub, right_sub);
                    }
                    if (sub != null)
                    {
                        sub.Title = key.ToString();
                        node.Add(sub);
                    }
                }
                foreach (object key in right_coll)
                {
                    node.Add(key.ToString(), null, right_coll[key]);
                }

                return(node.ChildCount > 0 ? node : null);
            }

            if (left is ICollection)
            {
                D.DifferenceNode node = new D.DifferenceNode(null, left, right);
                D.DifferenceNode sub;

                Func <ICollection, List <object> > clone = (src) => {
                    List <object> dst = new List <object>();
                    foreach (object val in src)
                    {
                        dst.Add(val);
                    }
                    return(dst);
                };
                List <object> left_coll  = clone(left as ICollection);
                List <object> right_coll = clone(right as ICollection);

                for (int index = 0; index < left_coll.Count; ++index)
                {
                    object left_sub  = left_coll[index];
                    object right_sub = null;
                    if (index < right_coll.Count)
                    {
                        right_sub         = right_coll[index];
                        right_coll[index] = null;
                    }

                    if (right_sub == null && left_sub != null)
                    {
                        sub = new D.DifferenceNode(null, left_sub, null);
                    }
                    else if (left_sub is P.Property)
                    {
                        sub = _Compare(left_sub as P.Property, right_sub as P.Property);
                    }
                    else
                    {
                        sub = _CompareObject(left_sub, right_sub);
                    }
                    if (sub != null)
                    {
                        string title = left_sub.PrettyName();
                        if (string.IsNullOrEmpty(title))
                        {
                            title = index.ToString();
                        }
                        sub.Title = title;
                        node.Add(sub);
                    }
                }
                for (int index = 0; index < right_coll.Count; ++index)
                {
                    object right_sub = right_coll[index];
                    if (right_sub != null)
                    {
                        string title = right_sub.PrettyName();
                        if (string.IsNullOrEmpty(title))
                        {
                            title = index.ToString();
                        }
                        node.Add(title, null, right_sub);
                    }
                }

                return(node.ChildCount > 0 ? node : null);
            }

            return(null);
        }
        internal bool _CompareAll()
        {
            int total = _left_save.TotalElements + _right_save.TotalElements;

            Log.Info("Comparing a ~{0} elements ...", total);
            _cbStart(total, Translate._("Action.Compare.Progress"), "");

            D.DifferenceNode        node;
            D.DifferenceNode        sub;
            List <D.DifferenceNode> nodes = new List <D.DifferenceNode>();
            int differences = 0;

            Func <P.Properties, P.Properties> clone = (src) => {
                P.Properties dst = new P.Properties();
                foreach (P.Property prop in src)
                {
                    dst.Add(prop);
                }
                return(dst);
            };


            node = _Compare(_left_save.Header, _right_save.Header);
            if (node != null)
            {
                node.Title = "Header";
                _differences.Add(node);
                ++differences;
            }


            P.Properties left_objects  = clone(_left_save.Objects);
            P.Properties right_objects = clone(_right_save.Objects);
            while (left_objects.Count > 0)
            {
                P.Property left = left_objects[0];
                left_objects.RemoveAt(0);

                _cbUpdate(null, left.ToString());

                P.Property right = _FindMatchByPath(left, right_objects);
                if (right == null)
                {
                    sub = new D.DifferenceNode(left.ToString(), left, null);
                }
                else
                {
                    right_objects.Remove(right);
                    sub = _Compare(left, right);
                }
                if (sub != null)
                {
                    sub.Title = left.ToString();
                    nodes.Add(sub);
                }
            }
            foreach (P.Property right in right_objects)
            {
                nodes.Add(new D.DifferenceNode(right.ToString(), null, right));
            }
            if (nodes.Count > 0)
            {
                differences += nodes.Count;
                foreach (D.DifferenceNode child in nodes)
                {
                    AddDifference(child);
                }
                nodes.Clear();
            }


            P.Properties left_coll  = clone(_left_save.Collected);
            P.Properties right_coll = clone(_right_save.Collected);
            while (left_coll.Count > 0)
            {
                P.Property left = left_coll[0];
                left_coll.RemoveAt(0);

                _cbUpdate(null, left.ToString());

                P.Property right = _FindMatchByPath(left, right_coll);
                if (right == null)
                {
                    sub = new D.DifferenceNode(left.ToString(), left, null);
                }
                else
                {
                    right_coll.Remove(right);
                    sub = _Compare(left, right);
                }
                if (sub != null)
                {
                    sub.Title = left.ToString();
                    nodes.Add(sub);
                }
            }
            foreach (P.Property right in right_coll)
            {
                nodes.Add(new D.DifferenceNode(right.ToString(), null, right));
            }
            if (nodes.Count > 0)
            {
                differences += nodes.Count;
                foreach (D.DifferenceNode child in nodes)
                {
                    AddDifference(child);
                }
            }


            //if (_left_save.Missing != null && _left_save.Missing.Length > 0)
            //{
            //	//...
            //}


            _cbStop(Translate._("Action.Done"), "");
            Log.Info("... done comparing, differences={0}", differences);

            return(differences == 0);
        }