%%-----------------------------------------------------------------------------
%% @Module  :       lib_dungeon_flop.erl
%% @Author  :       zengzy
%% @Created :       2018-08-20
%% @Description:    副本翻牌
%%-----------------------------------------------------------------------------

-module (lib_dungeon_flop).

-export([
	login/2
	,start_dun_flop/3
	,start_batch_dun_flop/3
	,notice_flop_info/4
	,rare_reward_info/1
	,dun_flop/2
	,dun_batch_flop/3
	]).

-export([
	force_role_flop/2
	,force_role_batch_flop/3
	,handle_event/2
	]).

-include ("dungeon.hrl").
-include ("server.hrl").
-include ("predefine.hrl").
-include ("errcode.hrl").
-include ("def_fun.hrl").
-include ("figure.hrl").
-include ("goods.hrl").
-include ("common.hrl").
-include ("rec_event.hrl").
-include ("def_module.hrl").
-include ("def_event.hrl").
-include("def_goods.hrl").


login(Id, StatusDungeon) ->
	case db:get_row(?SQL_SELECT_ROLE_DUN_FLOP, [Id]) of
		[TreasureId, FlopVal, Treasured] ->
			#status_dungeon{flop = RoleFlop} = StatusDungeon,
			NewRoleFlop = RoleFlop#role_dun_flop{
				id = Id,
				treasure_id = TreasureId,
				flop_val = FlopVal,
				treasured = util:bitstring_to_term(Treasured)
			},
			StatusDungeon#status_dungeon{flop = NewRoleFlop};
		_ ->
			[MinId|_] = data_dungeon:get_all_share_id(),
			StatusDungeon#status_dungeon{flop = #role_dun_flop{id = Id, treasure_id = MinId}}
	end.

db_update_flop(StatusDungeon) ->
	#status_dungeon{flop = Flop} = StatusDungeon,
	case Flop of
		#role_dun_flop{id = RoleId} when RoleId =/= 0 ->
			#role_dun_flop{treasure_id = TreasureId, flop_val = FlopVal, treasured = Treasured} = Flop,
			db:execute(?SQL_REPLACE_ROLE_DUN_FLOP, [RoleId, TreasureId, FlopVal, util:term_to_bitstring(Treasured)]);
		_ ->
			% ?ERR("flop error ~w", [Flop]),
			ok
	end.


%% 开始翻牌
start_dun_flop(Player, _DunType, DunId) ->
    Now = utime:unixtime(),
    TempFlop  = #temp_flop{flop_time = Now + ?NORMAL_FLOP_MAX_TIME + 3, flop_dun_id = DunId},
    #player_status{dungeon = #status_dungeon{flop = #role_dun_flop{tmp_flop = TempFlop1} = RoleFlop} = StatusDungeon}
     = NewPlayer = lib_dungeon:update_status_dungeon([{flop, TempFlop}], Player),
    Msg = {'mod', ?MODULE, force_role_flop, [DunId]},
    Ref = erlang:send_after(?FLOP_FORCE_INTERVAL, self(), Msg),
    NewPlayer1 = NewPlayer#player_status{dungeon = StatusDungeon#status_dungeon{
    	flop = RoleFlop#role_dun_flop{tmp_flop = TempFlop1#temp_flop{ref = Ref}}}},
    % ?ERR("start_dun_flop ~p ~p", [_DunType, DunId]),
    notice_flop_info(?SUCCESS, 0, 0, NewPlayer1),
    {ok, NewPlayer1}.

%% 开始批量水晶开启
start_batch_dun_flop(Player, DunType, DunCountList) ->
	Now = utime:unixtime(),
	TempFlop = #temp_flop{flop_kind = ?BATCH_FLOP, flop_time = Now + ?BATCH_FLOP_MAX_TIME, flop_duns = DunCountList, flop_dun_type = DunType},
	#player_status{dungeon = #status_dungeon{flop = #role_dun_flop{tmp_flop = TempFlop1} = RoleFlop} = StatusDungeon}
	 = NewPlayer = lib_dungeon:update_status_dungeon([{flop, TempFlop}], Player),
	Msg = {'mod', ?MODULE, force_role_batch_flop, [DunType, DunCountList]},
	Ref = erlang:send_after(?FLOP_FORCE_INTERVAL, self(), Msg),
	NewPlayer1 = NewPlayer#player_status{dungeon = StatusDungeon#status_dungeon{
		flop = RoleFlop#role_dun_flop{tmp_flop  = TempFlop1#temp_flop{ref = Ref}}}},
	notice_batch_flop_info(?SUCCESS, NewPlayer),
	{ok, NewPlayer1}.

