module Mouth

  # Simple base class to serve as an ORM for the mongo driver, without importing a large ORM like mongomapper.
  class Record
    
    # Keys are symbols
    # id is :id, not _id
    attr_accessor :attributes
    
    def initialize(attrs = {})
      self.attributes = normalize_attributes(attrs)
    end
    
    def all_attributes
      self.attributes
    end
    
    def save
      if self.attributes[:id]
        attrs = self.attributes.dup
        the_id = attrs.delete(:id).to_s
        doc = self.class.collection.update({"_id" => BSON::ObjectId(the_id)}, attrs)
      else
        self.class.collection.insert(self.attributes)
        self.attributes[:id] = self.attributes.delete(:_id).to_s
      end
      true
    end
    
    def update(new_attrs)
      self.attributes = normalize_attributes(new_attrs)
      self.save
    end
    
    def destroy
      self.class.collection.remove({"_id" => BSON::ObjectId(self.attributes[:id])})
    end
    
    def normalize_attributes(attrs)
      normalize = lambda do |h|
        hd = {}
        h.each_pair do |key, val|
          val = normalize.call(val) if val.is_a?(Hash)
          val = val.to_s if val.is_a?(BSON::ObjectId)
          # TODO: arrays :(
          hd[key.to_s == "_id" ? :id : key.to_sym] = val
        end
        hd
      end
      normalize.call attrs
    end
    
    def self.collection
      demodularized = self.to_s.match(/(.+::)?(.+)$/)[2] || "record"
      tableized = demodularized.downcase + "s" # (: lol :)
      @collection ||= Mouth.mongo.collection(tableized)
    end
    
    def self.find(id)
      collection.find({"_id" => BSON::ObjectId(id)}).to_a.collect {|d| new(d) }.first
    end
    
    def self.create(attributes)
      r = new(attributes)
      r.save
      r
    end
    
    def self.all
      collection.find.to_a.collect {|d| new(d) }
    end
  end
end
