require 'maintain/backend/base'

module Maintain
  module Backend
    class << self
      def add(name, owner)
        classes[name.to_sym] = owner
        modules = owner.split('::')
        if Object.const_defined?(modules.first) && owner = Object.const_get(modules.shift)
          while modules.length > 0
            owner = owner.const_get(modules.shift)
          end
          if owner.is_a? Module
            owner.class_eval do
              class << self
                include Maintain
              end
            end
          else
            owner.extend Maintain
          end
        end
      end

      def build(back_end)
        back_end = back_end.to_s.split('_').map(&:capitalize).join('')
        if constants.include? back_end.to_s
          const_get(back_end.to_sym).new
        else
          begin
            back_end = const_missing(back_end)
            back_end.new
          rescue
          end
        end
      end

      def classes
        @classes ||= {}
      end

      def const_missing(constant)
        underscore_constant = constant.to_s.dup
        underscore_constant.gsub!(/::/, '/')
        underscore_constant.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
        underscore_constant.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
        underscore_constant.tr!("-", "_")
        underscore_constant.downcase!
        begin
          require("maintain/backend/#{underscore_constant}")
          const_get(constant)
        rescue
          super
        end
      end

      # Detect if we've loaded a backend for this class - that means if its ancestors or
      # parent classes include any of our back-end classes.
      def detect(owner)
        ancestors = owner.ancestors.map(&:to_s)
        # While owner does not refer to "Object"
        while owner.superclass
          ancestors.push(owner.to_s)
          owner = owner.superclass
        end
        classes.each do |back_end, class_name|
          if ancestors.include? class_name
            return back_end
          end
        end
        nil
      end
    end
  end
end