%% 强制翻牌
force_role_flop(Player, DunId) ->
	#player_status{dungeon = StatusDungeon} = Player,
	#status_dungeon{flop = RoleFlop} = StatusDungeon,
	#role_dun_flop{tmp_flop = TempFlop} = RoleFlop,
	util:cancel_timer(TempFlop#temp_flop.ref),
	case force_action_check(DunId, TempFlop) of
		true ->
			case dun_flop(_Pos = 1, Player) of
				{ok, NewPlayer} ->
					{ok, NewPlayer};
				_ ->
					{noreply, Player}
			end;
		_ ->
			{noreply, Player}
	end.

%% 强制批量翻牌
force_role_batch_flop(Player, DunType, _DunCountList) ->
	#player_status{dungeon = StatusDungeon} = Player,
	#status_dungeon{flop = RoleFlop} = StatusDungeon,
	#role_dun_flop{tmp_flop = TempFlop} = RoleFlop,
	util:cancel_timer(TempFlop#temp_flop.ref),
	case force_batch_action_check(DunType, TempFlop) of
		true ->
			case dun_batch_flop(DunType, _Index = 1, Player) of
				{ok, NewPlayer} ->
					{ok, NewPlayer};
				ok ->
					{noreply, Player};
				_ ->
					{noreply, Player}
			end;
		_ ->
			{noreply, Player}
	end.

notice_flop_info(ErrCode, Pos, Reset, Player) ->
	#player_status{sid = Sid, dungeon = StatusDun} = Player,
    #status_dungeon{flop = RoleFlop} = StatusDun,
    #role_dun_flop{
        treasure_id = TreasureId,
        flop_val    = FlopVal,
        tmp_flop    = Flop
    } = RoleFlop,
    #temp_flop{
        flop_count 	= FlopCount,
        flop_time 	= EndTime,
        flop_dun_id = DunId,
        reward 		= Reward
    } = Flop,
    RewardList = pack_reward_list(DunId, FlopCount, Reward),
    case data_dungeon:get_share_flop_treasure(TreasureId) of
    	#share_flop_treasure_cfg{flop_cost = Cost} -> ok;
    	_ -> Cost = 0
    end,
    % ?ERR("~p", [RewardList]),
    {ok, BinData}  = pt_610:write(61047, [ErrCode, Pos, FlopVal, Cost, EndTime, Reset, RewardList]),
    lib_server_send:send_to_sid(Sid, BinData),
    ok.

%% 61067
notice_batch_flop_info(_ErrCode, Player) ->
	#player_status{sid = Sid} = Player,
	InfoList = pack_batch_flop_info(61067, 0, Player),
	lib_server_send:send_to_sid(Sid, pt_610, 61067, InfoList),
	ok.

%% 61068
notice_batch_flop_action(ErrCode, Index, Reset, Rewards, Player) ->
	#player_status{sid = Sid} = Player,
	InfoList = pack_batch_flop_info(61068, Reset, Player),
	Rewards1 = pack_flop_reward_list(Rewards),
	InfoList1 = lists:append([ErrCode, Index|InfoList], [Rewards1]),
	lib_server_send:send_to_sid(Sid, pt_610, 61068, InfoList1),
	ok.

pack_flop_reward_list(Rewards) ->
	lists:foldl(fun({_, _, FlopType, Args}, Acc) ->
		case FlopType of
			?FLOP_NORMAL ->
				[RewardsX, Times|_] = Args,
				TimesRewards = [{Times, GoodsType, GoodsId, Num} || {GoodsType, GoodsId, Num} <- RewardsX],
				lists:append(TimesRewards, Acc);
			?FLOP_RARE ->
				[TreasureId, Index|_] = Args,
				case data_dungeon:get_share_flop_treasure(TreasureId) of
					#share_flop_treasure_cfg{treasure = TreasureList} ->
						case lists:keyfind(Index, 1, TreasureList) of
							{_, RewardsX, _} ->
								RewardsX1 = [{1, GoodsType, GoodsId, Num} || {GoodsType, GoodsId, Num} <- RewardsX],
								lists:append([RewardsX1, Acc]);
							_ ->
								Acc
						end;
					_ ->
						Acc
				end;
			_ ->
				Acc
		end
	 end, [], Rewards).

pack_batch_flop_info(Cmd, Reset, Player) ->
	#player_status{dungeon = StatusDun} = Player,
	#status_dungeon{flop = RoleFlop} = StatusDun,
	#role_dun_flop{
		treasure_id = TreasureId,
		flop_val 	= FlopVal,
		tmp_flop 	= Flop
	} = RoleFlop,
	#temp_flop{
		flop_count = FlopCount,
		flop_time  = _EndTime,
		flop_duns  = FlopDuns,
		flop_dun_type = DunType
	} = Flop,
	FreeCount = lists:sum([CountX || {_DunIdX, CountX} <- FlopDuns]),
	RestFreeCount = if FlopCount == 0 -> FreeCount;
		true -> 0
	end,
	RestAllCount  = FreeCount*(?FLOP_MAX_COUNT - FlopCount),
    %% 最大进度
    case data_dungeon:get_share_flop_treasure(TreasureId) of
    	#share_flop_treasure_cfg{flop_cost = Cost} -> ok;
    	_ -> Cost = 0
    end,
    ExtraCount 	  = ?FLOP_MAX_COUNT - 1,
    ExtraAllCount = ?FLOP_MAX_COUNT,
    {ExtraCountCost, ExtraMaxCountCost} =
     lists:foldl(fun({DunId, Count}, {Acc1, Acc2}) ->
    	case data_dungeon:get_dun(DunId) of
    		#dun_cfg{flop_cost = FlopCost} ->
    			NewAcc1 = case lists:keyfind(ExtraCount, 1, FlopCost) of
    				{_, _, _, Num} ->
    					round(Count*Num+Acc1);
    				_ ->
    					Acc1
    			end,
    			NewAcc2 = case lists:keyfind(ExtraAllCount, 1, FlopCost) of
    				{_, _, _, Num1} ->
    					Acc2+round(Num1*Count);
    				_ ->
    					Acc2
    			end,
    			{NewAcc1, NewAcc2};
    		_ ->
    			{Acc1, Acc2}
    	end
     end, {0, 0}, FlopDuns),
    ExtraAllCountCost = ExtraCountCost + ExtraMaxCountCost,
    if Cmd == 61068 ->
    		[DunType, RestFreeCount, RestAllCount, FlopVal, Cost, Reset, ExtraCountCost, ExtraAllCountCost];
    	true ->
    		[DunType, RestFreeCount, RestAllCount, FlopVal, Cost, ExtraCountCost, ExtraAllCountCost]
    end.

