module Makura
  class Layout
    attr_accessor :design, :name, :map, :reduce

    PATH = [
      './couch',
      File.join(Makura::ROOT, '../couch')
    ]

    def initialize(name, design)
      @name, @design = name, design
      @design[name] = self
      @map = @reduce = nil
      @options = {}
    end

    def load_proto_map(file_or_function, replace = {})
      return unless common_load(:proto_map, file_or_function)
      replace.each{|from, to| @proto_map.gsub!(/"\{\{#{from}\}\}"/, to) }
      @map = @proto_map
    end

    def load_proto_reduce(file_or_function, replace = {})
      return unless common_load(:proto_reduce, file_or_function)
      replace.each{|from, to| @proto_reduce.gsub!(/"\{\{#{from}\}\}"/, to) }
      @reduce = @proto_reduce
    end

    def load_map(file_or_function)
      common_load(:map, file_or_function)
    end

    def load_reduce(file_or_function)
      common_load(:reduce, file_or_function)
    end

    def common_load(type, file_or_function)
      return unless file_or_function

      case file_or_function
      when /function\(.*\)/, /^_(sum|count|stats)$/
        function = file_or_function
      else
        parts = file_or_function.to_s.split('::')
        file = parts.pop
        filename = File.join(parts, type.to_s, "#{file}.js")

        if pathname = PATH.find{|pa| File.file?(File.join(pa, filename)) }
          function = File.read(File.join(pathname, filename))
        end
      end

      instance_variable_set("@#{type}", function) if function
    end

    def save
      @design[@name] = self.to_hash
      @design.save
    end

    def to_hash
      {:map => @map, :reduce => @reduce, :makura_options => @options}
    end
  end
end
