require 'cgi'
require 'drb/drb'
require 'rinda/ring'
require 'singleton'

class RWikiProxy 
  include Singleton

  class RWikiFinder
    RWIKI_URI = 'druby://localhost:8470'
    def initialize(use_ring=true)
      @use_ring = use_ring
    end

    def get_obj
      if @use_ring
	lookup_rwiki[0]
      else
	DRbObject.new(nil, RWIKI_URI)
      end
    end
    
    def lookup_rwiki
      ts = Rinda::RingFinger.primary
      ts.read_all([:name, :RWiki, nil, nil]).collect do |tuple|
	tuple[2]
      end
    end
  end

  class Page
    def initialize(name, proxy)
      @name = name
      @proxy = proxy
      @last = Time.at(1)
      
      @body = ''
      @links = []
      @revlinks = []
    end
    attr_reader :body, :modified, :links, :revlinks, :hot_links, :name
    attr_reader :last, :section_prop
    
    def update
      page = @proxy.rwiki.page(@name)
      @body = page.body_html({'ref_name'=>@proxy.ref_proc})
      @empty = page.empty?
      @modified = page.modified
      @links = page.links
      @revlinks = page.revlinks
      @hot_links = page.hotlinks.collect {|pg| pg.name}
      @section_prop = page.prop(:section) || {}
      @last = Time.now
    end

    def empty?
      @empty
    end
  end

  def initialize
    @cache = {}
    @ref_proc = Proc.new {|cmd, name| escape(name)}
    @rwiki = nil
    @recent_expires = Time.at(1)
    @recent = nil
  end
  attr_reader :ref_proc

  def rwiki
    return @rwiki if @rwiki
    @rwiki = RWikiFinder.new(true).get_obj
    @rwiki
  end

  def path2name(path)
    if /\/(.+)$/ =~ path #/
      unescape($1)
    else
      nil
    end
  end

  def escape(name)
    CGI.escape(name).gsub(/\%/, "@") + '.html'
  end

  def unescape(enc)
    CGI.unescape(enc.sub(/\.html$/, '').gsub(/\@/, "%"))
  end

  def update(name)
    modified = nil
    v = (@cache[name] ||= Page.new(name, self))
    v.update if v.last < Time.now - 300
    return v
  end
  
  def fetch(name)
    update(name)
  end

  def update_recent
    @recent = @rwiki.recent_changes
    @recent_expire = Time.now + 300
  end

  def recent_changes
    update_recent if @recent_expires < Time.now
    @recent
  end
end

