package fishing

import (
	"math"
	"mongo.games.com/game/common"
	"mongo.games.com/game/gamerule/fishing"
	"mongo.games.com/game/gamesrv/base"
	"mongo.games.com/game/proto"
	fishing_proto "mongo.games.com/game/protocol/fishing"
	"mongo.games.com/goserver/core"
	"mongo.games.com/goserver/core/timer"
	"time"
)

var ScenePolicyFishingSington = &ScenePolicyFishing{}

type ScenePolicyFishing struct {
	base.BaseScenePolicy
	states [FishingSceneStateMax]base.SceneState
}

func (this *ScenePolicyFishing) CreateSceneExData(s *base.Scene) interface{} {
	sceneEx := NewFishingSceneData(s)
	if sceneEx != nil {
		if sceneEx.init() {
			s.SetExtraData(sceneEx)
		}
	}
	return sceneEx
}

func (this *ScenePolicyFishing) CreatePlayerExData(s *base.Scene, p *base.Player) interface{} {
	playerEx := &FishingPlayerData{Player: p}
	if playerEx != nil {
		p.SetExtraData(playerEx)
	}
	return playerEx
}

func (this *ScenePolicyFishing) OnStart(s *base.Scene) {
	fishlogger.Trace("(this *ScenePolicyFishing) OnStart, sceneId=", s.GetSceneId())
	sceneEx := NewFishingSceneData(s) // 初始化当前场景的数据接口
	if sceneEx != nil {
		if sceneEx.init() {
			s.SetExtraData(sceneEx)
			s.ChangeSceneState(FishingSceneStateStart)
		}
	}
}

func (this *ScenePolicyFishing) OnTick(s *base.Scene) {
	if s == nil {
		return
	}
	if s.GetSceneState() != nil {
		s.GetSceneState().OnTick(s)
	}
}

func (this *ScenePolicyFishing) GetPlayerNum(s *base.Scene) int32 {
	if s == nil {
		return 0
	}
	if sceneEx, ok := s.GetExtraData().(*FishingSceneData); ok {
		return int32(len(sceneEx.players))
	}
	return 0
}

func (this *ScenePolicyFishing) OnPlayerEnter(s *base.Scene, p *base.Player) {
	if s == nil || p == nil {
		return
	}
	fishlogger.Trace("(this *ScenePolicyFishing) OnPlayerEnter, sceneId=", s.GetSceneId(), " player=", p.SnId)
	if sceneEx, ok := s.GetExtraData().(*FishingSceneData); ok {
		sceneEx.SetGameNowTime(time.Now())
		playerEx := &FishingPlayerData{Player: p}
		playerEx.init(s)
		playerEx.taxCoin = 0
		playerEx.sTaxCoin = 0
		playerEx.winCoin = 0
		playerEx.enterTime = time.Now()
		sceneEx.EnterPlayer(playerEx)
		s.FirePlayerEvent(p, base.PlayerEventEnter, nil)
	}
}

func (this *ScenePolicyFishing) OnPlayerLeave(s *base.Scene, p *base.Player, reason int) {
	if s == nil || p == nil {
		return
	}
	fishlogger.Trace("(this *ScenePolicyFishing) OnPlayerLeave, sceneId=", s.GetSceneId(), " player=", p.Name)
	if sceneEx, ok := s.GetExtraData().(*FishingSceneData); ok {
		if this.CanChangeCoinScene(s, p) {
			if playerEx, ok := p.GetExtraData().(*FishingPlayerData); ok {
				playerEx.SaveDetailedLog(s)
				sceneEx.QuitPlayer(playerEx, reason)
				s.FirePlayerEvent(p, base.PlayerEventLeave, []int64{int64(reason)})
				if playerEx.GetCurrentCoin() == 0 {
					playerEx.SetCurrentCoin(playerEx.GetTakeCoin())
				}
				playerEx.SaveSceneCoinLog(playerEx.GetCurrentCoin(), int64(playerEx.CoinCache-playerEx.GetCurrentCoin()),
					playerEx.GetCoin(), 0, int64(math.Floor(playerEx.taxCoin+0.5)), playerEx.winCoin, 0, 0)
				playerEx.SetCurrentCoin(playerEx.GetCoin())
			}
		}
		//检测房间人数
		if len(sceneEx.players) == 0 {
			sceneEx.Stop()
		}
	}
}

