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

module Qwik
  class Action
    # ============================== verify
    def check_session
      sid = @req.cookies["sid"] # get sid from cookie.
      return if sid.nil? || sid.empty? # return if you don't have
      sdb = @memory.sessiondb
      user = sdb.get(sid) # get user from SessionDB.
      return if user.nil? # return if there is no session id.
      @req.user = user # OK! I have your sesssionid, and I know who you are.
      @req.auth = "session"
    end

    # ============================== login
    def session_store(user)
      sdb = @memory.sessiondb
      sid = sdb.generate_sid # make a new session id
      sdb.put(sid, user) # store it to session db
      return sid
    end

    # ============================== logout
    def session_clear
      sid = @req.cookies["sid"] # get sid from cookie.
      return if sid.nil? || sid.empty? # return if you don't have
      sdb = @memory.sessiondb
      user = sdb.get(sid) # get user from SessionDB.
      return if user.nil? # return if there is no session id.
      sdb.clear(sid)
    end
  end

  class SessionDB
   #DEFAULT_EXPIRE_TIME = 60 * 60 * 2 # 2 hours
    DEFAULT_EXPIRE_TIME = 60 * 60 * 24 * 14 # 2 weeks

    def initialize(config)
      @config = config
      @path = @config.cache_dir.path+"sid"
      @path.check_directory
      @expire_time = DEFAULT_EXPIRE_TIME
    end

    def generate_sid
      str = Time.now.to_i.to_s+":"+rand.to_s
      return str.md5hex
    end

    def path(sid)
      @path + sid
    end

    def put(sid, user)
      path(sid).open("wb") {|f|
	f.print(user)
      }
    end

    def clear(sid)
      file = path(sid)
      return nil if ! file.exist?
      file.unlink # delete it
    end

    def get(sid)
      return if sid.nil? || sid.empty?
      file = path(sid)
      return nil if ! file.exist?
      mtime = file.mtime
      diff = Time.now.to_i - mtime.to_i
      if @expire_time < diff
	clear(sid)
	return nil
      end
      str = file.open {|f| f.read }
      return str
    end
  end
end

if $0 == __FILE__
  $LOAD_PATH << "../../lib" unless $LOAD_PATH.include?("../../lib")
  require "t/test"
  $debug = true
end

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

    def test_all
      # not use
    end
  end

  class TC_SessionDB < Test::Unit::TestCase
    def test_all
      if defined?($test_memory)
	@memory = $test_memory
      else
	@memory = Qwik::ServerMemory.new(@config)
      end

      sdb = @memory.sessiondb

      # test generate session id
      sid = sdb.generate_sid
      assert_equal(32, sid.length)
      assert_match(/\A[0-9a-f]+\z/, sid)

      # test put
      sdb.put(sid, "user@e.com")
      file = sdb.path(sid)
      assert_equal(true, file.exist?)

      # test get empty
      assert_equal(nil, sdb.get(nil))
      assert_equal(nil, sdb.get(""))

      # test get
      user = sdb.get(sid)
      assert_equal("user@e.com", user)

      mtime = file.mtime
      oldtime = Time.at(mtime.to_i - 60 * 60 * 24 * 100)
      file.utime(oldtime, oldtime)

      # test session expired
      user = sdb.get(sid)
      assert_equal(nil, user)
      assert_equal(false, file.exist?)
    end
  end
end
