# Copyright: Copyright 2009 Topic Maps Lab, University of Leipzig.
# License:   Apache License, Version 2.0

module RTM
  module Axes

    # ---- Proxy ---------------------------------------------------------------#
    class Proxy
      #attr_accessor :construct
      attr_reader :construct
      attr_reader :tm
      
      def initialize(construct,tm)
        test_for_type(construct)
        @construct = construct
        @tm = tm
      end
    end
    
    # ---- ItemProxy -----------------------------------------------------------#
    class ItemProxy < Proxy
      alias result construct
      alias :tmapi :result
    end
    
    # ---- RTM::Axes::Topic ----------------------------------------#
    class Topic < ItemProxy
      require "rtm/axes/topic"
      
      private
      
      def test_for_type(construct)
        unless construct.is_a?(RTM::Topic)
          raise("This is not a Topic. A RTM::Axes::Topic object requires a RTM::Topic.")
        end
      end
    end
    
    # ---- Association ---------------------------------------------------------#
    class Association < ItemProxy
      require "rtm/axes/association"
      
      private
      
      def test_for_type(construct)
        unless construct.is_a?(RTM::Association)
          raise("This is not an Association. An RTM::Axes::Association object requires a RTM::Association.")
        end
      end
    end
    
    # ---- RTM::Axes::Characteristic -------------------------------#
    class Characteristic < ItemProxy
      require "rtm/axes/characteristic"
      
      private
      
      def test_for_type(construct)
        unless construct.is_a?(RTM::Name) || construct.is_a?(RTM::Occurrence)
          raise("This is not a Name or Occurrence. A RTM::Axes::Characteristic object requires a RTM::Name or RTM::Occurrence.")
        end
      end
    end
    
    # ---- RTM::Axes::Name -----------------------------------------#
    class Name < Characteristic
      
      private
      
      def test_for_type(construct)
        unless construct.is_a?(RTM::Name)
          raise("This is not a Name. A RTM::Axes::Name object requires a RTM::Name.")
        end
      end
    end
    # ---- RTM::Axes::Occurrence -----------------------------------#
    class Occurrence < Characteristic
      
      private
      
      def test_for_type(construct)
        unless construct.is_a?(RTM::Occurrence)
          raise("This is not a Occurrence. A RTM::Axes::Occurrence object requires a RTM::Occurrence.")
        end
      end
    end
    
    # ---- RTM::Axes::String ---------------------------------------#
    class String < ItemProxy
      require "rtm/axes/string"
      
      private
      
      def test_for_type(construct)
        unless construct.is_a?(Object::String)
          raise("This is not a String. A RTM::Axes::String object requires a String.")
        end
      end
    end
    
    # ---- ArrayProxy ----------------------------------------------------------#
    module ArrayProxy
      def define_helper(method,*args)
        inject([]){|all,containee| all << containee.send(method,*args)}.flatten
      end
    end
    
    #  # ---- ArrayProxy ----------------------------------------------------------#
    #  class ArrayProxy < Proxy
    ##    def method_missing(method,*args)
    ##      if @construct.all? {|containee| containee.respond_to?(method)}
    ##        ArrayProxy.new(@construct.inject([]){|all,containee| all << containee.send(method,*args)})
    ##      else
    ##        super
    ##      end
    ##    end
    #
    #
    #
    #    def self.define_proxy_return_topics(method,*args)
    #      define_method method do |*args|
    #        _res = filter_helper(method,*args)
    #        _res = _res.map{|item| item.construct}.flatten
    #        if _res.empty?
    #          EmptyArrayProxy.new(_res)
    #        else
    #          Topics.new(_res)
    #        end
    #      end
    #    end
    #
    #    def self.define_proxy_return_associations(method,*args)
    #      define_method method do |*args|
    #        _res = filter_helper(method,*args)
    #        _res = _res.map{|item| item.construct}.flatten
    #        if _res.empty?
    #          EmptyArrayProxy.new(_res)
    #        else
    #          Associations.new(_res)
    #        end
    #      end
    #    end
    #
    #    def self.define_proxy_return_characteristics(method,*args)
    #      define_method method do |*args|
    #        _res = filter_helper(method,*args)
    #        _res = _res.map{|item| item.construct}.flatten
    #        if _res.empty?
    #          EmptyArrayProxy.new(_res)
    #        else
    #          Characteristics.new(_res)
    #        end
    #      end
    #    end
    #
    #    def self.define_proxy_return_strings(method,*args)
    #      define_method method do |*args|
    #        _res = filter_helper(method,*args)
    #        _res = _res.map{|item| item.construct}.flatten
    #        if _res.empty?
    #          EmptyArrayProxy.new(_res)
    #        else
    #          Strings.new(_res)
    #        end
    #      end
    #    end
    #
    #    def self.define_proxy_return_string(method,*args)
    #      define_method method do |*args|
    #        _res = filter_helper(method,*args)
    #        if _res.empty?
    #          EmptyArrayProxy.new(_res)
    #        else
    #          Strings.new(_res)
    #        end
    #      end
    #    end
    #
    #    def self.define_proxy_return_item(method,*args)
    #      define_method method do |*args|
    #        _res = filter_helper(method,*args)
    #        if _res.empty?
    #          EmptyArrayProxy.new(_res)
    #        else
    #          AssocsNamesOccsProxy.new(_res)
    #        end
    #      end
    #    end
    #
    #    def result
    #      @construct.map{|containee| containee.result}
    #    end
    #    alias :tmapi :result
    #
    #    def filter_helper(method,*args)
    #      _res = define_helper(method,*args) #Array
    #      _res = _res.reject{|item| item.empty? }
    #      _res = _res.reject{|item| item.class == NilProxy}
    #    end
    #
    #    def define_helper(method,*args)
    #      #@construct.inject([]){|all,containee| all << containee.send(method,*args).construct}.flatten
    #      @construct.inject([]){|all,containee| all << containee.send(method,*args)}
    #    end
    #  end
    
    #  # ---- Topics ---------------------------------------------------------#
    #  class Topics < ArrayProxy
    #    define_proxy_return_characteristics(:characteristics)
    #    define_proxy_return_strings(:indicators)
    #    define_proxy_return_string(:item)
    #    define_proxy_return_strings(:locators)
    #    define_proxy_return_associations(:reverse_players)
    #    define_proxy_return_item(:reifier)
    #
    #    define_proxy_return_topics(:supertypes)
    #
    #    define_proxy_return_topics(:subtypes)
    #    define_proxy_return_topics(:traverse)
    #    define_proxy_return_topics(:types)
    #    define_proxy_return_topics(:instances)
    #    define_proxy_return_topics(:reverse_types)
    #    define_proxy_return_topics(:reverse_instances)
    #    define_proxy_return_associations(:reverse_roles)
    #  end
  end