%%
rare_reward_info(Player) ->
	#player_status{sid = Sid, dungeon = StatusDungeon} = Player,
	#status_dungeon{flop = RoleFlop} = StatusDungeon,
	#role_dun_flop{
		treasure_id = TreasureId,
		treasured 	= Treasured
	} = RoleFlop,
	{TreasurePool1, RareTreasureIds} = case data_dungeon:get_share_flop_treasure(TreasureId) of
		#share_flop_treasure_cfg{treasure = TreasurePool} ->
			TreasureIds = [Index || {Index, _, _} <- TreasurePool],
			case lists:keyfind(TreasureId, 1, Treasured) of
				{_, TreasuredIndex} ->
					{TreasurePool, TreasureIds -- TreasuredIndex};
				_ ->
					{TreasurePool, TreasureIds}
			end;
		_ ->
			{[], []}
	end,
	%?ERR("~p ~p", [TreasureId, RareTreasureIds]),
 	AvalibleRewardList = get_rare_treasure_list(RareTreasureIds, TreasurePool1),
 	lib_server_send:send_to_sid(Sid, pt_610, 61048, [AvalibleRewardList]),
 	ok.


get_rare_treasure_list(IndexIds, TreasurePool) ->
	lists:foldl(fun(IndexId, Acc) ->
		case lists:keyfind(IndexId, 1, TreasurePool) of
			{_, GoodsList, _} ->
				lists:append(GoodsList, Acc);
			_ ->
				Acc
		end
	 end, [], IndexIds).

pack_reward_list(DunId, _FlopCount, Reward) ->
	FlopPos = FlopNum = lists:seq(1, ?FLOP_MAX_COUNT),
	{PackRewardList, _} = lists:foldl(fun(Count, {Acc, TmpPos}) ->
		case lists:keyfind({DunId, Count}, 1, Reward) of
			{_, Pos, _RareType = ?FLOP_NORMAL, Args} ->
				[RewardX, Times|_] = Args,
				Args1 = [{Times, GoodsType, GoodsId, Num} || {GoodsType, GoodsId, Num} <- RewardX],
				NewAcc = lists:append([{Pos, ?FLOPED, Args1}], Acc),
				NewTmpPos = lists:delete(Pos, TmpPos),
				{NewAcc, NewTmpPos};
			{_, Pos, _RareType = ?FLOP_RARE, Args} ->
				[TreasurePoolId, Index|_] = Args,
				NewAcc = case data_dungeon:get_share_flop_treasure(TreasurePoolId) of
					#share_flop_treasure_cfg{treasure = Treasures} ->
						case lists:keyfind(Index, 1, Treasures) of
							{_, GoodsList0, _} ->
								GoodsList = [{1, GoodsType, GoodsId, Num} || {GoodsType, GoodsId, Num} <- GoodsList0],
								lists:append([{Pos, ?FLOPED, GoodsList}], Acc);
							_ -> Acc
						end;
					_ -> Acc
				end,
				NewTmpPos = lists:delete(Pos, TmpPos),
				{NewAcc, NewTmpPos};
			_ ->
				[Pos|_] = TmpPos,
				NewAcc = lists:append([{Pos, ?FLOPING, []}], Acc),
				NewTmpPos = lists:delete(Pos, TmpPos),
				{NewAcc, NewTmpPos}
		end
	 end, {[], FlopPos}, FlopNum),
	PackRewardList.

