contract CryptoWarriorBase is PermissionControll, PVPListenerInterface {

    /*** EVENTS ***/

    /// @dev The Arise event is fired whenever a new warrior comes into existence. This obviously
    ///  includes any time a warrior is created through the ariseWarrior method, but it is also called
    ///  when a new miner warrior is created.
    event Arise(address owner, uint256 warriorId, uint256 identity);

    /// @dev Transfer event as defined in current draft of ERC721. Emitted every time a warrior
    ///  ownership is assigned, including dungeon rewards.
    event Transfer(address from, address to, uint256 tokenId);

    /*** CONSTANTS ***/
    
	uint256 public constant IDLE = 0;
    uint256 public constant PVE_BATTLE = 1;
    uint256 public constant PVP_BATTLE = 2;
    uint256 public constant TOURNAMENT_BATTLE = 3;
    
    //max pve dungeon level
    uint256 public constant MAX_LEVEL = 25;
    //how many points is needed to get 1 level
    uint256 public constant POINTS_TO_LEVEL = 10;
    
    /// @dev A lookup table contains PVE dungeon level requirements, each time warrior
    /// completes dungeon, next level requirement is set, until 25lv (250points) is reached.
    uint32[6] public dungeonRequirements = [
        uint32(10),
        uint32(30),
        uint32(60),
        uint32(100),
        uint32(150),
        uint32(250)
    ];

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

    /*** STORAGE ***/

    /// @dev An array containing the Warrior struct for all Warriors in existence. The ID
    ///  of each warrior is actually an index of this array.
    DataTypes.Warrior[] warriors;

    /// @dev A mapping from warrior IDs to the address that owns them. All warriors have
    ///  some valid owner address, even miner warriors are created with a non-zero owner.
    mapping (uint256 => address) public warriorToOwner;

    // @dev A mapping from owner address to count of tokens that address owns.
    //  Used internally inside balanceOf() to resolve ownership count.
    mapping (address => uint256) ownersTokenCount;

    /// @dev A mapping from warrior IDs to an address that has been approved to call
    ///  transferFrom(). Each Warrior can only have one approved address for transfer
    ///  at any time. A zero value means no approval is outstanding.
    mapping (uint256 => address) public warriorToApproved;
    
    // Mapping from owner to list of owned token IDs
    mapping (address => uint256[]) internal ownedTokens;

    // Mapping from token ID to index of the owner tokens list
    mapping(uint256 => uint256) internal ownedTokensIndex;


    /// @dev The address of the ClockAuction contract that handles sales of warriors. This
    ///  same contract handles both peer-to-peer sales as well as the miner sales which are
    ///  initiated every 15 minutes.
    SaleClockAuction public saleAuction;
    
    
    /// @dev Assigns ownership of a specific warrior to an address.
    function _transfer(address _from, address _to, uint256 _tokenId) internal {
        // When creating new warriors _from is 0x0, but we can't account that address.
        if (_from != address(0)) {
            _clearApproval(_tokenId);
            _removeTokenFrom(_from, _tokenId);
        }
        _addTokenTo(_to, _tokenId);
        
        // Emit the transfer event.
        Transfer(_from, _to, _tokenId);
    }
    
    function _addTokenTo(address _to, uint256 _tokenId) internal {
        // Since the number of warriors is capped to '1 000 000' we can't overflow this
        ownersTokenCount[_to]++;
        // transfer ownership
        warriorToOwner[_tokenId] = _to;
        
        uint256 length = ownedTokens[_to].length;
        ownedTokens[_to].push(_tokenId);
        ownedTokensIndex[_tokenId] = length;
    }
    
    function _removeTokenFrom(address _from, uint256 _tokenId) internal {
        //
        ownersTokenCount[_from]--;
        
        warriorToOwner[_tokenId] = address(0);
        
        uint256 tokenIndex = ownedTokensIndex[_tokenId];
        uint256 lastTokenIndex = ownedTokens[_from].length - 1;
        uint256 lastToken = ownedTokens[_from][lastTokenIndex];
    
        ownedTokens[_from][tokenIndex] = lastToken;
        ownedTokens[_from][lastTokenIndex] = 0;
        
        // Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to
        // be zero. Then we can make sure that we will remove _tokenId from the ownedTokens list since we are first swapping
        // the lastToken to the first position, and then dropping the element placed in the last position of the list
        ownedTokens[_from].length--;
        ownedTokensIndex[_tokenId] = 0;
        ownedTokensIndex[lastToken] = tokenIndex;
    }
    
    function _clearApproval(uint256 _tokenId) internal {
        if (warriorToApproved[_tokenId] != address(0)) {
            // clear any previously approved ownership exchange
            warriorToApproved[_tokenId] = address(0);
        }
    }
    
    function _createWarrior(uint256 _identity, address _owner, uint256 _cooldown, uint256 _level, uint256 _rating, uint256 _dungeonIndex)
        internal
        returns (uint256) {
        	    
        DataTypes.Warrior memory _warrior = DataTypes.Warrior({
            identity : _identity,
            cooldownEndBlock : uint64(_cooldown),
            level : uint64(_level),//uint64(10),
            rating : int64(_rating),//int64(100),
            action : uint32(IDLE),
            dungeonIndex : uint32(_dungeonIndex)//uint32(0)
        });
        uint256 newWarriorId = warriors.push(_warrior) - 1;
        
        // let's just be 100% sure we never let this happen.
        require(newWarriorId == uint256(uint32(newWarriorId)));
        
        // emit the arise event
        Arise(_owner, newWarriorId, _identity);
        
        // This will assign ownership, and also emit the Transfer event as
        // per ERC721 draft
        _transfer(0, _owner, newWarriorId);

        return newWarriorId;
    }
    

    // Any C-level can fix how many seconds per blocks are currently observed.
    function setSecondsPerBlock(uint256 secs) external onlyAuthorized {
        secondsPerBlock = secs;
    }
}
function _transfer(address _from, address _to, uint256 _tokenId) internal {
    // When creating new warriors _from is 0x0, but we can't account that address.
    if (_from != address(0)) {
        _clearApproval(_tokenId);
        _removeTokenFrom(_from, _tokenId);
    }
    _addTokenTo(_to, _tokenId);
        
    // Emit the transfer event.
    Transfer(_from, _to, _tokenId);
}

/// @dev Assigns ownership of a specific warrior to an address.