module Uberkit
  module Menu
    def ubermenu(options = {}, &block)
      nav = NavigationMenu.new(self,options)
      yield nav
      concat(nav.to_html) if nav.actions.any?
    end

    class NavigationMenu < Uberkit::Displayer
      def initialize(template,options = {})
        super(template)
        @actions = []
        @subnavs = []
        @id = options.delete(:id)
        @class_name = options.delete(:class)
      end

      def action_wrapper(contents, options = {}, url_for_options = {})
        classes = Array.new        
        classes << "first" if @actions.first == [contents, options, url_for_options]
        classes << "last" if @actions.last == [contents, options, url_for_options]
        classes << "current" if merits_current?(contents,options,url_for_options)
        classes << "disabled" if options.delete(:disabled)    
        classes << classes.join("_") if classes.size > 1
        classes << options[:html].delete(:class) if options[:html] && options[:html][:class]
        content_tag(:li, contents, (options[:html] || {}).merge(:class => classes.join(" ")))
      end

      def merits_current?(contents,options={},url_for_options={})
        if options[:force_current]
          return true if options.delete(:current) == true && !options[:disabled]
        else
          return true if (options.delete(:current) == true || (!url_for_options.is_a?(Symbol) && (@template.current_page?(url_for_options)) && url_for_options != {}) and !options[:disabled])
        end
         false
      end

      def action(name, options = {}, html_options = {})
        wrapper_options = { 
          :current => html_options.delete(:current), 
          :disabled => html_options.delete(:disabled), 
          :force_current => html_options.delete(:force_current), 
          :url => options,
          :html => html_options.delete(:html)
        }
        @actions << [@template.link_to(name,options,html_options), wrapper_options, options]
      end

      def actions
        @actions
      end

      def remote_action(name, options = {}, html_options = {})
        wrapper_options = { :current => options.delete(:current), :disabled => options.delete(:disabled), :force_current => options.delete(:force_current), :url => options[:url] }
        @actions << [@template.link_to_remote(name,options,html_options), wrapper_options, options[:url]]
      end

      def custom_action(options = {}, &block)
        options[:force_current] = true
        @actions << [capture(&block), options, {}]
      end

      def submenu(name, options = {}, html_options = {}, &block)
        subnav = NavigationMenu.new(@template,html_options)
        @subnavs << subnav
        yield subnav

        if subnav.actions.any?
          if options == :delegate
            @actions << [@template.link_to(name, subnav.actions.first[1][:url]) + subnav.to_html, {:current => subnav.any_current?, :url => subnav.actions.first[1][:url]}, {:class => 'submenu'}]
          else
            @actions << [@template.link_to(name,options,html_options) + subnav.to_html, {:current => subnav.any_current?, :url => options}, {:class => 'submenu'}.merge(options)] if subnav.actions.any?
          end
        end
      end

      def any_current?
        @actions.select{|a| merits_current?(*a)}.any?
      end

      def build
        content_tag :ul, @actions.collect{|a| action_wrapper(*a)}.join("\n"),
                    :id => @id,
                    :class => @class_name
      end
      alias :to_html :build
    end
  end
end