dun_flop(Pos, Player) ->
	#player_status{sid = Sid, dungeon = #status_dungeon{flop = RoleFlop}} = Player,
	Now = utime:unixtime(),
	case flop_check(RoleFlop, Now, Pos) of
		{true, flop_info_show} ->
			#role_dun_flop{treasure_id = TreasureId, flop_val = FlopVal, tmp_flop = #temp_flop{flop_time = EndTime}} = RoleFlop,
			#share_flop_treasure_cfg{flop_cost = Cost} = data_dungeon:get_share_flop_treasure(TreasureId),
		    {ok, BinData}  = pt_610:write(61047, [?SUCCESS, Pos, FlopVal, Cost, EndTime, 0, []]),
			lib_server_send:send_to_sid(Sid, BinData),
			ok;
		{true, FlopType, CostList} ->
			% ?ERR("flop_type ~p ~p", [FlopType, CostList]),
			if CostList == [] ->
					do_dun_flop(Pos, FlopType, Player);
				true ->
					case lib_goods_api:cost_object_list_with_check(Player, CostList, dungoen_flop, "dungeon_flop") of
						{true, NewPlayer,_} ->
							do_dun_flop(Pos, FlopType, NewPlayer);
						{false, Err, _} ->
							notice_flop_info(Err, Pos, 0, Player)
					end
			end;
		{false, ErrCode} -> %?ERR("~p", [ErrCode]),
			notice_flop_info(ErrCode, Pos, 0, Player)
	end.

%% 1全部免费开启|2额外开启一次|3全部开启
dun_batch_flop(DunType, Index, Player) ->
	#player_status{dungeon = StatusDungeon = #status_dungeon{flop = RoleFlop}} = Player,
	Now = utime:unixtime(),
	case batch_flop_check(RoleFlop, Now, Index) of
		{true, Cost} ->
			if Cost == [] ->
			 		{NewRoleFlop, Rewards, RewardRec, Reset} = do_dun_batch_flop(Index, DunType, RoleFlop),
			 		Rewards1 = lib_goods_util:merge_same_goods(Rewards),
			 		NewPlayer0 = lib_goods_api:send_reward(Player, Rewards1, dun_batch_sweep),
			 		NewStatusDungeon = StatusDungeon#status_dungeon{flop = NewRoleFlop},
			 		db_update_flop(NewStatusDungeon),
			 		NewPlayer = NewPlayer0#player_status{dungeon = NewStatusDungeon},
			 		notice_batch_flop_action(?SUCCESS, Index, Reset, RewardRec, NewPlayer),
			 		{ok, NewPlayer};
			 	true ->
			 		case lib_goods_api:cost_object_list_with_check(Player, Cost, dun_batch_flop_cost, "") of
			 			{true, NewPlayer, _} ->
			 				{NewRoleFlop, Rewards, RewardRec, Reset} = do_dun_batch_flop(Index, DunType, RoleFlop),
			 				Rewards1 = lib_goods_util:merge_same_goods(Rewards),
			 				NewPlayer0 = lib_goods_api:send_reward(NewPlayer, Rewards1, dun_cost_batch_sweep_reward),
			 				NewStatusDungeon = StatusDungeon#status_dungeon{flop = NewRoleFlop},
			 				db_update_flop(NewStatusDungeon),
			 				NewPlayer1 = NewPlayer0#player_status{dungeon = NewStatusDungeon},
			 				notice_batch_flop_action(?SUCCESS, Index, Reset, RewardRec, NewPlayer1),
			 				{ok, NewPlayer1};
			 			{false, ErrCode, _} ->
			 				notice_batch_flop_action(ErrCode, Index, 0, [], Player),
			 				ok
			 		end
			end;
		{false, ErrCode} -> %?ERR("~p ~p ~p", [DunType, Index, ErrCode]),
			notice_batch_flop_action(ErrCode, Index, 0, [], Player),
			ok
	end.

do_dun_batch_flop(Index, _DunType, RoleFlop) ->
	#role_dun_flop{treasure_id = TreasureId, flop_val = FlopVal, treasured = Treasured, 
		tmp_flop = TempFlop} = RoleFlop,
	#temp_flop{flop_duns = FlopDuns, batch_rewarded = BatchRewarded, ref = Ref, reward = Rewarded} = TempFlop,
	util:cancel_timer(Ref),
	Reset = 0,
	% ?ERR("before batch flop ~p ~p ~p ~p ~p ~p", [FlopDuns, FlopVal, TreasureId, Treasured, BatchRewarded, Index]),
	{NewFlopVal, NewTreasureId, NewTreasured, Rewards, Rewarded1, NewReset} = do_dun_batch_flop_loop(FlopDuns, FlopVal, TreasureId, Treasured, BatchRewarded, Index, Reset, [], []),
	% ?ERR("after batch flop ~p ~p ~p ~p", [NewFlopVal, NewTreasureId, NewTreasured, Rewarded1]),
	NewBatchRewarded = update_batchrewarded(Index, BatchRewarded),
	NewFlopCount = lists:max(NewBatchRewarded),
	NewRewarded = lists:append([Rewarded, Rewarded1]),
	% ?ERR("~p ~p", [NewBatchRewarded, NewFlopCount]),
	NewTempFlop = TempFlop#temp_flop{flop_count = NewFlopCount, reward = NewRewarded, batch_rewarded = NewBatchRewarded, ref = undefined},
	NewRoleFlop = RoleFlop#role_dun_flop{treasure_id = NewTreasureId, flop_val = NewFlopVal, treasured = NewTreasured, tmp_flop = NewTempFlop},
	{NewRoleFlop, Rewards, Rewarded1, NewReset}.

