module Lolita
  # Create mapping for routes.
  # Each mapping has name, like :posts, :files etc.
  # Also it accepts options: 
  # * <tt>:singular</tt> - singular form for route, by default it call #singularize on _name_.
  # * <tt>:class_name</tt> - class that is related with route, by default it uses :singular, and classify it. It should be like "Post".
  # * <tt>:path_prefix</tt> - path starts with path prefix, like /path_prefix/lolita/posts.
  # * <tt>:path</tt> - path and path url methods starts with this path.
  # =====Example
  #     lolita_for :posts, :path=>"admin"
  #     # add paths like this to routes
  #     # admin_posts GET /admin/posts {:controller=>"lolita/rest", :action=>:index}
  #     # edit_admin_posts GET /admin/post/1/edit {:controller=>"lolita/rest",:action=>:edit}
  # * <tt>:module</tt> - change module for path, it changes <i>:controller</i> that is used for lolita, like, 
  #   <code>:module=>"admin"</code>, change controller to "admin/posts". If this is used without :path then no named routes will be generated
  # Instances of this class is used all over the Lolita, this class itself represent what name does resource has,
  # what controller to use, what model is related with it and so on. This is used to generate urls and paths.
  # Also eahc request containers information with mapping related to it.
  class Mapping
    attr_reader :class_name,:path,:singular,:plural,:path_prefix,:module,:as,:controllers,:ref
    attr_reader :visible, :only, :append_to, :title
    alias :name :singular
    
    
    def initialize(name,options={})
      # TODO how it is when lolita plugin extend default path and there is module is this not break the logic?
      @as           = options[:as]
      @title        = options[:title]
      @to           = options[:to].is_a?(String) ? options[:to].constantize : options[:to]
      @visible      = options.keys.include?(:visible) ? options[:visible] : true
      @append_to    = options[:append_to]
      @only         = options[:only] || nil
      @plural       = (options[:as] ? options[:as] : name).to_sym
      @singular     = (options[:singular] || @plural.to_s.singularize).to_sym
      @class_name   = (options[:class_name] || name.to_s.classify).to_s
      @ref          = @class_name.to_s.camelize
      @path_prefix  = options[:path_prefix]
      @path         = (options[:path] || "lolita").to_s
      @module       = options[:module] 
      @default_mod  = @module || "lolita"
      @controllers  = Hash.new{|h,k|
        h[k]=options[:controller] || "#{!@module && "lolita/"}#{k}" 
      }
    end
  
    def controller
      "#{@default_mod}#{@default_mod && "/"}#{@plural}"
    end

    # Return class that is related with mapping.
    def to
      @to || (@ref.constantize rescue nil)
    end
    
    # full path of current mapping
    def fullpath
      "#{@path_prefix}/#{@path}".squeeze("/")
    end

    def url_name #TODO test what with namespace
      "#{@path}_#{@plural}"
    end

    def add_to_navigation_tree
      tree = Lolita.navigation
      if self.visible
        if self.append_to
          parent_branch = tree.branches.detect{|b| b.options[:system_name] == self.append_to}
          unless parent_branch
            parent_branch = tree.append(nil,:title => lambda{|branch| 
              return ::I18n.t("lolita.navigation." + branch.options[:system_name])
              }, :system_name => self.append_to
            )
          end
          tree = parent_branch.children
        end
        unless tree.branches.detect{|b| b.object.is_a?(Lolita::Mapping) && b.object.ref == self.ref}
          tree.append(self, :title => @title)
        end
      end
    end
    
  end
end