require 'logger'
require 'singleton'

require "tlogger/version"

module Tlogger
  class Error < StandardError; end
  # Your code goes here...

  # 
  # Singleton object to facilitate tag management
  #
  class TloggerConf
    include Singleton
    attr_reader :active_tags, :scoped_tag, :disabled_tags, :auto_tag
    #GLOBAL_TAG = :global
    GLOBAL_TAG = ""
    
    def initialize
      @active_tags = []
      @disabled_tags = []
      @disable_all_tags = false
      @auto_tag = false
    end

    def auto_tag_on
      @auto_tag = true
    end

    def auto_tag_off
      @auto_tag = false
    end

    def is_auto_tag_on?
      @auto_tag
    end

    def activate_tag(tag)
      @active_tags << tag
    end

    def deactivate_tag(tag)
      @active_tags.delete(tag)
    end

    def disable_tag(tag)
      if tag.is_a?(Array)
        @disabled_tags += tag
      else
        @disabled_tags << tag
      end
    end

    def all_tags_off
      @disable_all_tags = true
    end

    def all_tags_on
      @disable_all_tags = false
    end

    def enable_tag(tag)
      if tag.is_a?(Array)
        tag.each do |t|
          @disabled_tags.delete(t)
        end
      else
        @disabled_tags.delete(tag)
      end
    end
    
    def is_tag_active?(tag)
      if @disable_all_tags
        false
      else
        @active_tags.include?(tag) and not @disabled_tags.include?(tag)
      end
    end

    def remove_all_active_tags
      @active_tags.clear
    end

    def remove_all_disabled_tags
      @disabled_tags.clear
    end

    def set_scoped_tag(tag)
      @scoped_tag = tag
    end

    def clear_scoped_tag
      @scoped_tag = nil
    end

    def has_scoped_tag?
      if @disable_all_tags
        false
      else
        not @scoped_tag.nil? and not @scoped_tag.empty?
      end
    end

    def is_scoped_tag_active?
      not @disabled_tags.include?(@scoped_tag)
    end

    def self.method_missing(mtd,*args,&block)
      if TloggerConf.instance.respond_to?(mtd)
        TloggerConf.instance.send(mtd,*args,&block)
      else
        super
      end
    end
  end
  # 
  # end TloggerConf singleton
  #

  # 
  # add object like methods to make module a class
  #
  class << self
    attr_accessor :tag
    include Tlogger
    
    PROXY_MTD = [:debug, :info, :error, :warn]
    def new(*args)
      if args.length == 0
        args << STDOUT
      end
      @tlogger = Logger.new(*args)
      @tag = TloggerConf::GLOBAL_TAG
      self
    end

    def tag=(val)
      @tag = val
      TloggerConf.activate_tag(@tag)
      self
    end

    def tdebug(tag,*args)
      with_tag(tag) do
        debug(*args)
      end
      self
    end

    def terror(tag, *args)
      with_tag(tag) do
        error(*args)
      end
      self
    end

    def tinfo(tag, *args)
      with_tag(tag) do
        info(*args)
      end
      self
    end

    def twarn(tag, *args)
      with_tag(tag) do
        warn(*args)
      end
      self
    end

    def method_missing(mtd,*args,&block)
      @tlogger.debug "[tlogger] method_missing: Method #{mtd}"
      if @tlogger.respond_to?(mtd)
        if TloggerConf.is_tag_active?(@tag) or TloggerConf.has_scoped_tag?
          if PROXY_MTD.include?(mtd)
            # All messages should be tagged under this section...
            if TloggerConf.has_scoped_tag?
              if TloggerConf.is_scoped_tag_active?
                args[0] = "[#{TloggerConf.scoped_tag}] #{args[0]}"
                @tlogger.send(mtd,*args,&block)
              end
            else
              if not @tag.nil? and not @tag.empty?
                if @tag == TloggerConf::GLOBAL_TAG
                  if TloggerConf.is_auto_tag_on?
                    args = tag_class(*args)
                    @tlogger.send(mtd,*args,&block)
                  end
                else
                  args[0] = "[#{@tag}] #{args[0]}"
                  @tlogger.send(mtd,*args,&block)
                end
              elsif TloggerConf.is_auto_tag_on?
                args = tag_class(*args)
                @tlogger.send(mtd,*args,&block)
              end
            end
          
          else
            @tlogger.send(mtd,*args,&block)
          end
          # if in proxy method list
          
          #@tlogger.send(mtd,*args,&block)

        elsif TloggerConf.is_auto_tag_on?
          args = tag_class(*args)
          @tlogger.send(mtd, *args, &block)
        end
      elsif TloggerConf.respond_to?(mtd)
        # redirect the config method to make it consistent API
        TloggerConf.send(mtd, *args, &block)
      else
        super
      end
    end
    # end method_missing
    # 

    private
    def tag_class(*args)
      caller.each do |c|
        next if c =~ /tlogger.rb/
        @cal = c
        break
      end
      
      if not @cal.nil? and not @cal.empty?
        wd = Dir.getwd
        @scal = @cal[wd.length+1..-1]
        args[0] = "[#{@scal}] #{args[0]}"
      end

      args
      #args[0] = "[#{@cal}] #{args[0]}"
    end
    # end tag_class()
    #
  end
  # 
  # end class definition
  #


  def with_tag(tag,&block)
    if block
      TloggerConf.instance.set_scoped_tag(tag) #if not TloggerConf.instance.disabled_tags.include?(tag)
      block.call
      TloggerConf.instance.clear_scoped_tag
    end
  end
  
end