func (this *ScenePolicyFishing) OnPlayerDropLine(s *base.Scene, p *base.Player) {
	if s == nil || p == nil {
		return
	}
	fishlogger.Trace("(this *ScenePolicyFishing) OnPlayerDropLine, sceneId=", s.GetSceneId(), " player=", p.Name)
	s.FirePlayerEvent(p, base.PlayerEventDropLine, nil)
	if _, ok := s.GetExtraData().(*FishingSceneData); ok {
		if _, ok := p.GetExtraData().(*FishingPlayerData); ok {
		}
	}
}

func (this *ScenePolicyFishing) OnPlayerRehold(s *base.Scene, p *base.Player) {
	if s == nil || p == nil {
		return
	}
	fishlogger.Trace("(this *ScenePolicyFishing) OnPlayerRehold, sceneId=", s.GetSceneId(), " player=", p.SnId)
	if _, ok := s.GetExtraData().(*FishingSceneData); ok {
		if _, ok := p.GetExtraData().(*FishingPlayerData); ok {
			s.FirePlayerEvent(p, base.PlayerEventRehold, nil)
		}
	}
}

func (this *ScenePolicyFishing) OnPlayerReturn(s *base.Scene, p *base.Player) {
	if s == nil || p == nil {
		return
	}
	fishlogger.Trace("(this *ScenePolicyFishing) OnPlayerReturn, sceneId=", s.GetSceneId(), " player=", p.SnId)
	if _, ok := s.GetExtraData().(*FishingSceneData); ok {
		if _, ok := p.GetExtraData().(*FishingPlayerData); ok {
			s.FirePlayerEvent(p, base.PlayerEventReturn, nil)
		}
	}
}

func (this *ScenePolicyFishing) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool {
	if s == nil || p == nil {
		return false
	}
	if s.GetSceneState() != nil {
		return s.GetSceneState().OnPlayerOp(s, p, opcode, params)
	}
	return true
}

func (this *ScenePolicyFishing) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) {
	if s == nil || p == nil {
		return
	}
	if s.GetSceneState() != nil {
		s.GetSceneState().OnPlayerEvent(s, p, evtcode, params)
	}
}

func (this *ScenePolicyFishing) IsCompleted(s *base.Scene) bool     { return false }
func (this *ScenePolicyFishing) IsCanForceStart(s *base.Scene) bool { return true }
func (this *ScenePolicyFishing) CanChangeCoinScene(s *base.Scene, p *base.Player) bool {
	if s == nil || p == nil {
		return true
	}
	if s.GetSceneState() != nil {
		return s.GetSceneState().CanChangeCoinScene(s, p)
	}
	return true
}

func FishingSendRoomInfo(p *base.Player, sceneEx *FishingSceneData) {
	pack := &fishing_proto.SCFishingRoomInfo{
		RoomId:        proto.Int(sceneEx.GetSceneId()),
		Creator:       proto.Int32(sceneEx.GetCreator()),
		GameId:        proto.Int(sceneEx.gameId),
		RoomMode:      proto.Int(sceneEx.sceneMode),
		AgentId:       proto.Int32(sceneEx.agentor),
		SceneType:     proto.Int(sceneEx.sceneType),
		Params:        sceneEx.GetParams(),
		NumOfGames:    proto.Int(sceneEx.GetNumOfGames()),
		State:         proto.Int(sceneEx.GetSceneState().GetState()),
		TimeOut:       proto.Int(sceneEx.GetSceneState().GetTimeout(sceneEx.Scene)),
		DisbandGen:    proto.Int(sceneEx.GetDisbandGen()),
		GameFreeId:    proto.Int32(sceneEx.gamefreeId),
		FrozenTick:    proto.Int32(sceneEx.frozenTick),
		MinPower:      proto.Int32(sceneEx.GetDBGameFree().GetIntuseCannonMin()),
		MaxPower:      proto.Int32(sceneEx.GetDBGameFree().GetIntuseCannonMax()),
		PowerList:     sceneEx.GetDBGameFree().GetOtherIntParams(),
		ChangeSceneId: proto.Int32(sceneEx.ChangeSceneId),
	}
	for _, pp := range sceneEx.players {
		pd := &fishing_proto.FishingPlayerData{
			SnId:        proto.Int32(pp.SnId),
			Name:        proto.String(pp.Name),
			Head:        proto.Int32(pp.Head),
			Sex:         proto.Int32(pp.Sex),
			Coin:        proto.Int64(pp.CoinCache),
			Pos:         proto.Int(pp.GetPos()),
			Flag:        proto.Int(pp.GetFlag()),
			City:        proto.String(pp.GetCity()),
			Params:      proto.String(pp.Params),
			HeadOutLine: proto.Int32(pp.HeadOutLine),
			VIP:         proto.Int32(pp.VIP),
			SelVip:      proto.Int32(pp.SelVip),
			Power:       proto.Int32(pp.power),
			AgentParam:  proto.Int32(pp.AgentParam),
			TargetSel:   proto.Int32(pp.SelTarget),
			AutoFishing: proto.Int32(pp.AutoFishing),
			FireRate:    proto.Int32(pp.FireRate),
			IsRobot:     proto.Bool(pp.IsRob),
			NiceId:      proto.Int32(pp.NiceId),
			UnMaxPower:  proto.Int64(pp.UnMaxPower),
			UnPowerList: pp.PowerList,
			FishLevel:   proto.Int64(pp.FishLevel),
			FishExp:     proto.Int64(pp.FishExp),
		}
		for _, v := range pp.RobotSnIds {
			pd.RobotSnIds = append(pd.RobotSnIds, v)
		}
		pack.Players = append(pack.Players, pd)
	}
	proto.SetDefaults(pack)
	p.SendToClient(int(fishing_proto.FIPacketID_FISHING_SC_ROOMINFO), pack)
}

