# Copyright (C) 2003-2005 Kouichirou Eto, All rights reserved.

$LOAD_PATH << "../../lib" unless $LOAD_PATH.include?("../../lib")
require "qwik/catalog-factory"
require "qwik/gettext"

# load basic actions
require "qwik/act-generate"
require "qwik/act-condition"
require "qwik/act-login"
require "qwik/act-view"
require "qwik/act-plugin"
require "qwik/act-toc"
require "qwik/act-basic-plugin"
require "qwik/act-interwiki"
require "qwik/act-newpage"
require "qwik/act-sitelog"
require "qwik/act-edit"

module Qwik
  class Action
    include GetText

    PRE_ACTION = ["theme", "css", "redirect", "getpass",
      "login", "basicauth", "typekey", "logout"]
    PRE_EXT = ["xml", "rss", ""] # "" is important to treat with redirect

    def initialize(config, memory, req, res)
      @config, @memory, @req, @res = config, memory, req, res
    end

    def init_catalog (req)
      accept_languages = req.accept_language
      accept_languages.each {|lang|
	catalog = @catalog_factory.get_catalog(lang)
        if catalog
          set_catalog(catalog)
          break
        end
      }
    end

    def run
      @catalog_factory = @memory.catalog
      init_catalog(@req)

      @site = @memory.farm.get_site(@req.sitename)

      if @site.nil?
	@site = @memory.farm.get_default_site
	return action_no_such_site
      end

      # RingInviteMailTemplate is using "GetPass.html".
      file = @req.base+"."+@req.ext
      @req.plugin = "getpass" if file == "GetPass.html"

      begin
	# get user
	get_user

	# do pre action
	if @req.plugin && PRE_ACTION.include?(@req.plugin)
	  return do_action(@req.plugin)
	end

	# do pre ext
	if @req.ext && PRE_EXT.include?(@req.ext)
	  return do_ext(@req.ext)
	end

	# check auth for the site
	require_mail   = true
	require_member = true
	if @site.is_open?
	  require_mail   = false
	  require_member = false
	end

	if require_mail && @req.user.nil?
	  @res.clear_cookies
	  return action_go_login
	end

	if require_member && !@site.member.exist?(@req.user)
	  return action_member_only_form(@req.user, @site.ml)
	end

	# do action
	if @req.plugin
	  return do_action(@req.plugin)
	end

	# do ext action
	return do_ext(@req.ext)

      rescue InvalidUserError
	@res.clear_cookies # important
	return login_invalid_user

      rescue RequireLogin
	return action_require_login

      rescue RequireMember
	return action_member_only_form(@req.user, @site.ml)

      rescue RequirePost
	return action_require_post

      rescue PageNotFound
	return action_page_not_found

      rescue NoPathArgs
	return action_no_path_args

      rescue BaseIsNotSitename
	return action_require_base_is_sitename

      rescue WEBrick::HTTPStatus::Status
	raise $!

      rescue StandardError
	e = $!
	pp e.message
	pp e.backtrace
	raise e
	#return c_nerror(e.message){ backtrace_html($!) }
      end
    end

    def action_no_such_site
      c_nerror(_("No such site"), nil, 404){[
	  [:p, [:b, @req.sitename], " : ", _("no correspond site")],
	  [:p , _("Please send mail to make a site")],
	  [:p, [:a, {:href=>"http://qwik.jp/"}, "qwik.jp"],
	    _("Access here and see how to.")],
	]}
    end

    def action_go_login
      c_notice(_("Login"), ".login"){[
	  [:p, _("Please login.")],
	  [:p,[:a,{:href=>".login"},_("Login")]," : "+_("Access here.")],
	]}
    end

    def action_require_login
      c_nerror(_("Please login.")){[
	  [:p, _("You need login to use this function.")],
	  [:p,[:a,{:href=>".login"},_("Login")]," : "+_("Access here.")],
	  [:hr],
	  [:p,_("Go back")," : ",[:a,{:href=>"FrontPage.html"},"FrontPage"]]
	]}
    end

    def action_member_only_form(user, ml)
      c_nerror(_("Member Only")){[
	  [:p, _("You are now logged in as this user id."), [:br],
	    [:strong, user]],
	  [:p, _("This user id is not a member of this group."), [:br],
	    [:strong, ml]],
	  [:p, _("If you would like to login as another account,"), [:br],
	    _("do logout at the first.")],
	]+logout_form
      }
    end

    def action_require_post
      c_nerror(_("Need POST")){[
	  [:p, _("This function needs POST method.")],
	  [:p,_("Go back")," : ",[:a,{:href=>"FrontPage.html"},"FrontPage"]]
	]}
    end

    def action_page_not_found
      c_nerror(_("Page not found."), "FrontPage.html", 404){
	[:h2, _("Page not found.")]
      }
    end

    def action_no_path_args
      c_nerror(_("No path args"), "FrontPage.html", 404){
	[:h2, _("Path args are not acceptable.")]
      }
    end

    def action_require_base_is_sitename
      c_nerror(_("Not found."), "FrontPage.html", 404){
	[:h2, _("Not found.")]
      }
    end

    def do_action(action)
      method = "act_"+action.to_s
      return self.send(method) if self.respond_to?(method)
      return c_nerror("no such action : #{action}")
    end

    def do_ext(ext)
      method = "ext_"+ext.to_s
      return self.send(method) if self.respond_to?(method)
      if @req.sitename == "www" # Special attach mode.
	@req.path_args = [@req.base+"."+@req.ext]
	return act_attach
      end
      return c_nerror("no such extention : #{ext}")
    end

    def ext_ # null ext
      s =  @req.base
      c_notice("redirect to site : "+s, "/#{s}/"){}
    end
  end
end

if $0 == __FILE__
  require "qwik/test-common"
  $debug = true
end

if $debug
  class TC_Action < Test::Unit::TestCase
    include TestSession

    def test_action
      # Check a site that is not exist.
      session("/nosuchsite/")
      assert_text("No such site", "title")
      assert_text("No such site", "h1")
      assert_text("nosuchsite", "b")
      assert_equal(404, @res.status)

      # Check a private site.
      session("/test/")
      assert_text("Member Only", "title")
      assert_xpath([:p, "You are now logged in as this user id.", [:br],
		     [:strong, "user@e.com"]],"//p")

      t_add_user

      # Nosuch action.
      session("/test/.nosuch")
      assert_text("no such action : nosuch", "title")

      # Nosuch ext.
      session("/test/1.nosuch")
      assert_text("no such extention : nosuch", "title")

      # Redirect to site
      session("/test")
      assert_text("redirect to site : test", "title")
      assert_xpath([:meta, {:content=>"0; url=/test/",
		       "http-equiv"=>"Refresh"}], "//meta[2]")
    end
  end
end
