module SpatialAdapter
  module SpatialColumn
    attr_reader  :geometry_type, :srid, :with_z, :with_m

    def initialize(name, default, sql_type = nil, null = true, srid=-1, with_z=false, with_m=false)
      super(name, default, sql_type, null)
      @geometry_type = geometry_simplified_type(@sql_type)
      @srid = srid
      @with_z = with_z
      @with_m = with_m
    end

    def spatial?
      !@geometry_type.nil?
    end

    def geographic?
      false
    end

    # Redefines type_cast to add support for geometries
    # alias_method :type_cast_without_spatial, :type_cast
    def type_cast(value)
      return nil if value.nil?
      spatial? ? self.class.string_to_geometry(value) : super
    end

    #Redefines type_cast_code to add support for geometries.
    #
    #WARNING : Since ActiveRecord keeps only the string values directly returned from the database, it translates from these to the correct types everytime an attribute is read (using the code returned by this method), which is probably ok for simple types, but might be less than efficient for geometries. Also you cannot modify the geometry object returned directly or your change will not be saved.
    # alias_method :type_cast_code_without_spatial, :type_cast_code
    def type_cast_code(var_name)
      spatial? ? "#{self.class.name}.string_to_geometry(#{var_name})" : super
    end


    #Redefines klass to add support for geometries
    # alias_method :klass_without_spatial, :klass
    def klass
      spatial? ? GeoRuby::SimpleFeatures::Geometry : super
    end

    private

    # Maps additional data types to base Rails/Arel types
    #
    # For Rails 3, only the types defined by Arel can be used.  We'll
    # use :string since the database returns the columns as hex strings.
    def simplified_type(field_type)
      case field_type
      when /geography|geometry|point|linestring|polygon|multipoint|multilinestring|multipolygon|geometrycollection/i then :string
      else super
      end
    end

    # less simlpified geometric type to be use in migrations
    def geometry_simplified_type(sql_type)
      case sql_type
      when /^point$/i then :point
      when /^linestring$/i then :line_string
      when /^polygon$/i then :polygon
      when /^geometry$/i then :geometry
      when /multipoint/i then :multi_point
      when /multilinestring/i then :multi_line_string
      when /multipolygon/i then :multi_polygon
      when /geometrycollection/i then :geometry_collection
      end
    end
  end
end