contract BaseGame is ERC721Token {
    /// EVENTS
    ///@dev the Created event is fired whenever create or clone new fan token
    event NewAccount(address owner, uint tokenId, uint parentTokenId, uint blockNumber);

    ///@dev the NewForecast event is fired whenever any user create new forecast for game
    event NewForecast(address owner, uint tokenId, uint forecastId, uint _gameId,
        uint _forecastData);

    /// STRUCTS
    ///@dev Token - main token struct
    struct Token {
        // create block number, for tournament round, and date
        uint createBlockNumber;

        // parent
        uint parentId;
    }

    enum Teams { DEF,
        RUS, SAU, EGY, URY,     // group A
        PRT, ESP, MAR, IRN,     // group B
        FRA, AUS, PER, DNK,     // group C
        ARG, ISL, HRV, NGA,     // D
        BRA, CHE, CRI, SRB,     // E
        DEU, MEX, SWE, KOR,     // F
        BEL, PAN, TUN, GBR,     // G
        POL, SEN, COL, JPN      // H
    }

    ///#dev game changed event
    event GameChanged(uint _gameId, uint64 gameDate, Teams teamA, Teams teamB,
        uint goalA, uint goalB, bool odds, uint shotA, uint shotB);


    ///@dev Game info with result, index = official game id
    struct Game {
        // timestamp game date
        uint64 gameDate;

        // id teamA and teamB
        Teams teamA;
        Teams teamB;

        // count of total goal
        uint goalA;
        uint goalB;

        // game overweight / true - A / false - B
        bool odds;

        // total blows on target
        uint shotA;
        uint shotB;

        // list of ID forecast's
        uint[] forecasts;
    }

    ///@dev Forecast - fan forecast to game
    struct Forecast {
        // bits forecast for game from fan
        uint gameId;
        uint forecastBlockNumber;

        uint forecastData;
    }

    /// STORAGE
    ///@dev array of token fans
    Token[] tokens;

    ///@dev array of game from, 0 - invalid, index - official ID of game
    // http://welcome2018.com/matches/#
    //Game[65] games;
    mapping (uint => Game) games;

    ///@dev array of forecast for game from fans
    Forecast[] forecasts;

    ///@dev forecast -> token
    mapping (uint => uint) internal forecastToToken;

    ///@dev token -> forecast's
    mapping (uint => uint[]) internal tokenForecasts;

    /**
    * @dev Constructor function
    */
    constructor(string _name, string _symbol) ERC721Token(_name, _symbol) public {}

    /// METHOD's
    ///@dev create new token
    function _createToken(uint _parentId, address _owner) internal whenNotPaused
    returns (uint) {
        Token memory _token = Token({
            createBlockNumber: block.number,
            parentId: _parentId
            });
        uint newTokenId = tokens.push(_token) - 1;

        emit NewAccount(_owner, newTokenId, uint(_token.parentId), uint(_token.createBlockNumber));
        _mint(_owner, newTokenId);
        return newTokenId;
    }

    ///@dev Create new forecast
    function _createForecast(uint _tokenId, uint _gameId, uint _forecastData) internal whenNotPaused returns (uint) {
        require(_tokenId < tokens.length);

        Forecast memory newForecast = Forecast({
            gameId: _gameId,
            forecastBlockNumber: block.number,
            forecastData: _forecastData
            });

        uint newForecastId = forecasts.push(newForecast) - 1;

        forecastToToken[newForecastId] = _tokenId;
        tokenForecasts[_tokenId].push(newForecastId);
        games[_gameId].forecasts.push(newForecastId);

        //fire forecast!
        emit NewForecast(tokenOwner[_tokenId], _tokenId, newForecastId, _gameId, _forecastData);
        return newForecastId;
    }    
}
///@dev Base game contract. Holds all common structs, events and base variables.
function _createToken(uint _parentId, address _owner) internal whenNotPaused
returns (uint) {
    Token memory _token = Token({
        createBlockNumber: block.number,
        parentId: _parentId
        });
    uint newTokenId = tokens.push(_token) - 1;

    emit NewAccount(_owner, newTokenId, uint(_token.parentId), uint(_token.createBlockNumber));
    _mint(_owner, newTokenId);
    return newTokenId;
}

/// METHOD's
///@dev create new token