do_dun_batch_flop_loop([], FlopVal, TreasureId, Treasured, _BatchRewarded, _, Reset, Rewards, Rewarded) ->
	{FlopVal, TreasureId, Treasured, Rewards, Rewarded, Reset};
do_dun_batch_flop_loop([{DunId, Count}|Rest], FlopVal, TreasureId, Treasured, BatchRewarded, Index, Reset, TmpReward, Rewarded) ->
	#dun_cfg{flop_pools = FlopPools} = data_dungeon:get_dun(DunId),
	ExecuteSeq = calc_execute_count(Index, BatchRewarded, Count),
	{NewTreasureId, NewTreasured, NewFlopVal, NewTmpReward, NewRewarded, NewReset} = lists:foldl(fun(SeqIndex, {TmpTreasureId, TmpTreasured, TmpFlopVal, TmpReward1, TmpRewarded, TmpReset}) ->
			#share_flop_treasure_cfg{flop_cost = Cost} = data_dungeon:get_share_flop_treasure(TmpTreasureId),
			FlopType = calc_this_flop_type(Cost, FlopPools, TmpFlopVal),
			{RewardRecX, RewardsX} = get_flop_reward(FlopType, TmpTreasureId, TmpTreasured, DunId, SeqIndex, Index),
			if FlopType == ?FLOP_NORMAL -> 
					NewTmpFlopVal = TmpFlopVal + 1,
					NewTmpTreasureId = TmpTreasureId,
					NewTmpTreasured  = TmpTreasured,
					NewTmpReset = TmpReset,
					NewTmpRewarded = lists:append([RewardRecX, TmpRewarded]);
				true -> 
					NewTmpFlopVal = 0,
					[{_, _, _, [_, NewIndex|_]}|_] = RewardRecX,
					NewTmpReset = 1,
					{NewTmpTreasureId, NewTmpTreasured} = update_treasure_pool(TmpTreasureId, NewIndex, TmpTreasured),
					NewTmpRewarded = lists:append([RewardRecX, TmpRewarded])
			end,
			NewTmpReward1 = lists:append(RewardsX, TmpReward1),
			{NewTmpTreasureId, NewTmpTreasured, NewTmpFlopVal, NewTmpReward1, NewTmpRewarded, NewTmpReset}
	 end, {TreasureId, Treasured, FlopVal, TmpReward, Rewarded, Reset}, ExecuteSeq),

	do_dun_batch_flop_loop(Rest, NewFlopVal, NewTreasureId, NewTreasured, BatchRewarded, Index, NewReset, NewTmpReward, NewRewarded).


update_batchrewarded(Index, BatchRewarded) ->
	if Index == 1 -> %% 1
			update_batchrewarded_do(Index, BatchRewarded);
		Index < ?FLOP_MAX_COUNT -> %% 2
			PreIndex = Index - 1,
			NewBatchRewarded = update_batchrewarded_do(PreIndex, BatchRewarded),
			update_batchrewarded_do(Index, NewBatchRewarded);
		true -> %% 3
			PreIndex  = Index - 1,
			PreIndex1 = Index - 2,
			NewBatchRewarded  = update_batchrewarded_do(PreIndex, BatchRewarded),
			NewBatchRewarded1 = update_batchrewarded_do(PreIndex1, NewBatchRewarded),
			update_batchrewarded_do(Index, NewBatchRewarded1)
	end.

update_batchrewarded_do(Index, BatchRewarded) ->
	case lists:member(Index, BatchRewarded) of
		true ->
			BatchRewarded;
		_ ->
			[Index|BatchRewarded]
	end.

%% Index前面已检查,正常不小于1
calc_execute_count(Index, BatchRewarded, Count) ->
	if Index == 1 -> lists:duplicate(Count, Index);
		Index < ?FLOP_MAX_COUNT -> %% 2
			PreIndex = Index-1,
			case lists:member(PreIndex, BatchRewarded) of
				true ->
					lists:duplicate(Count, Index);
				_ ->
					Counts1 = lists:duplicate(Count, Index),
					Counts2 = lists:duplicate(Count, PreIndex),
					lists:append([Counts1, Counts2])
			end;
		true -> %% 3
			PreIndex  = Index - 2,
			PreIndex1 = Index - 1,
			%% 免费开启是否已使用
			PreIndexCounts = case lists:member(PreIndex, BatchRewarded) of
				true -> [];
				_ -> lists:duplicate(Count, PreIndex)
			end,
			%% 额外一次开启是否已使用
			PreIndexCounts1 = case lists:member(PreIndex1, BatchRewarded) of
				true -> [];
				_ -> lists:duplicate(Count, PreIndex1)
			end,
			IndexCounts = lists:duplicate(Count, Index),
			lists:append([PreIndexCounts, PreIndexCounts1, IndexCounts])
			% HaveUsed = Use1 + Use2,
			% CanUse = Index - HaveUsed,
			% round(CanUse*Count)
	end.
	% lists:duplicate(ExeCount, Index).	

