contract GameChannel is GameChannelConflict {
    /**
     * @dev contract constructor
     * @param _serverAddress Server address.
     * @param _minStake Min value player needs to deposit to create game session.
     * @param _maxStake Max value player can deposit to create game session.
     * @param _conflictResAddress Conflict resolution contract address.
     * @param _houseAddress House address to move profit to.
     */
    function GameChannel(
        address _serverAddress,
        uint _minStake,
        uint _maxStake,
        address _conflictResAddress,
        address _houseAddress,
        uint _gameIdCntr
    )
        public
        GameChannelConflict(_serverAddress, _minStake, _maxStake, _conflictResAddress, _houseAddress, _gameIdCntr)
    {
        // nothing to do
    }

    /**
     * @notice Create games session request. msg.value needs to be valid stake value.
     * @param _endHash Last hash of the hash chain generated by the player.
     */
    function createGame(bytes32 _endHash)
        public
        payable
        onlyValidValue
        onlyValidHouseStake(activeGames + 1)
        onlyNotPaused
    {
        address playerAddress = msg.sender;
        uint previousGameId = playerGameId[playerAddress];
        Game storage game = gameIdGame[previousGameId];

        require(game.status == GameStatus.ENDED);

        uint gameId = gameIdCntr++;
        playerGameId[playerAddress] = gameId;
        Game storage newGame = gameIdGame[gameId];

        newGame.stake = msg.value;
        newGame.status = GameStatus.WAITING_FOR_SERVER;

        activeGames = activeGames + 1;

        LogGameCreated(playerAddress, gameId, msg.value, _endHash);
    }

    /**
     * @notice Cancel game session waiting for server acceptance.
     * @param _gameId Game session id.
     */
    function cancelGame(uint _gameId) public {
        address playerAddress = msg.sender;
        uint gameId = playerGameId[playerAddress];
        Game storage game = gameIdGame[gameId];

        require(gameId == _gameId);
        require(game.status == GameStatus.WAITING_FOR_SERVER);

        closeGame(game, gameId, playerAddress, ReasonEnded.CANCELLED_BY_PLAYER, 0);
        payOut(game, playerAddress);
    }

    /**
     * @dev Called by the server to reject game session created by player with address
     * _playerAddress.
     * @param _playerAddress Players's address who created the game session.
     * @param _gameId Game session id.
     */
    function rejectGame(address _playerAddress, uint _gameId) public onlyServer {
        uint gameId = playerGameId[_playerAddress];
        Game storage game = gameIdGame[gameId];

        require(_gameId == gameId);
        require(game.status == GameStatus.WAITING_FOR_SERVER);

        closeGame(game, gameId, _playerAddress, ReasonEnded.REJECTED_BY_SERVER, 0);
        payOut(game, _playerAddress);

        LogGameRejected(_playerAddress, gameId);
    }

    /**
     * @dev Called by server to accept game session created by player with
     * address _playerAddress.
     * @param _playerAddress Player's address who created the game.
     * @param _gameId Game id of game session.
     * @param _endHash Last hash of the hash chain generated by the server.
     */
    function acceptGame(address _playerAddress, uint _gameId, bytes32 _endHash)
        public
        onlyServer
    {
        uint gameId = playerGameId[_playerAddress];
        Game storage game = gameIdGame[gameId];

        require(_gameId == gameId);
        require(game.status == GameStatus.WAITING_FOR_SERVER);

        game.status = GameStatus.ACTIVE;

        LogGameAccepted(_playerAddress, gameId, _endHash);
    }

    /**
     * @dev Regular end game session. Used if player and house have both
     * accepted current game session state.
     * The game session with gameId _gameId is closed
     * and the player paid out. This functions is called by the server after
     * the player requested the termination of the current game session.
     * @param _roundId Round id of bet.
     * @param _gameType Game type of bet.
     * @param _num Number of bet.
     * @param _value Value of bet.
     * @param _balance Current balance.
     * @param _serverHash Hash of server's seed for this bet.
     * @param _playerHash Hash of player's seed for this bet.
     * @param _gameId Game session id.
     * @param _contractAddress Address of this contract.
     * @param _playerAddress Address of player.
     * @param _playerSig Player's signature of this bet.
     */
    function serverEndGame(
        uint32 _roundId,
        uint8 _gameType,
        uint16 _num,
        uint _value,
        int _balance,
        bytes32 _serverHash,
        bytes32 _playerHash,
        uint _gameId,
        address _contractAddress,
        address _playerAddress,
        bytes _playerSig
    )
        public
        onlyServer
    {
        verifySig(
                _roundId,
                _gameType,
                _num,
                _value,
                _balance,
                _serverHash,
                _playerHash,
                _gameId,
                _contractAddress,
                _playerSig,
                _playerAddress
        );

        regularEndGame(_playerAddress, _roundId, _gameType, _num, _value, _balance, _gameId, _contractAddress);
    }

    /**
     * @notice Regular end game session. Normally not needed as server ends game (@see serverEndGame).
     * Can be used by player if server does not end game session.
     * @param _roundId Round id of bet.
     * @param _gameType Game type of bet.
     * @param _num Number of bet.
     * @param _value Value of bet.
     * @param _balance Current balance.
     * @param _serverHash Hash of server's seed for this bet.
     * @param _playerHash Hash of player's seed for this bet.
     * @param _gameId Game session id.
     * @param _contractAddress Address of this contract.
     * @param _serverSig Server's signature of this bet.
     */
    function playerEndGame(
        uint32 _roundId,
        uint8 _gameType,
        uint16 _num,
        uint _value,
        int _balance,
        bytes32 _serverHash,
        bytes32 _playerHash,
        uint _gameId,
        address _contractAddress,
        bytes _serverSig
    )
        public
    {
        verifySig(
                _roundId,
                _gameType,
                _num,
                _value,
                _balance,
                _serverHash,
                _playerHash,
                _gameId,
                _contractAddress,
                _serverSig,
                serverAddress
        );

        regularEndGame(msg.sender, _roundId, _gameType, _num, _value, _balance, _gameId, _contractAddress);
    }

    /**
     * @dev Regular end game session implementation. Used if player and house have both
     * accepted current game session state. The game session with gameId _gameId is closed
     * and the player paid out.
     * @param _playerAddress Address of player.
     * @param _gameType Game type of bet.
     * @param _num Number of bet.
     * @param _value Value of bet.
     * @param _balance Current balance.
     * @param _gameId Game session id.
     * @param _contractAddress Address of this contract.
     */
    function regularEndGame(
        address _playerAddress,
        uint32 _roundId,
        uint8 _gameType,
        uint16 _num,
        uint _value,
        int _balance,
        uint _gameId,
        address _contractAddress
    )
        private
    {
        uint gameId = playerGameId[_playerAddress];
        Game storage game = gameIdGame[gameId];
        address contractAddress = this;
        int maxBalance = conflictRes.maxBalance();

        require(_gameId == gameId);
        require(_roundId > 0);
        // save to cast as game.stake hash fixed range
        require(-int(game.stake) <= _balance && _balance <= maxBalance);
        require((_gameType == 0) && (_num == 0) && (_value == 0));
        require(_contractAddress == contractAddress);
        require(game.status == GameStatus.ACTIVE);

        closeGame(game, gameId, _playerAddress, ReasonEnded.REGULAR_ENDED, _balance);
        payOut(game, _playerAddress);
    }
}
function regularEndGame(
    address _playerAddress,
    uint32 _roundId,
    uint8 _gameType,
    uint16 _num,
    uint _value,
    int _balance,
    uint _gameId,
    address _contractAddress
)
    private
{
    uint gameId = playerGameId[_playerAddress];
    Game storage game = gameIdGame[gameId];
    address contractAddress = this;
    int maxBalance = conflictRes.maxBalance();

    require(_gameId == gameId);
    require(_roundId > 0);
    // save to cast as game.stake hash fixed range
    require(-int(game.stake) <= _balance && _balance <= maxBalance);
    require((_gameType == 0) && (_num == 0) && (_value == 0));
    require(_contractAddress == contractAddress);
    require(game.status == GameStatus.ACTIVE);

    closeGame(game, gameId, _playerAddress, ReasonEnded.REGULAR_ENDED, _balance);
    payOut(game, _playerAddress);
}

/**
 * @dev Regular end game session implementation. Used if player and house have both
 * accepted current game session state. The game session with gameId _gameId is closed
 * and the player paid out.
 * @param _playerAddress Address of player.
 * @param _gameType Game type of bet.
 * @param _num Number of bet.
 * @param _value Value of bet.
 * @param _balance Current balance.
 * @param _gameId Game session id.
 * @param _contractAddress Address of this contract.
 */