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

$LOAD_PATH << "../../lib" unless $LOAD_PATH.include?("../../lib")
require "qwik/wabisabi-diff"
require "qwik/act-plain"

module Qwik
  class Action
    def plg_page_link(ext, msg=ext)
      [[:span, {:class=>"attribute"},
	  [:a, {:href=>@req.base+"."+ext}, _(msg)]], "\n"]
    end

    def plg_backup_list
      return if @req.user.nil?
      return if !defined?(@req.base) || @req.base.nil?
      return plg_page_link("backup", "Show backup")
    end

    def ext_backup
      c_require_pagename
      c_require_member
      #c_require_page_exist # does not require the page is exist
      # because you can see the list of the page that is already deleted.
      c_require_no_path_args

      args = @req.ext_args
      if 0 < args.length # has target
	return backup_show(@site, @req.base, args)
      end

      return backup_list_page(@site, @req.base)
    end

    def backup_show(site, key, args)
      page = site[key]

      # error check
      return c_nerror("only one time stamp") if 1 < args.length

      # should be a number
      time = args.shift
      return c_nerror("should be number") unless /\A[0-9]+\z/ =~ time

      # Is the backup exist?
      time = Time.at(time.to_i)
      unless site.backupdb.exist?(key, time)
	return c_nerror("not found", nil, 404)
      end

      #qp time
      #qp time.ymdx

      # Get the old content.
      str = site.backupdb.get(key, time)
      #qp str

      # Get the list.
      list = backup_list(site, key)

      # Get the index of the content.
      index = nil
      list.each_with_index {|a, i|
	if a[1] == time.to_i
	  index = i
	end
      }
      return c_nerror("no data?", nil, 404) if index.nil?

      msg = ""
      if index == 0
	msg = [:p, _("The first page.")]
      else
	diff = backup_diff(list, index-1, index)
	msg = [:div, {:class=>"differ"}, *diff]
      end

      return c_plain(key+" @ "+time.ymdax){[
	  [:div, {:class=>"day"},
	    [:h2, _("Diff from the previous page")],
	    [:div, {:class=>"section"},
	      msg]],
	  [:div, {:class=>"day"},
	    [:h2, _("Original data")],
	    [:div, {:class=>"section"},
	      [:pre, str]]]
	]}
    end

    def backup_list(site, key)
      list = []
      site.backupdb.each_by_key(key) {|v, time|
	list << [v, time.to_i]
      }
      list
    end

    def backup_diff(list, last, now)
      s1, t1 = list[last]
      s2, t2 = list[now]
      return DiffGenerator.generate(s1, s2)
    end

    def backup_list_page(site, key)
      list = backup_list(site, key)

      ul = list.map {|v, time|
	[:li, [:a, {:href=>key+"."+time.to_s+".backup"},
	    Time.at(time).format_date]]
      }
      if 0 < ul.length
	ul.last << " "+_("<-")+" "+ _("newest")
      end

      c_plain(_("backup list")){
	[:div, {:class=>"day"},
	  [:div, {:class=>"section"},
	    [:ul, ul]]]
      }
    end

  end
end

if $0 == __FILE__
  require "t/test"
  $debug = true
end

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

    def test_plg_backup_list
      assert_wiki([[:span, {:class=>"attribute"},
		      [:a, {:href=>"1.backup"}, "Show backup"]], "\n"],
		  "{{backup_list}}")
    end

    def test_act_backup
      return if $0 != __FILE__

      # Only members can see the page.
      session("/test/1.html")
      assert_text("Member Only", "title")
      session("/test/1.backup")
      assert_text("Member Only", "title")

      t_add_user

      # You can see backup page even if the page does not exist.
      session("/test/1.html")
      assert_text("Page not found.", "title")
      session("/test/1.backup")
      assert_in(["backup list"], "//title")

      page = @site.create_new
      page.store("t")

      session("/test/1.html")
      assert_text("1", "title")
      session("/test/1.backup")
      assert_in(["backup list"], "//title")

      # Error check.
      session("/test/1.backup/0")
      assert_text("No path args", "title")
      session("/test/1.100.200.backup")
      assert_text("only one time stamp", "title")
      session("/test/1.hoge.backup")
      assert_text("should be number", "title")

      list = @action.backup_list(@site, "1")
      assert_equal("t", list[0][0])
      assert_equal(nil, list[1])

      t1 = list[0][1]
      path = "/test/1."+t1.to_s+".backup"
      session(path)
      assert_text(/\A1 @ /, "title")
      assert_text("t", "pre")

      # Edit the page again.
      sleep 1
      page.store("t2")

      list = @action.backup_list(@site, "1")
      assert_equal("t", list[0][0])
      assert_equal("t2", list[1][0])
      assert_equal(nil, list[2])

      diff = @action.backup_diff(list, 0, 1)
      assert_equal([[:del, "t"], [:br], [:ins, "t2"], [:br]], diff)

      t2 = list[1][1]
      path = "/test/1."+t2.to_s+".backup"
      session(path)
      assert_text(/\A1 @ /, "title")
      assert_text("t2", "pre")
      assert_in([[:del, "t"], [:br], [:ins, "t2"], [:br]],
		"//div[@class='differ']")

      # Edit the page again. The 3rd times.
      sleep 1
      page.store("t3")

      list = @action.backup_list(@site, "1")
      assert_equal("t", list[0][0])
      assert_equal("t2", list[1][0])
      assert_equal("t3", list[2][0])
      assert_equal(nil, list[3])

      diff = @action.backup_diff(list, 1, 2)
      assert_equal([[:del, "t2"], [:br], [:ins, "t3"], [:br]], diff)

      t3 = list[2][1]
      path = "/test/1."+t3.to_s+".backup"
      session(path)
      assert_text("t3", "pre")
      assert_in([[:del, "t2"], [:br], [:ins, "t3"], [:br]],
		"//div[@class='differ']")
    end
  end
end
