contract MonstersBase is MonsterAccessControl, MonstersData {
    /// @dev Transfer event as defined in current draft of ERC721. Emitted every time a monster
    ///  ownership is assigned, including births.
    event Transfer(address from, address to, uint256 tokenId);

    bool lockedMonsterCreator = false;

    MonsterAuction public monsterAuction;
    MonsterCreatorInterface public monsterCreator;

    function setMonsterCreatorAddress(address _address) external onlyAdmin {
        // only set this once so we (the devs) can't cheat!
        require(!lockedMonsterCreator);
        MonsterCreatorInterface candidateContract = MonsterCreatorInterface(_address);

        monsterCreator = candidateContract;
        lockedMonsterCreator = true;
    }

    // An approximation of currently how many seconds are in between blocks.
    uint256 public secondsPerBlock = 15;

    // array containing all monsters in existence
    Monster[] monsters;

    uint8[] areas;
    uint8 areaIndex = 0;

    mapping(address => Trainer) public addressToTrainer;
    /// @dev A mapping from monster IDs to the address that owns them. All monster have
    ///  some valid owner address, even gen0 monster are created with a non-zero owner.
    mapping (uint256 => address) public monsterIndexToOwner;
    // @dev A mapping from owner address to count of tokens that address owns.
    // Used internally inside balanceOf() to resolve ownership count.
    mapping (address => uint256) ownershipTokenCount;
    mapping (uint256 => address) public monsterIndexToApproved;
    mapping (uint256 => string) public monsterIdToNickname;
    mapping (uint256 => bool) public monsterIdToTradeable;
    mapping (uint256 => uint256) public monsterIdToGeneration;
    
    mapping (uint256 => uint8[7]) public monsterIdToIVs;

    // adds new area to world
    function _createArea() internal {
        areaIndex++;
        areas.push(areaIndex);
    }

    function _createMonster(uint256 _generation, address _owner, uint256 _mID, bool _tradeable,
        bool _female, bool _shiny) internal returns (uint)
    {

        Monster memory _monster = Monster({
            generation: uint16(_generation),
            birthTime: uint64(now),
            mID: uint16(_mID),
            tradeable: _tradeable,
            female: _female,
            shiny: _shiny
        });

        uint256 newMonsterId = monsters.push(_monster) - 1;

        require(newMonsterId == uint256(uint32(newMonsterId)));

        monsterIdToNickname[newMonsterId] = "";

        _transfer(0, _owner, newMonsterId);

        return newMonsterId;
    }

    function _createTrainer(string _username, uint16 _starterId, address _owner) internal returns (uint mon) {
        Trainer memory _trainer = Trainer({
            birthTime: uint64(now),
            username: string(_username),
             // sets to first area!,
            currArea: uint16(1),
            owner: address(_owner)
        });

        addressToTrainer[_owner] = _trainer;

        bool gender = monsterCreator.getMonsterGender();

        // starters cannot be traded and are not shiny
        if (_starterId == 1) {
            mon = _createMonster(0, _owner, 1, false, gender, false);
        } else if (_starterId == 2) {
            mon = _createMonster(0, _owner, 4, false, gender, false);
        } else if (_starterId == 3) {
            mon = _createMonster(0, _owner, 7, false, gender, false);
        }
    }

    function _moveToArea(uint16 _newArea, address player) internal {
        addressToTrainer[player].currArea = _newArea;
    }

    // assigns ownership of monster to address
    function _transfer(address _from, address _to, uint256 _tokenId) internal {
        ownershipTokenCount[_to]++;
        monsterIndexToOwner[_tokenId] = _to;

        if (_from != address(0)) {
            ownershipTokenCount[_from]--;

            // clear any previously approved ownership exchange
            delete monsterIndexToApproved[_tokenId];
        }

        // Emit Transfer event
        Transfer(_from, _to, _tokenId);
    }

    // Only admin can fix how many seconds per blocks are currently observed.
    function setSecondsPerBlock(uint256 secs) external onlyAdmin {
        //require(secs < cooldowns[0]);
        secondsPerBlock = secs;
    }
}
function _transfer(address _from, address _to, uint256 _tokenId) internal {
    ownershipTokenCount[_to]++;
    monsterIndexToOwner[_tokenId] = _to;

    if (_from != address(0)) {
        ownershipTokenCount[_from]--;

        // clear any previously approved ownership exchange
        delete monsterIndexToApproved[_tokenId];
    }

    // Emit Transfer event
    Transfer(_from, _to, _tokenId);
}

// assigns ownership of monster to address