module EasyPatch

  module MenuHelperPatch
    def self.included(base)
      base.extend(ClassMethods)
      base.send(:include, InstanceMethods)

      base.class_eval do

        alias_method_chain :extract_node_details, :easy_extensions
        alias_method_chain :render_menu, :easy_extensions
        alias_method_chain :render_single_menu_node, :easy_extensions
        alias_method_chain :render_menu_node_with_children, :easy_extensions


        def render_easy_custom_menu(user)
          menus = user.easy_user_type.easy_custom_menus.group_by(&:root_id)
          root_item = Redmine::MenuManager::MenuNode.new(:root, {})

          init_item = proc do |item|
            Redmine::MenuManager::MenuItem.new("#{item.id}_#{item.name}", item.url, caption: item.name, html: {
                class: item.easy_icon
            })
          end

          Array(menus[nil]).each do |root|
            menu_item = init_item.call(root)

            Array(menus[root.id]).each do |submenu|
              submenu_item = init_item.call(submenu)
              menu_item.add(submenu_item)
            end

            root_item.add(menu_item)
          end

          root_item.children.collect { |node| render_menu_easy_node(node) }.join("\n").html_safe
        end

        def render_dashboard_menu(menu, project = nil)
          menu_items = Array.new
          nil_category_name = 'others'
          menu_items_for(menu).group_by { |item| item.html_options[:menu_category] }.each_pair do |category, items|
            lis = Array.new
            items.each do |item|
              lis << render_dashboard_menu_node(item, project)
            end
            menu_items << content_tag(:fieldset, :class => "dashboard-container #{category}") do
              content_tag(:legend, l(category || nil_category_name, :scope => [:dashboard, :legends], :default => h(category))) +
                content_tag(:ul, lis.join("\n").html_safe, :class => "#{category || nil_category_name} menu-manager")
            end
          end

          return content_tag(:div, menu_items.join.html_safe, :class => 'menu-dashboard', :id => 'menu_' + menu.to_s)
        end

        def render_dashboard_menu_node(node, project = nil)
          caption, url, selected = extract_node_details(node, project)
          return content_tag('li', render_dashboard_menu_node_item(node, caption, url, selected), :class => selected && 'selected' || '')
        end

        def render_dashboard_menu_node_item(item, caption, url, selected)
          link_to(content_tag(:span, content_tag(:i, '', item.html_options), :class => 'dashboard-item-icon') + content_tag(:span, h(caption), :class => 'dashboard-item-label'), url)
        end

        def render_easy_menu(menu, project=nil, options={})
          links = []
          menu_items_for(menu, project) do |node|
            node.project = options[:optional_project]
            links << render_menu_easy_node(node, project)
          end
          if options[:no_container]
            links.join("\n").html_safe
          elsif links.empty?
            nil
          else
            content_tag('ul', links.join("\n").html_safe, :class => "menu-manager menu-#{menu.to_s.dasherize}")
          end
        end

        def render_menu_easy_node(node, project=nil)
          if node.children.present? || !node.child_menus.nil?
            if node.parent.name == :root
              return render_menu_easy_node_with_children(node, project)
            else
              return render_menu_node_with_children(node, project)
            end
          else
            caption, url, selected = extract_node_details(node, project)
            return content_tag('li',
                               render_single_menu_node(node, caption, url, selected))
          end
        end

        def render_menu_easy_node_with_children(node, project=nil)
          caption, url, selected = extract_node_details(node, project)

          html = [].tap do |html|
            html << '<li class="with-easy-submenu">'

            # Parent
            html << render_single_menu_node(node, caption, url, selected)

            html << content_tag(:span, :class => 'easy-top-menu-more-toggler', :data => {:menu_toggle => true}) do
              content_tag(:i, '', :class => 'icon-arrow down')
            end


            # Standard children
            standard_children_list = "".html_safe.tap do |child_html|
              each_node_easy_children(node, project) do |child|
                child_html << render_menu_node(child, project)
              end
            end

            html << content_tag(:ul, standard_children_list, :class => 'menu-children easy-menu-children', :style => 'display:none', :id => "easy_menu_children_#{node.name}") unless standard_children_list.empty?

            # Unattached children
            unattached_children_list = render_unattached_children_menu(node, project)
            html << content_tag(:ul, unattached_children_list, :class => 'menu-children easy-menu-children unattached', :style => 'display:none', :id => "easy_menu_children_#{node.name}") unless unattached_children_list.blank?

            html << '</li>'
          end
          return html.join("\n").html_safe
        end

        def each_node_easy_children(node, project=nil, &block)
          node.children.each do |child|
            next if !allowed_node?(child, User.current, project)
            yield child
          end
        end

        def render_easy_custom_project_menu(project)
          return render_menu(:application_menu, project) if project.nil? || project.new_record?
          return render_menu(:project_menu, project) if !project.easy_has_custom_menu?

          all_project_items = Redmine::MenuManager.items(:project_menu).root.children.select { |node| node.allowed?(User.current, project) }

          links = []

          EasyCustomProjectMenu.for_project(project).sorted.each do |custom_item|
            if custom_item.original_item?
              node = all_project_items.detect { |n| n.name.to_s == custom_item.menu_item.to_s }
              links << render_menu_node(node, project) if node
            else
              links << content_tag('li', link_to(custom_item.name, custom_item.url))
            end
          end

          links.empty? ? nil : content_tag('ul', links.join("\n").html_safe)
        end

        #  issue sidebar more menu links

        def link_to_issue_new_time_entry
          new_issue_time_entry_path(@issue, :back_url => issue_path(@issue))
        end

        def link_to_issue_copy
          { :controller => 'issues', :action => 'new', :project_id => @issue.project, :copy_from => @issue }
        end

        def link_to_issue_copy_as_subtask
          { :controller => 'issues', :action => 'new', :project_id => @issue.project, :copy_from => @issue, :subtask_for_id => @issue.id, :copy_subtasks => false }
        end

        def link_to_issue_move
          { :controller => 'issues', :action => 'bulk_edit', :ids  => [@issue] }
        end

        def link_to_issue_new_subtask
          { :controller => 'issues', :action => 'new', :project_id => @issue.project, :subtask_for_id => @issue }
        end

        def link_to_issue_new_project
          { :controller => 'projects', :action => 'new', :project => { :name => @issue.subject, :description => @issue.description, :due_date => @issue.due_date, :parent_id => @issue.project } }
        end

      end

    end

    module InstanceMethods

      def extract_node_details_with_easy_extensions(node, project=nil)
        project ||= node.project || (node.parent && node.parent.project)
        item = node
        url = case item.url
        when Hash
          additional_url_params = item.param.is_a?(Proc) ? (item.param.call(project) || {}) : {}
          additional_url_params.merge(project.nil? ? item.url : {item.param => project}.merge(item.url))
        when Symbol
          send(item.url)
        else
          item.url
        end
        caption = item.caption(project)
        return [caption, url, (current_menu_item == item.name)]
      end

      def render_menu_with_easy_extensions(menu, project=nil)
        links = []
        menu_items_for(menu, project) do |node|
          links << render_menu_node(node, project)
        end
        links.empty? ? nil : content_tag('ul', links.join.html_safe, :class => "menu-manager menu-#{menu.to_s.dasherize}")
      end

      def render_single_menu_node_with_easy_extensions(item, caption, url, selected)
        if (render_partial_path = item.html_options[:render_partial_path])
          render(partial: render_partial_path, locals: {item: item, caption: caption, url: url, selected: selected})
        else
          render_single_menu_node_without_easy_extensions(item, caption, url, selected)
        end
      end

      def render_menu_node_with_children_with_easy_extensions(node, project=nil)
        caption, url, selected = extract_node_details(node, project)

        html = [].tap do |html|
          html << '<li>'
          # Parent
          html << render_single_menu_node(node, caption, url, selected)

          # Standard children
          standard_children_list = "".html_safe.tap do |child_html|
            each_node_easy_children(node, project) do |child|
              child_html << render_menu_node(child, project) if allowed_node?(child, User.current, project)
            end
          end

          html << content_tag(:ul, standard_children_list, :class => 'menu-children') unless standard_children_list.empty?

          # Unattached children
          unattached_children_list = render_unattached_children_menu(node, project)
          html << content_tag(:ul, unattached_children_list, :class => 'menu-children unattached') unless unattached_children_list.blank?

          html << '</li>'
        end
        return html.join("\n").html_safe
      end

    end

    module ClassMethods

    end

  end

end
EasyExtensions::PatchManager.register_other_patch 'Redmine::MenuManager::MenuHelper', 'EasyPatch::MenuHelperPatch'
