contract CreditGAME is Owned, SafeMath, LinkedList{
    
    mapping(address => bool) approvedGames;
    mapping(address => GameLock) gameLocks;
    mapping(address => bool) public isGameLocked;
    mapping(uint => address) public concludedGames;
    
    uint public amountLocked = 0;
    uint public concludedGameIndex = 0;
    
    struct GameLock{
        uint amount;
        uint lockDuration;
    }
    
    event LockParameters(address gameAddress, uint totalParticipationAmount, uint tokenLockDuration);
    event UnlockParameters(address gameAddress, uint totalParticipationAmount);
    event GameConcluded(address gameAddress);

    //SET TOKEN ADDRESS BEFORE DEPLOY
    address public tokenAddress = 0xAef38fBFBF932D1AeF3B808Bc8fBd8Cd8E1f8BC5;
    
    /**
     * Set CRB token address here
     * 
     **/
    function setTokenAddress(address _tokenAddress) onlyOwner public {
        tokenAddress = _tokenAddress;
    }

    /**
     * When new game is created it needs to be approved here before it starts.
     * 
     **/
    function addApprovedGame(address _gameAddress) onlyOwner public{
        approvedGames[_gameAddress] = true;
        addItem(_gameAddress);
    }
    
    /**
     * Manually remove approved game.
     * 
     **/
    function removeApprovedGame(address _gameAddress) onlyOwner public{
        approvedGames[_gameAddress] = false;
        removeItem(_gameAddress);
    }

    /**
     * Remove failed game.
     * 
     **/
    function removeFailedGame() public{
      require(approvedGames[msg.sender] == true);
      removeItem(msg.sender);
      approvedGames[msg.sender] = false;
      concludedGames[concludedGameIndex] = msg.sender; 
      concludedGameIndex++;
      emit GameConcluded(msg.sender);
    }
    
    /**
     * Verify if game is approved
     * 
     **/
    function isGameApproved(address _gameAddress) view public returns(bool){
        if(approvedGames[_gameAddress] == true){
            return true;
        }else{
            return false;
        }
    }
    
    /**
     * Funds must be transfered by calling contract before calling this contract. 
     * msg.sender is address of calling contract that must be approved.
     * 
     **/
    function createLock(address _winner, uint _totalParticipationAmount, uint _tokenLockDuration) public {
        require(approvedGames[msg.sender] == true);
        require(isGameLocked[msg.sender] == false);
        
        //Create gameLock
        GameLock memory gameLock = GameLock(_totalParticipationAmount, block.number + _tokenLockDuration);
        gameLocks[msg.sender] = gameLock;
        isGameLocked[msg.sender] = true;
        amountLocked = safeAdd(amountLocked, _totalParticipationAmount);
        
        //Transfer game credits to winner
        generateChampionTokens(_winner, _totalParticipationAmount, _tokenLockDuration);
        emit LockParameters(msg.sender, _totalParticipationAmount, block.number + _tokenLockDuration);
    }
    
    /**
     * Call CRB token to mint champion tokens
     * 
     **/
    function generateChampionTokens(address _winner, uint _totalParticipationAmount, uint _tokenLockDuration) internal{
        ICreditBIT(tokenAddress).claimGameReward(_winner, _totalParticipationAmount, _tokenLockDuration);
    }
    
    /**
     * Check the CRB balance of this.
     * 
     **/
    function checkInternalBalance() public view returns(uint256 tokenBalance) {
        return IERC20Token(tokenAddress).balanceOf(address(this));
    }
    
    /**
     * Method called by game contract
     * msg.sender is address of calling contract that must be approved.
     **/
    function removeLock() public{
        require(approvedGames[msg.sender] == true);
        require(isGameLocked[msg.sender] == true);
        require(checkIfLockCanBeRemoved(msg.sender) == true);
        GameLock memory gameLock = gameLocks[msg.sender];
        
        //transfer tokens to game contract
        IERC20Token(tokenAddress).transfer(msg.sender, gameLock.amount);
        
        delete(gameLocks[msg.sender]);
        
        //clean up
        amountLocked = safeSub(amountLocked, gameLock.amount);
        
        isGameLocked[msg.sender] = false;
        emit UnlockParameters(msg.sender, gameLock.amount);
    }
    
    /**
     * Method called by game contract when last participant has withdrawn
     * msg.sender is address of calling contract that must be approved.
     **/
    function cleanUp() public{
        require(approvedGames[msg.sender] == true);
        require(isGameLocked[msg.sender] == false);
        removeItem(msg.sender);
        
        approvedGames[msg.sender] = false;
        concludedGames[concludedGameIndex] = msg.sender; 
        concludedGameIndex++;
        emit GameConcluded(msg.sender);
    }

    /**
     * Failsafe if game needs to be removed. Tokens are transfered to _tokenHolder address
     * 
     **/
    function removeGameManually(address _gameAddress, address _tokenHolder) onlyOwner public{
      GameLock memory gameLock = gameLocks[_gameAddress];
      //transfer tokens to game contract
      IERC20Token(tokenAddress).transfer(_tokenHolder, gameLock.amount);
      //clean up
      amountLocked = safeSub(amountLocked, gameLock.amount);
      delete(gameLocks[_gameAddress]);
      isGameLocked[_gameAddress] = false;
      removeItem(_gameAddress);
      approvedGames[_gameAddress] = false;
    }
    
    /**
     * Get gamelock parameters: CRB amount locked, CRB lock duration
     * 
     **/
    function getGameLock(address _gameAddress) public view returns(uint, uint){
        require(isGameLocked[_gameAddress] == true);
        GameLock memory gameLock = gameLocks[_gameAddress];
        return(gameLock.amount, gameLock.lockDuration);
    }

    /**
     * Verify if game is locked
     * 
     **/
    function isGameLocked(address _gameAddress) public view returns(bool){
      if(isGameLocked[_gameAddress] == true){
        return true;
      }else{
        return false;
      }
    }
    
    /**
     * Check if game lock can be removed
     * 
     **/
    function checkIfLockCanBeRemoved(address _gameAddress) public view returns(bool){
        require(approvedGames[_gameAddress] == true);
        require(isGameLocked[_gameAddress] == true);
        GameLock memory gameLock = gameLocks[_gameAddress];
        if(gameLock.lockDuration < block.number){
            return true;
        }else{
            return false;
        }
    }

    /**
     * Kill contract if needed
     * 
     **/
    function killContract() onlyOwner public {
      selfdestruct(owner);
    }
}
function killContract() onlyOwner public {
  selfdestruct(owner);
}

/**
 * Kill contract if needed
 * 
 **/