class Dir
  DIRSTACK = []
  class << self

    def pushd(*args)
#{{{
      usage = '[dir | N], [:n] %s'
      nochdir = ret = op = nil

      if args.empty?
        if DIRSTACK.size >=2
          op = lambda{DIRSTACK[0],DIRSTACK[1]=DIRSTACK[1],DIRSTACK[0]}
        end
      else
        arg, opt = args
        nochdir = opt == :n 
        case arg
          when Fixnum 
            if arg > 0 or arg < -1
              op = lambda{DIRSTACK.replace(DIRSTACK[arg..-1] + DIRSTACK[0...arg])}
            else
              raise ArgumentError, usage % "- <#{ arg.class }> <#{ arg.inspect }>" 
            end
          else
            raise ArgumentError, usage % "- <#{ arg.class }> <#{ arg.inspect }>" unless
              test ?d , arg
            op = lambda{Dir.chdir arg unless nochdir; DIRSTACK.unshift arg}
        end
      end

      if op
        begin
          Thread.critical = true
          ret = op.call
        ensure
          Thread.critical = false 
        end
      end

      ret
#}}}
    end

    def popd(*args)
#{{{
      usage = '[N], [:n] %s'
      nochdir = ret = op = nil

      if args.empty?
        op = lambda{(DIRSTACK.empty? ? nil : Dir.chdir(d=DIRSTACK.shift) and d)}
      else
        arg, opt = args
        nochdir = opt == :n 
        case arg
          when Fixnum 
            op = lambda{Dir.chdir DIRSTACK[arg]; DIRSTACK.delete_at arg}
          else
            raise ArgumentError, usage % "- <#{ arg.class }> <#{ arg.inspect }>"  
        end
      end

      if op
        begin
          Thread.critical = true
          ret = op.call
        ensure
          Thread.critical = false 
        end
      end

      ret
#}}}
    end

    def dirs(*args)
#{{{
      usage = '[N], [:c | :l | :p | :v]+ %s'
      nochdir = ret = op = nil

      if args.empty?
        DIRSTACK.dup
      else
        arg, opt = args

        opt = arg if Symbol == arg

        if Symbol === arg
          opt = arg
          case opt
            when :c
              DIRSTACK.clear
            when :l
              DIRSTACK.map{|d| File.expand_path d}
            when :p
              DIRSTACK.join "\n"
            when :v
              DIRSTACK.inject(a=[]){|a,d| a << "#{ a.size }:#{ File.expand_path d }"}
            else
              raise ArgumentError, usage % "- <#{ arg.class }> <#{ arg.inspect }>"  
          end
        else
          case arg
            when Fixnum 
              DIRSTACK[arg].dup
            else
              raise ArgumentError, usage % "- <#{ arg.class }> <#{ arg.inspect }>" unless 
                test ?d ,dir
              op = lambda{Dir.chdir dir unless nochdir; DIRSTACK.unshift arg}
          end
        end
      end
#}}}
    end

  end
end