type SceneBaseStateFishing struct {
	base.BaseScenePolicy
}

func (this *SceneBaseStateFishing) GetTimeout(s *base.Scene) int {
	if sceneEx, ok := s.GetExtraData().(*FishingSceneData); ok {
		return int(time.Now().Sub(sceneEx.GetStateStartTime()) / time.Second)
	}
	return 0
}

func (this *SceneBaseStateFishing) CanChangeTo(s base.SceneState) bool {
	return true
}

func (this *SceneBaseStateFishing) CanChangeCoinScene(s *base.Scene, p *base.Player) bool {
	if _, ok := p.GetExtraData().(*FishingPlayerData); ok {
		return true
	}
	return true
}

func (this *SceneBaseStateFishing) OnEnter(s *base.Scene) {
	if sceneEx, ok := s.GetExtraData().(*FishingSceneData); ok {
		sceneEx.SetStateStartTime(time.Now())
	}
}

func (this *SceneBaseStateFishing) OnLeave(s *base.Scene) {}
func (this *SceneBaseStateFishing) OnTick(s *base.Scene) {
	//玩家超时5分钟未发炮 踢出房间
	if sceneEx, ok := s.GetExtraData().(*FishingSceneData); ok {
		for _, p := range sceneEx.players {
			if time.Now().Sub(p.LastFireTime) > PlayerLongTimeNoOp {
				sceneEx.PlayerLeave(p.Player, common.PlayerLeaveReason_LongTimeNoOp, true)
				fishlogger.Tracef("玩家超过5分钟未开炮，踢出房间！snid = %v", p.SnId)
			}

		}
	}

}

