import sys
from decimal import Decimal

from geojson.base import GeoJSON


class Geometry(GeoJSON):
    """
    Represents an abstract base class for a WGS84 geometry.
    """

    if sys.version_info[0] == 3:
        # Python 3.x has no long type
        __JSON_compliant_types = (float, int, Decimal)
    else:
        __JSON_compliant_types = (float, int, Decimal, long)  # noqa

    def __init__(self, coordinates=None, crs=None, validate=False, **extra):
        """
        Initialises a Geometry object.

        :param coordinates: Coordinates of the Geometry object.
        :type coordinates: tuple
        :param crs: CRS
        :type crs: CRS object
        """

        super(Geometry, self).__init__(**extra)
        self["coordinates"] = coordinates or []
        self.clean_coordinates(self["coordinates"])
        if validate:
            errors = self.errors()
            if errors:
                raise ValueError('{}: {}'.format(errors, coordinates))
        if crs:
            self["crs"] = self.to_instance(crs, strict=True)

    @classmethod
    def clean_coordinates(cls, coords):
        for coord in coords:
            if isinstance(coord, (list, tuple)):
                cls.clean_coordinates(coord)
            elif not isinstance(coord, cls.__JSON_compliant_types):
                raise ValueError("%r is not JSON compliant number" % coord)


class GeometryCollection(GeoJSON):
    """
    Represents an abstract base class for collections of WGS84 geometries.
    """

    def __init__(self, geometries=None, **extra):
        super(GeometryCollection, self).__init__(**extra)
        self["geometries"] = geometries or []

    def errors(self):
        errors = [geom.errors() for geom in self['geometries']]
        return [err for err in errors if err]


# Marker classes.

def check_point(coord):
    if len(coord) not in (2, 3):
        return 'the "coordinates" member must be a single position'


class Point(Geometry):
    def errors(self):
        return check_point(self['coordinates'])


class MultiPoint(Geometry):
    def errors(self):
        return self.check_list_errors(check_point, self['coordinates'])


def check_line_string(coord):
    if len(coord) < 2:
        return ('the "coordinates" member must be an array of '
                'two or more positions')


class LineString(MultiPoint):
    def errors(self):
        return check_line_string(self['coordinates'])


class MultiLineString(Geometry):
    def errors(self):
        return self.check_list_errors(check_line_string, self['coordinates'])


def check_polygon(coord):
    lengths = all(len(elem) >= 4 for elem in coord)
    if lengths is False:
        return 'LinearRing must contain with 4 or more positions'

    isring = all(elem[0] == elem[-1] for elem in coord)
    if isring is False:
        return 'The first and last positions in LinearRing must be equivalent'


class Polygon(Geometry):
    def errors(self):
        return check_polygon(self['coordinates'])


class MultiPolygon(Geometry):
    def errors(self):
        return self.check_list_errors(check_polygon, self['coordinates'])


class Default(object):
    """
    GeoJSON default object.
    """

@@ -72,114 +72,8 @@
 N%0A%0A%0A
-class Geometry(GeoJSON):%0A    %22%22%22%0A    Represents an abstract base class for a WGS84 geometry.%0A    %22%22%22%0A%0A    
 if s
@@ -101,20 +101,16 @@
  3:%0A    
- 
-   
 # Python
@@ -131,25 +131,20 @@
 ng type%0A
-    
     
-_
 _JSON_co
@@ -181,20 +181,16 @@
 ecimal)%0A
-    
 else:%0A  
@@ -191,21 +191,16 @@
 se:%0A    
-   
- _
 _JSON_co
@@ -252,16 +252,119 @@
 # noqa%0A%0A
+%0Aclass Geometry(GeoJSON):%0A    %22%22%22%0A    Represents an abstract base class for a WGS84 geometry.%0A    %22%22%22%0A%0A
     def 
@@ -729,34 +729,8 @@
 %22%5D =
- coordinates or %5B%5D%0A       
  sel
@@ -749,22 +749,16 @@
 dinates(
-self%5B%22
 coordina
@@ -764,12 +764,17 @@
 ates
-%22
+ or %5B
 %5D)%0A
+%0A
     
@@ -1050,24 +1050,124 @@
 s, coords):%0A
+        new_coords = %5B%5D%0A        if isinstance(coords, Point):%0A            new_coords.append(coords)%0A
         for 
@@ -1248,16 +1248,34 @@
         
+new_coords.append(
 cls.clea
@@ -1290,24 +1290,25 @@
 nates(coord)
+)
 %0A           
@@ -1313,19 +1313,117 @@
    elif 
-not
+isinstance(coord, Geometry):%0A                new_coords.append(coord%5B'coordinates'%5D)%0A            elif
  isinsta
@@ -1437,13 +1437,8 @@
 rd, 
-cls._
 _JSO
@@ -1453,24 +1453,83 @@
 ant_types):%0A
+                new_coords.append(coord)%0A            else:%0A
             
@@ -1560,16 +1560,18 @@
  is not 
+a 
 JSON com
@@ -1594,16 +1594,42 @@
  coord)%0A
+        return new_coords%0A
 %0A%0Aclass 
@@ -2092,101 +2092,315 @@
  if 
-len(coord) not in (2, 3):%0A        return 'the %22coordinates%22 member must be a single position'
+not isinstance(coord, list):%0A        return 'each position must be a list'%0A    if len(coord) not in (2, 3):%0A        return 'a position must have exactly 2 or 3 values'%0A    for num in coord:%0A        if not isinstance(num, _JSON_compliant_types):%0A            return %22each value in a position must be a number%22
 %0A%0A%0Ac
@@ -2643,24 +2643,115 @@
 ing(coord):%0A
+    if not isinstance(coord, list):%0A        return 'each line must be a list of positions'%0A
     if len(c
@@ -2866,16 +2866,114 @@
 tions')%0A
+    for pos in coord:%0A        error = check_point(pos)%0A        if error:%0A            return error%0A
 %0A%0Aclass 

Allow constructing one object from another