end

module RTM::AxesExtension;end
module RTM::AxesExtension::Topic
  
  # Changes from TMAPI-mode to Axes-mode.
  #
  # :call-seq:
  #   axes -> RTM::Axes::Topic
  #
  def axes(tm = self.topic_map)
    RTM::Axes::Topic.new(self, tm)
  end
end

module RTM::AxesExtension::Name
  
  # Changes from TMAPI-mode to Axes-mode.
  #
  # :call-seq:
  #   axes -> RTM::Axes::Name
  #
  def axes(tm = self.topic_map)
    RTM::Axes::Name.new(self, tm)
  end
end

module RTM::AxesExtension::Occurrence
  
  # Changes from TMAPI-mode to Axes-mode.
  #
  # :call-seq:
  #   axes -> RTM::Axes::Occurrence
  #
  def axes(tm = self.topic_map)
    RTM::Axes::Occurrence.new(self, tm)
  end
end

module RTM::AxesExtension::Association
  
  # Changes from TMAPI-mode to Axes-mode.
  #
  # :call-seq:
  #   axes -> RTM::Axes::Association
  #
  def axes(tm = self.topic_map)
    RTM::Axes::Association.new(self, tm)
  end
end

class String
  
  # Changes from TMAPI-mode to Axes-mode.
  #
  # A TopicMap must be specified.
  #
  # :call-seq:
  #   axes(topic_map) -> RTM::Axes::String
  #
  def axes(tm)
    RTM::Axes::String.new(self,tm)
  end
end

RTM.register_extension(RTM::AxesExtension)

require "rtm/axes/topics"
require "rtm/axes/associations"
require "rtm/axes/characteristics"
require "rtm/axes/assocs_names_occs"
require "rtm/axes/strings"