func (this *SceneBaseStateFishing) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool {
	if playerEx, ok := p.GetExtraData().(*FishingPlayerData); ok {
		if sceneEx, ok := s.GetExtraData().(*FishingSceneData); ok {
			// start  检测当前房间是否处于基本的关闭状态
			if s.CheckNeedDestroy() {
				if sceneEx.hDestroy == timer.InvalidTimerHandle {
					if hNext, ok := common.DelayInvake(func() {
						sceneEx.hDestroy = timer.InvalidTimerHandle
						sceneEx.SceneDestroy(true)
					}, nil, time.Second*10, 1); ok {
						sceneEx.hDestroy = hNext
					}
				}
				//
				if opcode == FishingPlayerOpFire || opcode == FishingPlayerOpRobotFire { //房间开始关闭，拦截掉发炮数据
					return true
				}
			}
			// end
			switch opcode {
			case FishingPlayerOpFire:
				// 真人玩家的开火倍数
				if len(params) >= 4 {
					opRetCode := sceneEx.PushBullet(playerEx.SnId, int32(params[0]), int32(params[1]),
						int32(params[2]), int32(params[3]), int32(params[4]), int32(params[5]))
					// start  异常处理的时候 发统一的 处理逻辑
					if opRetCode == fishing_proto.OpResultCode_OPRC_CoinNotEnough {
						this.OnPlayerSToCOp(s, p, opcode, opRetCode, params)
					}
					// end
				}
			case FishingPlayerOpRobotFire:
				if len(params) >= 5 {
					robotPlayer := sceneEx.GetPlayer(int32(params[0]))
					if robotPlayer != nil && robotPlayer.IsRob == true && p.IsRob == false {
						opRetCode := sceneEx.PushBullet(robotPlayer.SnId, int32(params[1]), int32(params[2]),
							int32(params[3]), int32(params[4]), int32(params[4]), int32(params[5]))
						if opRetCode == fishing_proto.OpResultCode_OPRC_CoinNotEnough {
							//sceneEx.PlayerLeave(robotPlayer, common.PlayerLeaveReason_Bekickout, true)
							if !robotPlayer.IsMarkFlag(base.PlayerState_GameBreak) {
								robotPlayer.MarkFlag(base.PlayerState_GameBreak)
								sceneEx.SCRobotBehavior(p.SnId, robotPlayer.SnId, FishingRobotBehaviorCode_StopFire)
								this.OnPlayerSToCOp(s, robotPlayer, opcode, opRetCode, params)
							}
						}
						if robotPlayerEx, ok := robotPlayer.GetExtraData().(*FishingPlayerData); ok {
							fishlogger.Tracef("playerId  snid %v  robotPlayer sid %v snid %v  coin %v  name %v leaveCoin %v ", p.SnId, robotPlayer.GetSid(), robotPlayer.SnId, robotPlayerEx.CoinCache, robotPlayer.Name, robotPlayer.ExpectLeaveCoin)
							if robotPlayerEx.CoinCheck(robotPlayerEx.power) == false {
								//sceneEx.PlayerLeave(robotPlayerEx.Player, common.PlayerLeaveReason_Bekickout, true)
								fishlogger.Tracef("robotId  sid %v snid %v CoinCheck ", robotPlayer.GetSid(), robotPlayerEx.SnId)
								if !robotPlayer.IsMarkFlag(base.PlayerState_GameBreak) {
									robotPlayer.MarkFlag(base.PlayerState_GameBreak)
									sceneEx.SCRobotBehavior(p.SnId, robotPlayer.SnId, FishingRobotBehaviorCode_StopFire)
									this.OnPlayerSToCOp(s, robotPlayer, opcode, opRetCode, params)
								}
							}
							if !s.CoinInLimit(robotPlayerEx.CoinCache) {
								//sceneEx.PlayerLeave(robotPlayerEx.Player, common.PlayerLeaveReason_Bekickout, true)
								fishlogger.Tracef("robotId  sid %v snid %v CoinInLimit ", robotPlayer.GetSid(), robotPlayerEx.SnId)
								if !robotPlayer.IsMarkFlag(base.PlayerState_GameBreak) {
									robotPlayer.MarkFlag(base.PlayerState_GameBreak)
									sceneEx.SCRobotBehavior(p.SnId, robotPlayer.SnId, FishingRobotBehaviorCode_StopFire)
									this.OnPlayerSToCOp(s, robotPlayer, opcode, opRetCode, params)
								}
							}
							if s.CoinOverMaxLimit(robotPlayerEx.CoinCache, robotPlayer) {
								//sceneEx.PlayerLeave(robotPlayerEx.Player, common.PlayerLeaveReason_Normal, true)
								fishlogger.Tracef("robotId  sid %v snid %v CoinOverMaxLimit ", robotPlayer.GetSid(), robotPlayerEx.SnId)
								if !robotPlayer.IsMarkFlag(base.PlayerState_GameBreak) {
									robotPlayer.MarkFlag(base.PlayerState_GameBreak)
									sceneEx.SCRobotBehavior(p.SnId, robotPlayer.SnId, FishingRobotBehaviorCode_StopFire)
									this.OnPlayerSToCOp(s, robotPlayer, opcode, opRetCode, params)
								}
							}
						}
					}
				}
			case FishingPlayerOpHitFish:
				if len(params) >= 2 {
					fishId := []int32{int32(params[1])}
					extfishis := []int32{}
					for i := 2; i < len(params); i++ {
						extfishis = append(extfishis, int32(params[i]))
					}
					sceneEx.PushBattle(playerEx, int32(params[0]), fishId, extfishis)
				}
			case FishingPlayerOpRobotHitFish:
				if len(params) >= 3 {
					robotPlayer := sceneEx.GetPlayer(int32(params[0]))
					if robotPlayer != nil && robotPlayer.IsRob == true && p.IsRob == false {
						fishId := []int32{int32(params[2])}
						extfishis := []int32{}
						for i := 3; i < len(params); i++ {
							extfishis = append(extfishis, int32(params[i]))
						}
						if robotPlayerEx, ok := robotPlayer.GetExtraData().(*FishingPlayerData); ok {
							sceneEx.PushBattle(robotPlayerEx, int32(params[1]), fishId, extfishis)
						}
					}
				}
			case FishingPlayerOpSetPower:
				if len(params) >= 1 {
					fishlogger.Tracef("%v set power to %v.", playerEx.SnId, params[0])
					powers := sceneEx.GetDBGameFree().GetOtherIntParams() // power的配置信息
					// 当前如果是免费炮时期，后端直接屏蔽协议
					if playerEx.powerType == FreePowerType {
						fishlogger.Tracef("player %v 正处于免费炮阶段.", playerEx.SnId)
						return true
					}
					int32Slice := make([]int32, len(powers))
					for i, v := range powers {
						int32Slice[i] = int32(v)
					}
					if common.InSliceInt32(int32Slice, int32(params[0])) {
						playerEx.power = int32(params[0])
					} else {
						fishlogger.Errorf("Can't not switch power to %v.", params[0])
						fishlogger.Errorf("%v scene power list:%v.", sceneEx.gamefreeId, powers)
					}
					pack := &fishing_proto.SCFirePower{
						Snid:  proto.Int32(playerEx.SnId),
						Power: proto.Int32(playerEx.power),
					}

					if playerEx.IsRobot() && len(params) >= 2 {
						pack.TargetPower = proto.Int32(int32(params[1]))
						pack.RobitFire = proto.Bool(int32(params[1]) == playerEx.power)
					}
					sceneEx.BroadCastMessage(int(fishing_proto.FIPacketID_FISHING_SC_FIREPOWER), pack, 0)
					if playerEx.IsRobot() {
						fishlogger.Tracef("机器人%v设置倍率：当前倍率%v 目标倍率%v 能否发泡%v:", playerEx.SnId, playerEx.power, params[1], pack.RobitFire)
					}
					fishlogger.Trace("SCFirePower:", pack)
					if playerEx.IsRob {
						if playerEx.CoinCheck(playerEx.power) == false {
							sceneEx.PlayerLeave(playerEx.Player, common.PlayerLeaveReason_Bekickout, true)
						}
					}
				}
			case FishingRobotOpSetPower:
				if len(params) >= 2 {
					robotPlayer := sceneEx.GetPlayer(int32(params[0]))
					if robotPlayer != nil && robotPlayer.IsRob == true && p.IsRob == false {
						if robotPlayerEx, ok := robotPlayer.GetExtraData().(*FishingPlayerData); ok {
							fishlogger.Tracef("RobotID %v set power to %v.", params[0], params[1])
							powers := sceneEx.GetDBGameFree().GetOtherIntParams() // power的配置信息
							int32Slice := make([]int32, len(powers))
							for i, v := range powers {
								int32Slice[i] = int32(v)
							}
							if common.InSliceInt32(int32Slice, int32(params[1])) {
								robotPlayerEx.power = int32(params[1])
							} else {
								fishlogger.Errorf("Can't not switch power to %v.", params[0])
								fishlogger.Errorf("%v scene power list:%v.", sceneEx.gamefreeId, powers)
							}
							pack := &fishing_proto.SCFirePower{
								Snid:  proto.Int32(robotPlayerEx.SnId),
								Power: proto.Int32(robotPlayerEx.power),
							}
							sceneEx.BroadCastMessage(int(fishing_proto.FIPacketID_FISHING_SC_FIREPOWER), pack, 0)
						}
					}
				}

			case FishingPlayerOpSelVip:
				if len(params) > 0 {
					//if p.VIP >= int32(params[0]) {
					playerEx.SelVip = int32(params[0])
					pack := &fishing_proto.SCSelVip{
						Snid: proto.Int32(playerEx.SnId),
						Vip:  proto.Int32(playerEx.SelVip),
					}
					sceneEx.BroadCastMessage(int(fishing_proto.FIPacketID_FISHING_SC_SELVIP), pack, 0)
					//}
				}
			case FishingPlayerOpLeave:
				if playerEx.AgentParam != 0 {
					robot := base.PlayerMgrSington.GetPlayerBySnId(playerEx.AgentParam)
					if robot != nil {
						sceneEx.PlayerLeave(robot, common.PlayerLeaveReason_Bekickout, true)
					}
				}
				/*			case FishingPlayerOpAuto:
							{
								if len(params) > 0 {
									playerEx.AutoFishing = int32(params[0])
									this.OnPlayerSToCOp(s, p, opcode, fishing_proto.OpResultCode_OPRC_Sucess, params)
								}
							}*/
				/*			case FishingPlayerOpSelTarget:
							{
								if len(params) > 0 {
									playerEx.SelTarget = int32(params[0])
									pack := &fishing_proto.SCFishingOp{
										OpCode:    proto.Int(opcode),
										Params:    params,
										OpRetCode: fishing_proto.OpResultCode_OPRC_Sucess,
										SnId:      proto.Int32(playerEx.SnId),
									}
									proto.SetDefaults(pack)
									sceneEx.BroadCastMessage(int(fishing_proto.FIPacketID_FISHING_SC_OP), pack, 0)
								}
							}*/
				/*			case FishingPlayerOpFireRate:
							{
								if len(params) > 0 {
									playerEx.FireRate = int32(params[0])
									pack := &fishing_proto.SCFishingOp{
										OpCode:    proto.Int(opcode),
										Params:    params,
										OpRetCode: fishing_proto.OpResultCode_OPRC_Sucess,
										SnId:      proto.Int32(playerEx.SnId),
									}
									proto.SetDefaults(pack)
									sceneEx.BroadCastMessage(int(fishing_proto.FIPacketID_FISHING_SC_OP), pack, 0)
								}
							}*/
			case FishingPlayerHangup:
				{
					//客户端辅助,原路返回
					this.OnPlayerSToCOp(s, p, opcode, fishing_proto.OpResultCode_OPRC_Sucess, params)
				}
			case FishingRobotWantLeave:
				{
					//机器人想要离开
					if len(params) >= 1 {
						robotPlayer := sceneEx.GetPlayer(int32(params[0]))
						if robotPlayer != nil && robotPlayer.IsRob == true && p.IsRob == false {
							this.OnPlayerSToCOp(s, robotPlayer, opcode, fishing_proto.OpResultCode_OPRC_Sucess, params)
						}
					}
				}
			}
		}
	}
	return false
}

