# プレイ記録を受け持つクラス
require 'stringio'

module DarkHall

	class Reporter
		module Type
			ADVENTURE = :adventure
			ITEM = :item
			ALL_MESSAGE = :all_message
		end
	
		def initialize(dir_path)
			@dir_path = Pathname(dir_path)
		end
		
		def check_dir
			FileUtils.mkpath(@dir_path) unless @dir_path.exist?
			return self
		end


		
		def on_adventure_start(restarting, party = GS.party)
			#unless restarting then
				put(AdventureStartReport.new(party, restarting))
			#end
		end

		def on_adventure_end(intermitting, party = GS.party)
			#unless intermitting then
				put(AdventureEndReport.new(party, intermitting))
			#end
		end

		def on_battle_start(party = GS.party, troop = $troop)
			@battle_report = BattleReport.new(party)
			@battle_report.set_troop_captions(troop)
			@battle_report.set_before_member_data(party)
		end

		def on_battle_end(result, battle = $battle, party = GS.party)
			@battle_report.result = result
			@battle_report.round = battle.round
			@battle_report.gold = battle.total_gold
			@battle_report.set_after_member_data(party)
			put(@battle_report)
		end
		
		def on_treasure_box_find(party, box)
			@treasure_report = TreasureBoxReport.new(party, box)
		end

		def on_treasure_box_operate_trap(id, targets, vanished)
			@treasure_report.on_operate_trap(id, targets, vanished)
			if vanished then
				put(@treasure_report)
			end
		end

		def on_treasure_box_open
			@treasure_report.on_open
			put(@treasure_report)
			
			item = @treasure_report.treasure_box.item
			if item then
				put(TreasureGetReport.new(item), Type::ITEM)
			end
		end
		
		def on_treasure_box_leave
			put(@treasure_report)
		end
		
		def on_shop_buy(item)
			put(ItemBuyReport.new(item), Type::ITEM)
		end
		
		def on_shop_sell(item)
			put(ItemSellReport.new(item), Type::ITEM)
		end
		
		def on_item_identify(item)
			put(ItemIdentifyReport.new(item), Type::ITEM)
		end
		
		def on_message(body)
			if Game.debug_mode? then
				put(MessageReport.new(body), Type::ALL_MESSAGE)
			end
		end
		
		
		private		
		def put(rep, to = Type::ADVENTURE)
			case to
			when Type::ADVENTURE
				filename = sprintf("adventure_week%05d.txt", GS.week)
			when Type::ITEM
				filename = sprintf("item.txt")
			when Type::ALL_MESSAGE
				filename = sprintf("all_message.txt", GS.week)
			end
			(@dir_path + filename).open('a'){|f|
				f.puts(rep.to_s)
			}


		end
		






	end

	class Report
		HR = '=' * 60
		attr_accessor :floor_id, :x, :y, :direction

		def initialize(party)
			@floor_id = party.floor_id
			@x = party.x
			@y = party.y
			@direction = party.direction
		end

		private
		def name_with_spacing(name)
			name_length = 0
			name.each_char{|c| name_length += CHAR_LENGTH_TABLE[c.length]}

			return(name + ' ' * (NAME_LENGTH_MAX - name_length).abs)
		end
		
		def timestamp
			Time.now.strftime("[%Y-%m-%d %H:%M]")
		end

		def header_line
			case $section
			when Section::TOWN
				"[街]\n"
			else
				sprintf("[%s %d, %d, %s向き]\n", FLOORS[@floor_id].name, @x, @y, DIR_NAMES[@direction])
			end
		end
		
		def party_detail
			re = ""

			@members.each do |member|

				re << "\t" << name_with_spacing(member.name) << '  '
				re << sprintf("%s:L%-2d  HP: %4d / %4d  ", member.class_initial,
				              member.level, member.hp, member.hp_max)

				re << "\n"
			end
			
			re
		end



	end
	
	# 全メッセージ記録。デバッグモードでのみ有効	
	class MessageReport < Report
		def initialize(body)
			@body = body
		end

		def to_s
			re = "#{HR}\n#{@body}\n"

			re
		end
	end


	class AdventureStartReport < Report
		def initialize(party, restarting)
			super(party)
			@members = party.members
			@restarting = restarting
		end

		def to_s
			text = (@restarting ? _('Returning to The DarkHall') : _('Entering The DarkHall'))
			re = "#{HR}\n#{text}\n"
			unless @restarting then
				re << party_detail
			end
			re << "#{HR}\n\n"

			re
		end
	end

	class AdventureEndReport < Report
		def initialize(party, intermitting)
			super(party)
			@members = party.members
			@intermitting = intermitting
		end

		def to_s
			text = (@intermitting ? '冒険を中断' : '迷宮から帰還')
			re = "#{HR}\n#{text}\n"
			unless @intermitting then
				re << party_detail
			end
			re << "#{HR}\n\n"
			
			re
		end
	end


	class BattleReport < Report
		attr_accessor :result, :gold, :before_member_data, :after_member_data, :round

		def set_troop_captions(troop)
			@troop_captions = troop.groups.map{|enemies|
				"#{enemies.first.name}#{enemies.size}体"
			}
		end

		def set_before_member_data(party)
			@before_member_data = party.members.map{|x| member_to_data(x)}
		end

		def set_after_member_data(party)
			@after_member_data = party.members.map{|x| member_to_data(x)}
		end



		def to_s
			re = ""

			re << header_line
			re << "\t#{@troop_captions.join('、')}と遭遇\n"
			case @result
			when BR_WIN
				re << "\t#{@round}ラウンドで勝利し、計#{@gold}Gを獲得\n"
			when BR_PARTY_ESCAPE
				re << "\t#{@round}ラウンドで逃走に成功\n"
			when BR_PARTY_ESCAPE
				re << "\t#{@round}ラウンドで敵が逃走\n"
			when BR_WIPEOUT
				re << "\t#{@round}ラウンドで全滅\n"
			end

			re << "\n"

			@after_member_data.each_with_index do |after_data, index|
				name, hp, hp_max, dead, exp = after_data
				before_data = @before_member_data[index]
				
				before_hp = before_data[1]
				before_dead = before_data[3]
				before_exp = before_data[4]
				get_exp = exp - before_exp

				re << "\t\t" << name_with_spacing(name) << '  '
				if dead then
					re << sprintf("DEAD%4s    %4s    ", nil, nil)
				elsif hp == before_hp then
					re << sprintf("HP: %4d    %4s    ", before_hp, nil)
				else
					re << sprintf("HP: %4d -> %4d    ", before_hp, hp)
				end

				if get_exp >= 1 then
					re << sprintf("exp +%d", get_exp)
				end

				re << "\n"
			end
			re << "\n"

			re
		end

		private
		def member_to_data(member)
			[member.name, member.hp, member.hp_max, member.dead?, member.exp]
		end
	end
	
	class TreasureBoxReport < Report
		attr_reader :treasure_box
		def initialize(party, treasure_box)
			super(party)
			@treasure_box = treasure_box
			@operated_trap_id = nil
			@target_names = nil
			@vanished = false
			@opened = false
		end
		
		def on_operate_trap(id, targets, vanished)
			@operated_trap_id = id
			@target_names = targets.map{|x| x.name}
			@vanished = vanished
		end
		
		def on_open
			@opened = true
		end
		
		def to_s
			buf = StringIO.new
			buf.puts header_line
			buf.puts "\t宝箱を発見"
			if @operated_trap_id then
				buf.puts "\t#{TRAP_CAPTIONS[@operated_trap_id]}作動！"

				if @target_names then
					buf.puts "\t\t対象: #{@target_names.join(',')}"
				end
				
				if @vanished then
					buf.puts "\t宝箱は消滅してしまった"
				end
			end
			
			if @opened then
				if @treasure_box.item then
					buf.puts "\t#{@treasure_box.gold}枚の金貨と#{@treasure_box.item.name}を入手"
				else
					buf.puts "\t#{@treasure_box.gold}枚の金貨を入手"
				end
			end
			
			buf.puts
			
			return buf.string
		end
	end
	
	class ItemReport < Report
		def initialize(item, week = GS.week)
			@item = item
			@week = week
		end
	end
	
	class ItemIdentifyReport < ItemReport
		def to_s
			"[第#{@week}週]#{timestamp} 識別: #{@item.black_name} => #{@item.name}\n"
		end
	end
	
	class ItemBuyReport < ItemReport
		def to_s
			"[第#{@week}週]#{timestamp} 購入: #{@item.name}\n"
		end
	end
	
	class ItemSellReport < ItemReport
		def to_s
			"[第#{@week}週]#{timestamp} 売却: #{@item.name}\n"
		end
	end
	
	class ItemTrashReport < ItemReport
		def to_s
			"[第#{@week}週]#{timestamp} 捨てる: #{@item.name}\n"
		end
	end
	
	class TreasureGetReport < ItemReport
		def to_s
			"[第#{@week}週]#{timestamp} 宝箱: #{@item.name}\n"
		end
	end





end

