# $Id: ext_wikidb.rb,v 1.4 2004/04/21 09:32:30 eto Exp $
# Copyright (C) 2003-2004 Kouichirou Eto, All rights reserved.
# This is free software with ABSOLUTELY NO WARRANTY.
# You can redistribute it and/or modify it under the terms of the GNU GPL2.

require 'qwik/page'

module Qwik
  class Page
    def wikidb()
      @wikidb = WikiDB.new(self) if @wikidb.nil?
      @wikidb
    end
  end

  class WikiDB
    include Enumerable

    def initialize(page)
      @page = page
      @signature = ["|", ",", ":"]
      @delimiter = ","
      @str = nil
      @hash = {}
      check_new
    end

    def hash()
      check_new
      @hash
    end

    def [](key)
      hash()[key]
    end

    def exist?(key)
      self[key] != nil
    end

    def each
      hash().each {|k, v|
	k = k.dup # unfreeze
	yield(k, v)
      }
    end

    def add(k, *ar)
      ar.flatten!
      ar.delete(nil)
      @page.append(encode_line(k, ar)+"\n")
      true
    end

    def remove(key)
      return false unless exist?(key) # return if there is no key
      status = false
      newar = []
      str = @page.load
      str.each {|line|
	line.chomp!
	firstchar = line[0, 1]
	if @signature.include?(firstchar)
	  ar = line.split(firstchar)
	  ar.shift # drop first column
	  k = ar.shift
	  if k && k == key # do not add the line with the key
	    status = true # ok.
	    next
	  end
	end
	newar << line
      }
      newstr = newar.join('')
      @page.store(newstr, str.md5hex) # check if there is collision
      status
    end

    private

    def check_new
      str = @page.load
      return if str == @str
      @str = str
      @hash = {}
      @str.each {|line|
	line.chomp!
	firstchar = line[0, 1]
	next unless @signature.include?(firstchar)
	ar = line.split(firstchar)
	ar.shift # drop first column
	k = ar.shift
	if firstchar == ':'
	  v = ar.join(':')
	else
	  v = ar
	end
	@hash[k] = v
      }
    end

    def encode_line(k, *ar)
      ar.flatten!
      ar.delete(nil)
      nar = ['', k]
      nar << ar unless ar == nil || ar.length == 0
      nar.flatten.join(@delimiter);
    end
  end
end
