module BTech
	module Rest
	  module Actions
	    # Default index action.  Feel free to override.
	    def index
	      build_resources
	      if @resources.size > 1
	        # Records for a nested resource (act on the second-to-last parent).
	        parent = @resources[@resources.size - 2][:record]
	        @records = parent.instance_eval("#{@resources.last[:parent_resource_method] || @resources.last[:name]}").paginate :page => params[:page], :per_page => 10
	      else
	        # Records for single resource.
	        @records = @resources.last[:model].paginate :page => params[:page], :per_page => 10
	      end
	    end

	    # Default show action.  Feel free to override.
	    def show
	      build_resources
	      render :partial => @resources.last[:show_partial], :layout => true, :locals => {:record => @record, :resources => @resources}
	    end

	    # Default new action.  Feel free to override.
	    def new
	      build_resources
	      render_new_or_edit
	    end

	    # Default edit action.  Feel free to override.
	    def edit
	      build_resources
	      render_new_or_edit
	    end

	    # Default create action.  Feel free to override.
	    def create
	      build_resources
	      if @record.update_attributes params[:record]
	        redirect_to build_resource_url(@resources)
	      else
	        render_new_or_edit
	      end
	    end

	    # Default update action.  Feel free to override.
	    def update
	      build_resources
	      if @record.update_attributes params[:record]
	        redirect_to build_resource_url(@resources)
	      else
	        render_new_or_edit
	      end  
	    end

	    # Default destroy action.  Feel free to override.
	    def destroy
	      build_resources
	      @record.destroy
	      @resources.last.delete :record
	      redirect_to build_resource_url(@resources)
	    end

	    protected

	    # Convenience method for rendering the new or edit partial.
	    def render_new_or_edit
	      render :partial => @resources.last[:new_or_edit_partial], :layout => true, :locals => {:record => @record, :resources => @resources}
	    end

	    # Builds the RESTful parent URL based on an array of resources.
	    def build_parent_url resources = []
				namespaces = resources.last[:namespaces]
        url = namespaces && !namespaces.empty? ? '/' + resources.last[:namespaces].join('/') : nil
	      if resources.size > 1
	        resources.slice(0...resources.size - 1).each do |resource|
	          url = [url, resource[:name], resource[:parent_id]].join('/')
	        end
	      end
	      url
	    end    

	    # A convenience method for builing RESTful URLs based on an array of resources with the
	    # option to override the default action.  This is also defined as a helper method (see base.rb).
	    def build_resource_url resources = [], action = :index
	      name = resources.last[:name]
	      id = resources.last[:record].id if resources.last[:record]
        parent_url = build_parent_url(resources)
	      url = parent_url ? [parent_url, name].join('/') : '/' + name
	      case action
	        when :show then url = [url, id].compact.join('/')
	        when :new then url = [url, "new"].compact.join('/')
	        when :edit then url = [url, id, "edit"].compact.join('/')
	        when :update then url = [url, id].compact.join('/') if name == name.pluralize
	        when :destroy then url = [url, id].compact.join('/') if name == name.pluralize
	      end
	      logger.debug "Resource URL: #{url}"
	      url
	    end    

	    private

	    # Builds all resources for the controller(s).
	    def build_resources
	      @resources ||= []
	      if @resources.empty?
	        controller_name = self.class.name
	        add_resource controller_name, @resources
	        @resources.reverse!
	      end
	      # Convenience for holding the current record and for form manipulation.
	      @record = @resources.last[:record]
	    end 

			# Convenience method for answering back a properly camelized controller name.
			def camelize_controller_name name
				name = name.capitalize.gsub "controller", "Controller"
				name += "Controller" unless name.include? "Controller"
				name
			end

	    # Answers the child or parent controller namespaces (array) and name (string).
			# Accepts the following argruments:
			# * *full_name* - The fully namespaced controller (i.e. PostsController) or parent name (i.e. protected_pages).
			# Usage:
			# * Input:  Public::PostsController, Output: [Public], "PostsController"
			# * Input:  member_manage_posts, Output: [Member, Manage], "PostsController"
			# * Input:  posts, Output: nil, "PostsController"
			def get_controller_namespaces_and_name full_name
				if full_name
					delimiter = full_name.include?("Controller") ? "::" : '_'
					if full_name.include? delimiter
				    namespaces = full_name.split delimiter
						name = camelize_controller_name namespaces.pop
						return namespaces.collect(&:capitalize), name
					else
						return nil, camelize_controller_name(full_name)
					end
				end
			end			

	    # Recursively walks the controller belongs_to hierarchy (if any) adding new resources along the way.
	    def add_resource controller_name, resources
	      logger.debug "Adding resource '#{controller_name}' to resources (size = #{resources.size})."
	      resource = configure_resource controller_name
	      if resource
	        resources << resource
	        # Recursively add parents (if any).
	        if resource[:controller].methods.include? "parent_resource"
	          add_resource resource[:controller].parent_resource, resources
	        end
	      end
	    end

	    # Configures a resource via belongs_to name refrence in controller.  By default the controller and model
	    # are assumed to use the same root name regardless of singular or plural context. 
	    def configure_resource controller_name
				namespaces, name = get_controller_namespaces_and_name controller_name
	      controller = [namespaces, name].compact.join("::").constantize
        name = name.chomp("Controller").underscore
	      parent_key = name.singularize + "_id"
	      resource = controller.resource_options || {}
	      resource.reverse_merge! :parent_key => parent_key,
	      :parent_id => params[parent_key],
	      :name => name,
	      :controller => controller,
	      :label => name.capitalize,
	      :namespaces => (namespaces.collect(&:downcase) if namespaces),
	      :show_partial => '/' + [namespaces, name, "show"].compact.join('/').downcase,
	      :new_or_edit_partial => '/' + [namespaces, name, "new_or_edit"].compact.join('/').downcase
	      begin
	        resource.reverse_merge! :model => name.singularize.camelize.constantize
	      rescue NameError
	        logger.warn "Unable to constantize: " + name
	      end
	      add_record resource
	    end

	    # Adds the current record to the resource based on position in chain.
	    def add_record resource
	      if resource[:model]
	        if params.include? resource[:parent_key]
	          # Nested parent.
	          resource[:record] = resource[:model].find resource[:parent_id] if resource[:parent_id]
	        else
	          # Single resource and/or end of nested chain.
	          resource[:record] = params[:id] ? resource[:model].find(params[:id]) : resource[:model].new
	        end
	      else
	        logger.error "Invalid model.  Check that your controller and model are of the same name, otherwise specify the model as a resource option."
	      end
	      resource
	    end
	  end
	end	
end