module Restfulie
  module Server
    # Controller which adds default CRUD + search + other operations.
    # TODO: move these actions to controller/base.rb (maybe using InheritedResources, maybe not)
    module Controller
      # creates a model based on the request media-type extracted from its content-type
      def create
        type = model_type
        return head 415 unless fits_content(type, request.headers['CONTENT_TYPE'])

        @model = type.from_xml request.body.string
        if @model.save
          render_created @model
        else
          render :xml => @model.errors, :status => :unprocessable_entity
        end
      end
    
      # renders this resource
      def show
        @model = model_type.find(params[:id])
        instance_variable_set(model_variable_name, @model)
        render_resource(@model)
      end
      
      def model_variable_name
        ("@" + model_type.to_s.downcase).to_sym
      end

      # destroys this resource
      def destroy
        @model = model_type.find(params[:id])
        @model.destroy
        head :ok
      end

      # updates a resouce
      def update
        type = model_type

        @loaded = type.find(params[:id])
        return head(:status => 405) unless @loaded.can? :update

        return head(415) unless fits_content(type, request.headers['CONTENT_TYPE'])

        @model = Hash.from_xml(request.body.string)[model_name]
        pre_update(@model) if self.respond_to?(:pre_update)
        
        if @loaded.update_attributes(@model)
          render_resource @loaded
        else
          render :xml => @loaded.errors, :status => :unprocessable_entity
        end
      end

      # returns the model for this controller
      def model_type
        self.class.name[/(.*)Controller/,1].singularize.constantize
      end
      
      # retrieves the model name
      def model_name
        self.class.name[/(.*)Controller/,1].singularize.underscore
      end
    
      def fits_content(type, content_type)
        Restfulie::MediaType.supports?(content_type) &&
                (type.respond_to?(:media_type_representations) ?
                type.media_type_representations.include?(content_type) :
                Restfulie::MediaType.default_representations.include?(content_type))
      end
    end
  end
end