/*// SyncFishingTarget 同步其他玩家的瞄准数据
func SyncFishingTarget(sceneEx *FishingSceneData, playerEx *FishingPlayerData) {
	for _, value := range sceneEx.players {
		if value.SnId != playerEx.SnId {
			continue
		}
		if value.TargetFish == 0 || value.SelTarget == 0 {
			continue
		}
		pack := &fishing_proto.SCFishTarget{
			FishId: proto.Int32(value.TargetFish),
			SnId:   proto.Int32(value.SnId),
		}
		playerEx.SendToClient(int(fishing_proto.FIPacketID_FISHING_SC_FISHTARGET), pack)
	}
}*/

/*
同步当前玩家得炮台状态
*/
//func SyncFishingPowerState(sceneEx *FishingSceneData, playerEx *FishingPlayerData) {
//	playerPowerState := []*fishing_proto.PlayerPowerState{}
//	for _, value := range sceneEx.players {
//		pps := &fishing_proto.PlayerPowerState{
//			Snid:  proto.Int32(value.SnId),
//			State: proto.Int32(value.powerType),
//			Num:   proto.Int32(value.FreePowerNum),
//		}
//		playerPowerState = append(playerPowerState, pps)
//	}
//	pack := &fishing_proto.SCPowerState{
//		PowerState: playerPowerState,
//	}
//	//sceneEx.BroadCastMessage(int(fishing_proto.FIPacketID_FISHING_SC_POWERSTATE), pack,0)
//	playerEx.SendToClient(int(fishing_proto.FIPacketID_FISHING_SC_POWERSTATE), pack)
//}