calc_this_flop_type(Cost, FlopPools, FlopVal) ->
 	% ?ERR("~p ~p", [Cost, FlopVal]),
 	if FlopVal >= Cost -> %% 保底 
 			?FLOP_RARE;
 		true -> %% 未达保底随机
 			urand:rand_with_weight([{RandVal, TreasurePoolId} || {TreasurePoolId, RandVal} <- FlopPools])
 	end.

flop_check(RoleFlop, Now, Pos) ->
	#role_dun_flop{treasure_id = TreasureId, flop_val = FlopVal, tmp_flop = TempFlop} = RoleFlop,
	#temp_flop{flop_count = FlopCount, flop_time = EndTime, flop_dun_id = DunId, reward = Rewards} = TempFlop,
	FlopTreasureCfg = data_dungeon:get_share_flop_treasure(TreasureId),
	DunCfg 	= data_dungeon:get_dun(DunId),
	PosList = lists:seq(1, ?FLOP_MAX_COUNT),
	ValidPos = lists:member(Pos, PosList),
	FindResult = lists:keyfind(Pos, 2, Rewards),
	if
		DunId =< 0 ->
			{false, ?ERRCODE(err610_not_flop_times)};
		EndTime =< 0 orelse EndTime + 2 =< Now -> %?ERR("~p ~p", [EndTime, Now]),
			{false, ?ERRCODE(err610_flop_time_out)};
		FlopCount >= ?FLOP_MAX_COUNT ->
			{false, ?ERRCODE(err610_not_flop_times)};
		not is_record(DunCfg, dun_cfg) ->
			{false, ?ERRCODE(err153_goods_not_equal)};
		not is_record(FlopTreasureCfg, share_flop_treasure_cfg) ->
			{false, ?ERRCODE(err153_goods_not_equal)};
		Pos == 0 ->
			{true, flop_info_show};
		not ValidPos ->
			{false, ?ERRCODE(err610_not_flop_times)};
		FindResult =/= false -> %% 该位置已经翻过了
			{false, ?ERRCODE(err610_pos_repeated)};
		true ->
			#share_flop_treasure_cfg{flop_cost = Cost} = FlopTreasureCfg,
			#dun_cfg{flop_cost = FlopCost, flop_pools = FlopRandVal} = DunCfg,
			% ?ERR("rand flop type result ~p ~p", [TreasureId, FlopVal, Cost]),
			FlopType = if FlopVal >= Cost -> %% 本次保底条件达到
					?FLOP_RARE;
				true ->
					case urand:rand_with_weight([{RandVal, TreasurePoolId} || {TreasurePoolId, RandVal} <- FlopRandVal]) of
						FlopRandType when is_integer(FlopRandType) ->
							FlopRandType;
						_ ->
							false
					end
			end,
			if is_integer(FlopType) ->
					case lists:keyfind(FlopCount+1, 1, FlopCost) of
						{_, GoodsType, GoodsId, GoodsNum} when GoodsNum =/= 0 ->
							CostList = [{GoodsType, GoodsId, GoodsNum}];
						_ ->
							CostList = []
					end,
					{true, FlopType, CostList};
				true ->
					{false, ?ERRCODE(err177_data_no_exist)}
			end
	end.

batch_flop_check(RoleFlop, Now, Index) ->
	#role_dun_flop{treasure_id = TreasureId, tmp_flop = TempFlop} = RoleFlop,
	#temp_flop{batch_rewarded = BatchRewarded, flop_duns = FlopDuns, flop_time = FlopTime, flop_dun_type = FlopDunType} = TempFlop,
	FlopTreasureCfg = data_dungeon:get_share_flop_treasure(TreasureId),
	IsRewarded = lists:member(Index, BatchRewarded),
	if
		FlopTime =< 0 orelse FlopTime + 2 =< Now ->
			{false, ?ERRCODE(err610_flop_time_out)};
		not is_record(FlopTreasureCfg, share_flop_treasure_cfg) ->
			{false, ?ERRCODE(err153_goods_not_equal)};
		FlopDunType == 0 orelse FlopDuns == [] ->
			{false, ?ERRCODE(err610_dun_type_error)};
		Index == 0 ->
			{false, ?ERRCODE(err153_goods_not_equal)};
		IsRewarded ->
			{false, ?ERRCODE(err610_dun_flop_have_opened)};
		true ->
			MoneyCost = calc_batch_flop_cost(Index, BatchRewarded, FlopDuns),
			% ?ERR("cost ~p", [MoneyCost]),
			if Index == 1 andalso MoneyCost == 0 ->
					{true, []};
				true ->
					if MoneyCost == 0 ->
							{false, ?ERRCODE(data_error)};
						true ->
							{true, [{?TYPE_GOLD, 0, MoneyCost}]}
					end
			end
	end.

