module Lolita
  module Translation
    class ClassFactory

      def self.create(class_name, parent, superclass=nil, &block)
        first,*other = class_name.split("::")
        if other.empty?
          klass = superclass ? Class.new(superclass, &block) : Class.new(&block)
          parent.const_set(first, klass)
        else
          klass = Class.new
          parent = unless parent.const_defined?(first)
            parent.const_set(first, klass)
          else
            first.constantize
          end
          self.create(other.join('::'), parent, superclass, &block)
        end
      end
    end

    module ModelInstanceMethods
      # override validate to vaidate only translate fields from master Class
      def validate
        item = self.class.name.sub('Translation','').constantize.new(self.attributes.clone.delete_if{|k,_| !self.class.translate_attrs.include?(k.to_sym)})
        item_adapter = Lolita::DBI::Adapter.add(item.class)
        self_adapter = Lolita::DBI::Adapter.add(self)
        was_table_name = item_adapter.collection_name
        item_adapter.collection_name = self_adapter.collection_name
        item.valid? rescue
        self.class.translate_attrs.each do |attr|
          errors_on_attr = item.errors.on(attr)
          self.errors.add(attr,errors_on_attr) if errors_on_attr
        end
        item_adapter.collection_name = was_table_name
      end
    end

    module ModelClassMethods
      # sets real master_id it's aware of STI
      def extract_master_id name
        master_class = name.sub('Translation','').constantize
        #FIXME why need to check superclass ?
        class_name = master_class.name #!master_class.superclass.abstract_class? ? master_class.superclass.name : master_class.name
        self.master_id = :"#{class_name.demodulize.underscore}_id"
      end
    end

    class TranslationModel

      attr_reader :adapter,:klass

      def initialize(config)
        @config = config
        @adapter =  Lolita::DBI::Base.create(@config.klass)
        @klass = begin
          @config.translation_class_name.constantize 
        rescue
          self.create
        end
        fix_class_attrs
        @klass.extract_master_id(@config.translation_class_name)
      end

      def create
        translation_model = self
        config = @config
        new_klass = Lolita::Translation::ClassFactory.create(@config.translation_class_name, Object, get_orm_class) do
            if translation_model.adapter.dbi.adapter_name == :mongoid
              include Mongoid::Document
            end
            # set's real table name
            translation_adapter = Lolita::DBI::Base.create(self)
            translation_adapter.collection_name = config.options[:table_name] || translation_model.adapter.collection_name.to_s.singularize + "_translation"
           
            cattr_accessor :translate_attrs, :master_id

            include Lolita::Translation::ModelInstanceMethods
            extend Lolita::Translation::ModelClassMethods
        end
        new_klass.translate_attrs = @config.attrs
        new_klass
      end

      private

      def get_orm_class()
        @adapter.dbi.adapter_name == :active_record ?  ActiveRecord::Base : nil
      end

      def fix_class_attrs
        unless @klass.respond_to?(:translate_attrs)
          @klass.send(:cattr_accessor, :translate_attrs, :master_id)
          @klass.send(:extend,Lolita::Translation::ModelClassMethods)
          @klass.translate_attrs = @config.attrs            
        end
      end
    end
  end
end