contract SelectOne is Loan
{
  uint public playNo = 1;      
  uint public constant minNum = 1; 
  uint public constant maxNum = 22;         
  uint public constant winMultiplePer = 1800;

  struct betInfo              
  {
    address Player;         
    uint[] BetNums;
    uint AwardNum;
    uint256[] BetAmounts;      
    uint256 BlockNumber;    
    uint EventId;           
    bool IsReturnAward;     
  }
  mapping (uint => betInfo) public playerBetInfoOf;               
  IGameToken public GameToken;


  //function SelectOne(uint _maxNum, uint256 _gameMinBetAmount,uint256 _gameMaxBetAmount,uint _winMultiplePer,string _gameName,address _gameToken,bool _isToken) public{
  function SelectOne(uint256 _gameMinBetAmount,uint256 _gameMaxBetAmount, string _gameName,address _gameToken) public{
    //require(1 < _maxNum);
    //require(_maxNum < 100);
    require(_gameMinBetAmount > 0); 
    require(_gameMaxBetAmount >= _gameMinBetAmount);
    //require(_winMultiplePer < _maxNum.mul(100));
    owner = msg.sender;             
    //maxNum = _maxNum;
    gameMinBetAmount = _gameMinBetAmount;
    gameMaxBetAmount = _gameMaxBetAmount;
    minBankerEther = gameMaxBetAmount * 20;
    //winMultiplePer = _winMultiplePer;
    gameName = _gameName;   
    GameToken = IGameToken(_gameToken);
    shareholder = _gameToken;
    shareholderIsToken = true;
    officialGameUrl='http://select.donquixote.games/';
  }
  

  function tokenOf(address _user) view public returns(uint _result){
    _result = GameToken.balanceOf(_user);
  }

  event OnPlay(address indexed _player, uint[] _betNums,uint256[] _betAmounts,uint256 _giftToken, uint _blockNumber,uint _playNo, uint _eventTime, uint eventId);
  event OnGetAward(address indexed _player, uint256 _playNo, uint[] _betNums,uint _blockNumber,uint256[] _betAmounts ,uint _eventId,uint _awardNum,uint256 _awardAmount);


  function play(uint[] _betNums,uint256[] _betAmounts) public  payable returns(bool _result){       
    _result = false;
    require(_betNums.length > 0);
    require(_betNums.length == _betAmounts.length);
    depositEther();
    _result = _play(_betNums,_betAmounts);
  }

  function _play(uint[] _betNums, uint256[] _betAmounts) private  returns(bool _result){            
    _result = false;
    require (!isStopPlay);

    uint maxBetAmount = 0;
    uint totalBetAmount = 0;
    uint8[22] memory betNumOf;                      

    for(uint i=0;i < _betNums.length;i++){
      require(_betNums[i] > 0 && _betNums[i] <= maxNum );
      require(betNumOf[_betNums[i] - 1] == 0);       
	  betNumOf[_betNums[i] - 1] = 1;      
      if(_betAmounts[i] > gameMaxBetAmount){
        _betAmounts[i] = gameMaxBetAmount;
      }
      if(_betAmounts[i] > maxBetAmount){
        maxBetAmount = _betAmounts[i];
      }
      totalBetAmount = totalBetAmount.add(_betAmounts[i]);
    }

    uint256 needAmount = maxBetAmount.mul(winMultiplePer).div(100);
    if(totalBetAmount > needAmount){
      needAmount = 0;
    }else{
      needAmount = needAmount.sub(totalBetAmount);
    }
    require(userEtherOf[shareholder] >= needAmount);
    require(userEtherOf[msg.sender] >= totalBetAmount);
    lock();
    betInfo memory bi = betInfo({
      Player :  msg.sender,              
      BetNums : _betNums,                       
      AwardNum : 0,
      BetAmounts : _betAmounts,                     
      BlockNumber : block.number,         
      EventId : currentEventId,           
      IsReturnAward: false               
    });
    playerBetInfoOf[playNo] = bi;
    userEtherOf[msg.sender] = userEtherOf[msg.sender].sub(totalBetAmount);                  
    userEtherOf[shareholder] = userEtherOf[shareholder].sub(needAmount);             
    userEtherOf[this] = userEtherOf[this].add(needAmount).add(totalBetAmount);
    
    uint256 _giftToken = GameToken.mineToken(msg.sender,totalBetAmount);
    emit OnPlay(msg.sender,_betNums,_betAmounts,_giftToken,block.number,playNo,now, getEventId());      
    playNo++;       
    _result = true;
    unLock();
	  autoCheckPayShareholder();             
  }

  function getAward(uint[] _playNos) public returns(bool _result){
    require(_playNos.length > 0);
    _result = false;
    for(uint i = 0;i < _playNos.length;i++){
      _result = _getAward(_playNos[i]);
    }
  }

  function _getAward(uint _playNo) private  returns(bool _result){
    require(_playNo < playNo);       
    _result = false;        
    betInfo storage bi = playerBetInfoOf[_playNo];        
    require(block.number > bi.BlockNumber);
    require(!bi.IsReturnAward);      

    lock();
    uint awardNum = 0;
    uint256 awardAmount = 0;
    uint256 totalBetAmount = 0;
    uint256 maxBetAmount = 0;
    uint256 totalAmount = 0;
    for(uint i=0;i <bi.BetNums.length;i++){
      if(bi.BetAmounts[i] > maxBetAmount){
        maxBetAmount = bi.BetAmounts[i];
      }
      totalBetAmount = totalBetAmount.add(bi.BetAmounts[i]);
    }
    totalAmount = maxBetAmount.mul(winMultiplePer).div(100);
    if(totalBetAmount >= totalAmount){
      totalAmount = totalBetAmount;
    }
    if(bi.BlockNumber.add(256) >= block.number){
      uint256 randomNum = bi.EventId%1000000;
      bytes32 encrptyHash = keccak256(bi.Player,block.blockhash(bi.BlockNumber),uintToString(randomNum));
      awardNum = uint(encrptyHash)%22;
      awardNum = awardNum.add(1);
      bi.AwardNum = awardNum;
      for(uint n=0;n <bi.BetNums.length;n++){
        if(bi.BetNums[n] == awardNum){
          awardAmount = bi.BetAmounts[n].mul(winMultiplePer).div(100);
          bi.IsReturnAward = true;  
          userEtherOf[this] = userEtherOf[this].sub(totalAmount);
          userEtherOf[bi.Player] = userEtherOf[bi.Player].add(awardAmount);
          userEtherOf[shareholder] = userEtherOf[shareholder].add(totalAmount.sub(awardAmount));
          break;
        }
      }
    }
    if(!bi.IsReturnAward){
      bi.IsReturnAward = true;
      userEtherOf[this] = userEtherOf[this].sub(totalAmount);
      userEtherOf[shareholder] = userEtherOf[shareholder].add(totalAmount);
    }
    emit OnGetAward(bi.Player,_playNo,bi.BetNums,bi.BlockNumber,bi.BetAmounts,getEventId(),awardNum,awardAmount);  
    _result = true; 
    unLock();
  }
  function getAwardNum(uint _playNo) view public returns(uint _awardNum){
    betInfo memory bi = playerBetInfoOf[_playNo];
    if(bi.BlockNumber.add(256) >= block.number){
      uint256 randomNum = bi.EventId%1000000;
      bytes32 encrptyHash = keccak256(bi.Player,block.blockhash(bi.BlockNumber),uintToString(randomNum));
      _awardNum = uint(encrptyHash)%22;
      _awardNum = _awardNum.add(1);
    }
  }

  function uintToString(uint v) private pure returns (string)    
  {
    uint maxlength = 10;                     
    bytes memory reversed = new bytes(maxlength);
    uint i = 0;
    while (v != 0) {
      uint remainder = v % 10;
      v = v / 10;
      reversed[i++] = byte(48 + remainder);
    }
    bytes memory s = new bytes(i);          
    for (uint j = 0; j < i; j++) {
      s[j] = reversed[i - j - 1];         
    }
    string memory str = string(s);         
    return str;                            
  }

  function () public payable {        
    if(msg.value > 0){
      userEtherOf[msg.sender] = userEtherOf[msg.sender].add(msg.value);
    }
  }

}
function SelectOne(uint256 _gameMinBetAmount,uint256 _gameMaxBetAmount, string _gameName,address _gameToken) public{
  //require(1 < _maxNum);
  //require(_maxNum < 100);
  require(_gameMinBetAmount > 0); 
  require(_gameMaxBetAmount >= _gameMinBetAmount);
  //require(_winMultiplePer < _maxNum.mul(100));
  owner = msg.sender;             
  //maxNum = _maxNum;
  gameMinBetAmount = _gameMinBetAmount;
  gameMaxBetAmount = _gameMaxBetAmount;
  minBankerEther = gameMaxBetAmount * 20;
  //winMultiplePer = _winMultiplePer;
  gameName = _gameName;   
  GameToken = IGameToken(_gameToken);
  shareholder = _gameToken;
  shareholderIsToken = true;
  officialGameUrl='http://select.donquixote.games/';
}

//function SelectOne(uint _maxNum, uint256 _gameMinBetAmount,uint256 _gameMaxBetAmount,uint _winMultiplePer,string _gameName,address _gameToken,bool _isToken) public{