calc_batch_flop_cost(Index, BatchRewarded, FlopDuns) ->
	IsValidIndex = lists:member(Index, lists:seq(1, ?FLOP_MAX_COUNT)),
	if Index == 0 ->
			[];
		not IsValidIndex ->
			{false, ?ERRCODE(err153_goods_not_equal)};
		true ->
			lists:foldl(fun({DunId, Count}, Acc) ->
				case data_dungeon:get_dun(DunId) of
					#dun_cfg{flop_cost = FlopCost} ->
					 	NewAcc = case lists:keyfind(Index, 1, FlopCost) of
							{_, _, _, Num} -> round(Acc + Count*Num);
							_ -> Acc
						end,
						if Index == ?FLOP_MAX_COUNT ->
								case lists:member(Index-1, BatchRewarded) of
									true -> NewAcc;
									_ ->
										case lists:keyfind(Index-1, 1, FlopCost) of
											{_, _, _, Num1} -> round(NewAcc + Count*Num1);
											_ -> NewAcc
										end
								end;
							true -> NewAcc
						end;
					_ ->
						Acc
				end
			 end, 0, FlopDuns)
	end.

force_action_check(DunId, TempFlop) ->
	case TempFlop of
		#temp_flop{flop_count = FlopCount, flop_dun_id = DunId1} ->
			case DunId1 > 0 andalso DunId == DunId andalso FlopCount == 0 of
				true -> true;
				_ 	 -> false
			end;
		_ ->
			false
	end.

force_batch_action_check(DunType, TempFlop) ->
	#temp_flop{flop_count = FlopCount, flop_dun_type = DunType1, flop_duns = FlopDuns} = TempFlop,
	case DunType1 == DunType andalso FlopDuns =/= [] andalso FlopCount == 0 of
		true -> true;
		_ 	 -> false
	end.

do_dun_flop(Pos, FlopType, Player) ->
	#player_status{dungeon = StatusDungeon} = Player,
	#status_dungeon{flop = RoleFlop} = StatusDungeon,
	#role_dun_flop{
		treasure_id = TreasureId,
		treasured 	= Treasured,
		tmp_flop 	= #temp_flop{flop_count = OldCount, flop_dun_id = DunId, ref = Ref}
	} = RoleFlop,
	%% 取消强制免费翻牌定时器
	util:cancel_timer(Ref),
	%% 计算奖励
	{TmpReward, Reward} = get_flop_reward(FlopType, TreasureId, Treasured, DunId, OldCount+1, Pos),
	% ?ERR("~p ~p", [OldCount+1, Reward]),
	%% 发奖励
	NewPlayer = lib_goods_api:send_reward(Player, Reward, dun_flop_reward),
	%% 更新翻牌数据
	NewRoleFlop = update_temp_flop(FlopType, TmpReward, RoleFlop),
	% ?ERR("~p", [NewRoleFlop]),
	NewPlayer1 = NewPlayer#player_status{dungeon = StatusDungeon#status_dungeon{flop = NewRoleFlop}},
	db_update_flop(StatusDungeon#status_dungeon{flop = NewRoleFlop}),
	Reset = ?IF(FlopType == ?FLOP_RARE, 1, 0),
	notice_flop_info(?SUCCESS, Pos, Reset, NewPlayer1),
	{ok, NewPlayer1}.

%% 获取翻牌奖励
get_flop_reward(_FlopType = ?FLOP_NORMAL, _TreasureId, _Treasured, DunId, Count, Pos) ->
	#dun_cfg{flop_rewards = FlopGoods, flop_times = FlopTimes} = data_dungeon:get_dun(DunId),
	{GoodsType, GoodsId, Num} = urand:rand_with_weight(FlopGoods),
 	Times = calc_goods_times(Count, FlopTimes),
 	% ?ERR("rand reward ~p ~p ~p", [OldCount+1, Times, Num]),
	RewardList = multi_time_reward(Times, [{GoodsType, GoodsId, Num}]),
	TmpReward = [{{DunId, Count}, Pos, ?FLOP_NORMAL, [RewardList]++[Times]}],
	{TmpReward, RewardList};
get_flop_reward(_FlopType = ?FLOP_RARE, TreasureId, Treasured, DunId, Count, Pos) ->
	% #dun_cfg{flop_times = FlopTimes} = data_dungeon:get_dun(DunId),
	#share_flop_treasure_cfg{treasure = TreasurePool} = data_dungeon:get_share_flop_treasure(TreasureId),
	case lists:keyfind(TreasureId, 1, Treasured) of
		{_, HaveTreasuredIndex} -> ok;
		_ -> HaveTreasuredIndex = []
	end,
	%% 排除奖池中已抽的奖项
	TreasurePool1 = lists:filter(fun({Index, _GoodsList, _RandVal}) ->
		lists:member(Index, HaveTreasuredIndex) =/= true
	 end, TreasurePool),
	TreasurePool2 = [{RandVal1, {Index1, GoodsListX}} || {Index1, GoodsListX, RandVal1} <- TreasurePool1],
	{RandIndex, RandGoodsList} = urand:rand_with_weight(TreasurePool2),
	% Times = calc_goods_times(OldCount+1, FlopTimes),
	% RewardList = multi_time_reward(Times, RandGoodsList),
	RewardList = RandGoodsList,
	% ?ERR("rand reward ~p ~p ~p", [OldCount+1, Times, RandGoodsList]),
	TmpReward = [{{DunId, Count}, Pos, ?FLOP_RARE, [TreasureId, RandIndex]}],
	{TmpReward, RewardList}.

%% 随机物品倍率
calc_goods_times(Count, FlopTimes) ->
	case lists:keyfind(Count, 1, FlopTimes) of
		{_, RandTimes} ->
			Times = urand:rand_with_weight(RandTimes);
		_ ->
			Times = 1
	end,
	Times.

multi_time_reward(Times, GoodsList) ->
	[{GoodsType, GoodsId, round(Num*Times)}|| {GoodsType, GoodsId, Num} <- GoodsList].

%% 更新人物的翻牌数据
update_temp_flop(_FlopType = ?FLOP_NORMAL, [{{_DunId, NewCount}, _, _, _} = TmpReward|_], RoleFlop) ->
	#role_dun_flop{flop_val = FlopVal, tmp_flop = TempFlop} = RoleFlop,
	#temp_flop{flop_count = OldCount, reward = Reward} = TempFlop,
	NewReward = lists:keystore(NewCount, 1, Reward, TmpReward),
	NewTempFlop = TempFlop#temp_flop{flop_count = OldCount+1, reward = NewReward},
	NewRoleFlop = RoleFlop#role_dun_flop{flop_val = FlopVal+1, tmp_flop = NewTempFlop},
	NewRoleFlop;
update_temp_flop(_FlopType = ?FLOP_RARE, [{{_DunId, NewCount}, _, _, [TreasureId, NewIndex|_]} = TmpReward|_], RoleFlop) ->
	#role_dun_flop{treasured = Treasured, tmp_flop = TempFlop} = RoleFlop,
	#temp_flop{flop_count = OldCount, reward = Reward} = TempFlop,
	{NewTreasureId, NewTreasured} = update_treasure_pool(TreasureId, NewIndex, Treasured),
	NewReward = lists:keystore(NewCount, 1, Reward, TmpReward),
	NewTempFlop = TempFlop#temp_flop{flop_count = OldCount+1, reward = NewReward},
	NewRoleFlop = RoleFlop#role_dun_flop{
		flop_val 	= 0, %% 抽到稀有翻牌重置祝福值
		treasure_id = NewTreasureId,
		treasured 	= NewTreasured,
		tmp_flop 	= NewTempFlop},
	NewRoleFlop.


