# $Id: ext_member.rb,v 1.15 2004/05/12 18:23:34 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/ext_wikidb'
require 'qwik/ext_form'

module Qwik
  class Site
    def member()
      @member = SiteMember.new(@config, self) if @member.nil?
      @member
    end
  end

  class SiteMember
    include Enumerable

    def initialize(config, site)
      @config = config
      @site = site
      @key = @config.sitemember
      @quickml_member = QuickMLMember.new(@config, @site)
    end

    def exist?(user)
      return true if exist_qwik_members?(user)
      return true if @quickml_member.exist?(user)
      false
    end

    def exist_qwik_members?(user)
      return false if db_page.nil?
      db.exist?(user)
    end

    def add(user, invite=nil)
      db.add(user, invite)
    end
    alias invite add

    def remove(user)
      db.remove(user) if db_page
    end

    def list()
      ar = []
      ar += db.hash.keys.to_a if db_page
      ar += @quickml_member.list
      ar = ar.uniq
      ar = obfuscate(ar) if @site.is_open?
      ar
    end

    def each
      list().each {|u|
	yield u
      }
    end

    private
    def db_page
      @site[@key]
    end

    def db
      page = db_page()
      page = @site.create(@key) if page.nil?
      page.wikidb
    end

    def obfuscate(ar)
      ar.map {|u|
	MailAddress.new(u).obfuscate
      }
    end
  end

  class QuickMLMember # QuickML compatible
    include Enumerable
    KEY = ",members"
    COMMENT = ["#", ";"]

    def initialize(config, site)
      @config = config
      @site = site
      @str = nil
      @ar = []
      check_new
    end

    def list()
      check_new
      @ar
    end

    def exist?(user)
      list().include?(user)
    end

    private
    def check_new
      file = @site.dir.path+KEY
      return unless file.exist?
      str = file.open('rb'){|f| f.read }
      return if str == @str
      @str = str
      @ar = []
      @str.each {|line|
	firstchar = line[0, 1]
	next if COMMENT.include?(firstchar)
	k, v = line.chomp.split
	next if k.nil?
	@ar << k
      }
    end

  end

  class PasswordGenerator
    def initialize(config)
      @config = config
      @pass = ""
      file = @config.pass_file.path
      if file.exist?
	@pass = file.open('rb'){|f| f.gets }.to_s.chomp
      end
    end

    def generate(user, generation=0)
      (user.to_s+':'+@pass+':'+generation.to_s).md5hex.upcase[0, 8]
    end
  end

  class PasswordMailGenerator
    def initialize(config, site)
      @config, @site = config, site
    end

    def generate(user, generation=0)
      user = user.to_s
      domainurl = @site.domainurl()
      siteurl = @site.url()
      gen = PasswordGenerator.new(@config)
      password = gen.generate(user, generation)

      mail = Mail.new
      mail.from = @site.ml
      mail.to = user
      mail.subject = domainurl+" におけるパスワード"
      mail.content = <<EOM
#{domainurl} におけるユーザー名とパスワードは、下記の通りです。

ユーザー名:	#{user}
パスワード:	#{password}

#{siteurl} に再度アクセスしてみてください。
EOM
      return mail
    end
  end

  class Plugin
    def member_user(arg=nil)
      @user
    end

    def member_add
      tomail = @query['tomail']
      return member_add_go(tomail) if tomail
      member_add_form
    end

    def member_add_form(dest="")
#新規メンバーを追加します。
      form(dest){
"|あなたのメール|{{member_user(mail)}}|
|追加メール|{{input(tomail,,must)}}|
|追加したい人のメールアドレスを入力してください。|
||{{submit( 追加 )}}|"}
    end

    def member_add_go(tomail)
      goback = "\n:メール:#{tomail}\nブラウザの「戻るボタン」で入力画面に戻り、もう一度入力を確認してください。\n"

      if tomail.nil? || !MailAddress.new(tomail).valid?
	return "** メンバーは追加されませんでした。#{goback}".w.res
      end

      if @site.member.exist?(tomail)
	return "** メンバーはすでに追加されているようです。#{goback}".w.res
      end

      @site.member.add(tomail, @user)

      if !@site.member.exist?(tomail)
	return "** メンバー追加エラー\nシステム管理者にご連絡下さい。".w.res
      end

      return "** メンバーは追加されました。\n:メール:#{tomail}\n".w.res
    end

    def member_list
      list = @site.member.list
      msg = "total: "+list.length.to_s+" member"
      msg += "s" if 1 < list.length
      e = @g.ul
      list.sort.each {|user|
	user = user.dup # unfreeze
	e << @g.li{user} 
      }
      @g.div{[ e, @g.p{msg} ]}
    end

    CSV_DIVIDE = 50
    def member_list_csv
      list = @site.member.list
      str = ""
      c = 0
      list.sort.each {|user|
	str += user
	c += 1
	if c % CSV_DIVIDE == 0
	  str += "\n"
	else
	  str += ", "
	end
      }
#      @g.textarea('member'){str}
      @g.make(:textarea, :style=>'width:90%;height:40ex;'){str}
    end

  end
end
