/// <summary>
        /// Determines object type and calls the appropriate conversion call.
        /// </summary>
        /// <param name="o">Object to convert.</param>
        /// <param name="getEncoded">If set to true, will return a base64 encoded value of more complex objects (ie, breps).</param>
        /// <returns></returns>
        private static SpeckleObject fromGhRhObject(object o, bool getEncoded = false, bool getAbstract = true)
        {
            GH_Interval int1d = o as GH_Interval;

            if (int1d != null)
            {
                return(GhRhConveter.fromInterval(int1d.Value));
            }
            if (o is Interval)
            {
                return(GhRhConveter.fromInterval((Interval)o));
            }

            GH_Interval2D int2d = o as GH_Interval2D;

            if (int2d != null)
            {
                return(GhRhConveter.fromInterval2d(int2d.Value));
            }
            if (o is UVInterval)
            {
                return(GhRhConveter.fromInterval2d((UVInterval)o));
            }

            // basic stuff
            GH_Number num = o as GH_Number;

            if (num != null)
            {
                return(SpeckleConverter.fromNumber(num.Value));
            }
            if (o is double || o is int)
            {
                return(SpeckleConverter.fromNumber((double)o));
            }

            GH_Boolean bul = o as GH_Boolean;

            if (bul != null)
            {
                return(SpeckleConverter.fromBoolean(bul.Value));
            }
            if (o is Boolean)
            {
                return(GhRhConveter.fromBoolean((bool)o));
            }

            GH_String str = o as GH_String;

            if (str != null)
            {
                return(SpeckleConverter.fromString(str.Value));
            }
            if (o is string)
            {
                return(SpeckleConverter.fromString((string)o));
            }

            // simple geometry
            GH_Point point = o as GH_Point;

            if (point != null)
            {
                return(GhRhConveter.fromPoint(point.Value));
            }
            if (o is Point3d)
            {
                return(GhRhConveter.fromPoint((Point3d)o));
            }
            // added because when we assign user data to points they get converted to points.
            // the above comment does makes sense. check the sdk.
            if (o is Rhino.Geometry.Point)
            {
                return(GhRhConveter.fromPoint(((Rhino.Geometry.Point)o).Location));
            }

            GH_Vector vector = o as GH_Vector;

            if (vector != null)
            {
                return(GhRhConveter.fromVector(vector.Value));
            }
            if (o is Vector3d)
            {
                return(GhRhConveter.fromVector((Vector3d)o));
            }

            GH_Plane plane = o as GH_Plane;

            if (plane != null)
            {
                return(GhRhConveter.fromPlane(plane.Value));
            }
            if (o is Plane)
            {
                return(GhRhConveter.fromPlane((Plane)o));
            }

            GH_Line line = o as GH_Line;

            if (line != null)
            {
                return(GhRhConveter.fromLine(line.Value));
            }
            if (o is Line)
            {
                return(GhRhConveter.fromLine((Line)o));
            }

            GH_Arc arc = o as GH_Arc;

            if (arc != null)
            {
                return(GhRhConveter.fromArc(arc.Value));
            }
            if (o is Arc)
            {
                return(GhRhConveter.fromArc((Arc)o));
            }

            GH_Circle circle = o as GH_Circle;

            if (circle != null)
            {
                return(GhRhConveter.fromCircle(circle.Value));
            }
            if (o is Circle)
            {
                return(GhRhConveter.fromCircle((Circle)o));
            }

            GH_Rectangle rectangle = o as GH_Rectangle;

            if (rectangle != null)
            {
                return(GhRhConveter.fromRectangle(rectangle.Value));
            }
            if (o is Rectangle3d)
            {
                return(GhRhConveter.fromRectangle((Rectangle3d)o));
            }

            GH_Box box = o as GH_Box;

            if (box != null)
            {
                return(GhRhConveter.fromBox(box.Value));
            }
            if (o is Box)
            {
                return(GhRhConveter.fromBox((Box)o));
            }

            // getting complex
            GH_Curve curve = o as GH_Curve;

            if (curve != null)
            {
                Polyline poly;
                if (curve.Value.TryGetPolyline(out poly))
                {
                    return(GhRhConveter.fromPolyline(poly));
                }
                return(GhRhConveter.fromCurve(curve.Value, getEncoded, getAbstract));
            }

            if (o is Polyline)
            {
                return(GhRhConveter.fromPolyline((Polyline)o));
            }
            if (o is Curve)
            {
                return(GhRhConveter.fromCurve((Curve)o, getEncoded, getAbstract));
            }

            GH_Surface surface = o as GH_Surface;

            if (surface != null)
            {
                return(GhRhConveter.fromBrep(surface.Value, getEncoded, getAbstract));
            }

            GH_Brep brep = o as GH_Brep;

            if (brep != null)
            {
                return(GhRhConveter.fromBrep(brep.Value, getEncoded, getAbstract));
            }

            if (o is Brep)
            {
                return(GhRhConveter.fromBrep((Brep)o, getEncoded, getAbstract));
            }

            GH_Mesh mesh = o as GH_Mesh;

            if (mesh != null)
            {
                return(GhRhConveter.fromMesh(mesh.Value));
            }
            if (o is Mesh)
            {
                return(GhRhConveter.fromMesh((Mesh)o));
            }

            return(new SpeckleObject()
            {
                hash = "404", value = "Type not supported", type = "404"
            });
        }
        // encodes object
        public override object encodeObject(dynamic obj, dynamic objectProperties = null)
        {
            string type          = (string)obj.type;
            object encodedObject = null;

            switch (type)
            {
            case "Number":
                encodedObject = GhRhConveter.toNumber(obj); break;

            case "Boolean":
                encodedObject = GhRhConveter.toBoolean(obj); break;

            case "String":
                encodedObject = GhRhConveter.toString(obj); break;

            case "Point":
                encodedObject = GhRhConveter.toPoint(obj); break;

            case "Vector":
                encodedObject = GhRhConveter.toVector(obj); break;

            case "Plane":
                encodedObject = GhRhConveter.toPlane(obj); break;

            case "Line":
                encodedObject = GhRhConveter.toLine(obj); break;

            case "Arc":
                encodedObject = GhRhConveter.toArc(obj); break;

            case "Circle":
                encodedObject = GhRhConveter.toCircle(obj); break;

            case "Rectangle":
                encodedObject = GhRhConveter.toRectangle(obj); break;

            case "Box":
                encodedObject = GhRhConveter.toBox(obj); break;

            case "Polyline":
                encodedObject = GhRhConveter.toPolyline(obj); break;

            case "Curve":
                encodedObject = GhRhConveter.toCurve(obj); break;

            case "Brep":
                encodedObject = GhRhConveter.toBrep(obj); break;

            case "Mesh":
                encodedObject = GhRhConveter.toMesh(obj); break;

            // gh types:
            case "Interval":
                encodedObject = GhRhConveter.toInterval(obj); break;

            case "Interval2d":
                encodedObject = GhRhConveter.toInterval2d(obj); break;

            default:
                encodedObject = obj;
                break;
            }
            ;

            if (objectProperties == null)
            {
                return(encodedObject);
            }

            // try and cast
            CommonObject myObj = null;

            // polyline special cases yay
            if (type == "Polyline")
            {
                myObj = ((Polyline)encodedObject).ToNurbsCurve();
            }
            else
            {
                myObj = encodedObject as CommonObject;
            }

            // if still null get outta here
            if (myObj == null)
            {
                return(encodedObject);
            }

            myObj.UserDictionary.Clear();

            var dict = getArchivableDict((ExpandoObject)objectProperties.properties);

            myObj.UserDictionary.ReplaceContentsWith(dict);

            return(myObj);
        }