%% 稀有抽奖不返回
%% 当奖池抽尽时奖池id+1,若无下一个奖池则沿用当前奖池id
update_treasure_pool(TreasureId, NewIndex, Treasured) ->
	NewTreasured = case lists:keyfind(TreasureId, 1, Treasured) of
		{_, HaveTreasuredIndex} ->
			lists:keystore(TreasureId, 1, Treasured, {TreasureId, [NewIndex|HaveTreasuredIndex]});
		_ ->
			lists:keystore(TreasureId, 1, Treasured, {TreasureId, [NewIndex]})
	end,
	#share_flop_treasure_cfg{treasure = Treasures} = data_dungeon:get_share_flop_treasure(TreasureId),
	TreasureIndex = [Index1|| {Index1, _, _} <- Treasures],
	{_, NewHaveTreasureIndex} = lists:keyfind(TreasureId, 1, NewTreasured),
	Len1 = length(TreasureIndex),
	Len2 = length(NewHaveTreasureIndex),
	if Len2 >= Len1 ->
			NewTreasureId = TreasureId+1,
			case data_dungeon:get_share_flop_treasure(NewTreasureId) of
				#share_flop_treasure_cfg{} ->
					{NewTreasureId, []};
				_ ->
					{TreasureId, []}
			end;
		true ->
			{TreasureId, NewTreasured}
	end.

%% 玩家下线
handle_event(PS, #event_callback{type_id = ?EVENT_DISCONNECT}) when is_record(PS, player_status) ->
    #player_status{dungeon = #status_dungeon{flop = Flop}} = PS,
    Now = utime:unixtime(),
    case Flop of
   		#role_dun_flop{tmp_flop = #temp_flop{flop_kind = ?NORMAL_FLOP, flop_dun_id = DunId, flop_count = FlopCount, flop_time = FlopTime}} ->
		   	case DunId > 0 andalso Now =< FlopTime + 2 andalso FlopCount == 0 of
   				true ->
		   			case dun_flop(_Pos = 1, PS) of
		   				{ok, NewPS} -> {ok, NewPS};
		   				_           -> {ok, PS}
		   			end;
		   		false ->
		   			{ok, PS}
		   	end;
		#role_dun_flop{tmp_flop = #temp_flop{flop_kind = ?BATCH_FLOP, flop_count = FlopCount, flop_dun_type = DunType}} ->
			case DunType > 0  andalso FlopCount == 0 of
				true -> %?ERR("~p", [DunType]),
					case dun_batch_flop(_Index = 1, DunType, PS) of
						{ok, NewPS} -> {ok, NewPS};
						_ 			-> {ok, PS}
					end;
				false ->
					{ok, PS}
			end;
		_ ->
			{ok, PS}
	end;
handle_event(PS, _EventCallback) ->
    {ok, PS}.