func (this *SceneBaseStateFishing) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) {
	this.BaseScenePolicy.OnPlayerEvent(s, p, evtcode, params)
	if sceneEx, ok := s.GetExtraData().(*FishingSceneData); ok {
		if playerEx, ok := p.GetExtraData().(*FishingPlayerData); ok {
			switch evtcode {
			case base.PlayerEventRehold:
				fishlogger.Tracef("用户 %v PlayerEventRehold", playerEx.SnId)
			case base.PlayerEventEnter:
				fallthrough
			case base.PlayerEventReturn:
				FishingSendRoomInfo(p, sceneEx)
				pack := &fishing_proto.SCfishingEnter{
					Data: &fishing_proto.FishingPlayerData{
						SnId:        proto.Int32(playerEx.SnId),
						Name:        proto.String(playerEx.Name),
						Head:        proto.Int32(playerEx.Head),
						Sex:         proto.Int32(playerEx.Sex),
						Coin:        proto.Int64(playerEx.CoinCache),
						Pos:         proto.Int(playerEx.GetPos()),
						Flag:        proto.Int(playerEx.GetFlag()),
						City:        proto.String(playerEx.GetCity()),
						Params:      proto.String(playerEx.Params),
						HeadOutLine: proto.Int32(playerEx.HeadOutLine),
						VIP:         proto.Int32(playerEx.VIP),
						SelVip:      proto.Int32(playerEx.SelVip),
						Power:       proto.Int32(playerEx.power),
						AgentParam:  proto.Int32(playerEx.AgentParam),
						TargetSel:   proto.Int32(playerEx.SelTarget),
						AutoFishing: proto.Int32(playerEx.AutoFishing),
						FireRate:    proto.Int32(playerEx.FireRate),
						IsRobot:     proto.Bool(playerEx.IsRob),
						NiceId:      proto.Int32(playerEx.NiceId),
						UnMaxPower:  proto.Int64(playerEx.UnMaxPower),
						UnPowerList: playerEx.PowerList,
						FishLevel:   proto.Int64(playerEx.FishLevel),
						FishExp:     proto.Int64(playerEx.FishExp),
					},
				}
				for _, v := range playerEx.RobotSnIds {
					pack.Data.RobotSnIds = append(pack.Data.RobotSnIds, v)
				}
				fishlogger.Tracef("用户 %v 本身的VIP %v  selVip %v  playerEx.RobotSnIds %v", playerEx.SnId, playerEx.VIP, playerEx.SelVip, playerEx.RobotSnIds)
				sceneEx.BroadCastMessage(int(fishing_proto.FIPacketID_FISHING_SC_ENTER), pack, int64(playerEx.GetSid()))
				//SyncFishingTarget(sceneEx, playerEx)
				sceneEx.SyncFish(p)
			case base.PlayerEventLeave:
				pack := &fishing_proto.SCfishingLeave{
					SnId: proto.Int32(playerEx.SnId),
				}
				sceneEx.BroadCastMessage(int(fishing_proto.FIPacketID_FISHING_SC_LEAVE), pack, int64(playerEx.GetSid()))
			case base.PlayerEventRecharge, base.PlayerEventAddCoin:
				playerEx.CoinCache += params[0]
			}
		}
	}
}

// Op协议包的统一发送
func (this *SceneBaseStateFishing) OnPlayerSToCOp(s *base.Scene, p *base.Player, opcode int, opRetCode fishing_proto.OpResultCode, params []int64) {
	pack := &fishing_proto.SCFishingOp{
		OpCode:    proto.Int(opcode),
		Params:    params,
		OpRetCode: opRetCode,
		SnId:      proto.Int32(p.SnId),
	}
	proto.SetDefaults(pack)
	p.SendToClient(int(fishing_proto.FIPacketID_FISHING_SC_OP), pack)
}

type SceneStateFishingStart struct {
	SceneBaseStateFishing
}

func (this *SceneStateFishingStart) GetState() int { return FishingSceneStateStart }
func (this *SceneStateFishingStart) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool {
	if this.SceneBaseStateFishing.OnPlayerOp(s, p, opcode, params) {
		return true
	}
	return true
}
func (this *SceneStateFishingStart) OnEnter(s *base.Scene) {
	this.SceneBaseStateFishing.OnEnter(s)
	if sceneEx, ok := s.GetExtraData().(*FishingSceneData); ok {
		fishlogger.Tracef("(this *Scene) [%v] 场景状态进入 %v", s.GetSceneId(), len(sceneEx.players))
		pack := &fishing_proto.SCFishingRoomState{
			State: proto.Int(this.GetState()),
		}
		proto.SetDefaults(pack)
		sceneEx.BroadCastMessage(int(fishing_proto.FIPacketID_FISHING_SC_ROOMSTATE), pack, 0)
		sceneEx.lastTick = 0
		sceneEx.remainder = 0
	}
}
func (this *SceneStateFishingStart) OnTick(s *base.Scene) {
	this.SceneBaseStateFishing.OnTick(s)
	if sceneEx, ok := s.GetExtraData().(*FishingSceneData); ok {
		if sceneEx.lastTick == 0 {
			sceneEx.lastTick = time.Now().UnixNano()
		} else {
			diff := time.Now().UnixNano() - sceneEx.lastTick
			diff = diff / time.Millisecond.Nanoseconds()
			sceneEx.lastTick = time.Now().UnixNano()
			diff += sceneEx.remainder
			for i := int64(0); i < diff/100; i++ {
				// 每一百毫秒执行一次
				sceneEx.TimePoint++
			}
			sceneEx.remainder = diff % 100

		}
		sceneEx.fishBattle() // 子弹鱼碰撞处理
		sceneEx.OnTick()
	}
}

func (this *SceneStateFishingStart) OnLeave(s *base.Scene) {
	this.SceneBaseStateFishing.OnLeave(s)
	if sceneEx, ok := s.GetExtraData().(*FishingSceneData); ok {
		for _, p := range sceneEx.players {
			if p != nil && p.IsGameing() && !p.IsRob {
				p.SaveDetailedLog(s)
			}
		}
	}
}

type SceneStateFishingClear struct {
	SceneBaseStateFishing
}

func (this *SceneStateFishingClear) GetState() int                      { return FishingSceneStateClear }
func (this *SceneStateFishingClear) CanChangeTo(s base.SceneState) bool { return true }
func (this *SceneStateFishingClear) OnEnter(s *base.Scene) {
	this.SceneBaseStateFishing.OnEnter(s)
	if sceneEx, ok := s.GetExtraData().(*FishingSceneData); ok {
		fishlogger.Tracef("(this *Scene) [%v] 场景状态进入 %v", s.GetSceneId(), len(sceneEx.players))
		sceneEx.Clean()
		//sceneEx.ChangeFlushFish()
		pack := &fishing_proto.SCFishingRoomState{
			State:  proto.Int(this.GetState()),
			Params: []int32{int32(common.RandInt(5) + 1)},
		}
		proto.SetDefaults(pack)
		sceneEx.BroadCastMessage(int(fishing_proto.FIPacketID_FISHING_SC_ROOMSTATE), pack, 0)
	}
}
func (this *SceneStateFishingClear) OnTick(s *base.Scene) {
	this.SceneBaseStateFishing.OnTick(s)
	if sceneEx, ok := s.GetExtraData().(*FishingSceneData); ok {
		if time.Now().Sub(sceneEx.GetStateStartTime()) > FishingSceneAniTimeout {
			sceneEx.OnTick()
			sceneEx.ChangeSceneState(FishingSceneStateStart)
		}
	}
}
func (this *SceneStateFishingClear) OnLeave(s *base.Scene) {
	this.SceneBaseStateFishing.OnLeave(s)
	if sceneEx, ok := s.GetExtraData().(*FishingSceneData); ok {
		for _, p := range sceneEx.players {
			leave := false
			var reason int
			if p.IsRob {
				if s.CoinOverMaxLimit(p.CoinCache, p.Player) {
					leave = true
					reason = common.PlayerLeaveReason_Normal
				}
			} else {
				if !p.IsOnLine() {
					leave = true
					reason = common.PlayerLeaveReason_DropLine
				} else if !s.CoinInLimit(p.CoinCache) {
					leave = true
					reason = common.PlayerLeaveReason_Bekickout
				}
			}
			todayGamefreeIDSceneData, _ := p.GetDaliyGameData(int(sceneEx.GetDBGameFree().GetId()))
			if !p.IsRob &&
				todayGamefreeIDSceneData != nil &&
				sceneEx.GetDBGameFree().GetPlayNumLimit() != 0 &&
				todayGamefreeIDSceneData.GameTimes >= int64(sceneEx.GetDBGameFree().GetPlayNumLimit()) {
				leave = true
				reason = common.PlayerLeaveReason_GameTimes
			}
			if leave {
				s.PlayerLeave(p.Player, reason, true)
			}
		}
	}
}
func (this *ScenePolicyFishing) RegisteSceneState(state base.SceneState) {
	if state == nil {
		return
	}
	stateid := state.GetState()
	if stateid < 0 || stateid >= FishingSceneStateMax {
		return
	}
	this.states[stateid] = state
}
func (this *ScenePolicyFishing) GetSceneState(s *base.Scene, stateid int) base.SceneState {
	if stateid >= 0 && stateid < FishingSceneStateMax {
		return ScenePolicyFishingSington.states[stateid]
	}
	return nil
}

//	func (this *ScenePolicyFishing) GetGameSubState(s *base.Scene, stateid int) base.SceneGamingSubState {
//		return nil
//	}
func init() {
	ScenePolicyFishingSington.RegisteSceneState(&SceneStateFishingStart{})
	ScenePolicyFishingSington.RegisteSceneState(&SceneStateFishingClear{})
	core.RegisteHook(core.HOOK_BEFORE_START, func() error {
		base.RegisteScenePolicy(common.GameId_HFishing, fishing.RoomMode_HuanLe, ScenePolicyFishingSington)
		return nil
	})
}
