// Contract: CryptoCrab
// Target function: function ownerMintReserved(uint256 _nbTokens, address reciever) public onlyOwner
` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}


/**
 * @dev This implements an optional extension of {ERC721} defined in the EIP that adds
 * enumerability of all the token ids in the contract as well as all token ids owned by each
 * account.
 */
abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
    // Mapping from owner to list of owned token IDs
    mapping(address => mapping(uint256 => uint256)) private _ownedTokens;

    // Mapping from token ID to index of the owner tokens list
    mapping(uint256 => uint256) private _ownedTokensIndex;

    // Array with all token ids, used for enumeration
    uint256[] private _allTokens;

    // Mapping from token id to position in the allTokens array
    mapping(uint256 => uint256) private _allTokensIndex;

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {
        return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
        require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
        return _ownedTokens[owner][index];
    }

    /**
     * @dev See {IERC721Enumerable-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _allTokens.length;
    }

    /**
     * @dev See {IERC721Enumerable-tokenByIndex}.
     */
    function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
        require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
        return _allTokens[index];
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
     * transferred to `to`.
     * - When `from` is zero, `tokenId` will be minted for `to`.
     * - When `to` is zero, ``from``'s `tokenId` will be burned.
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual override {
        super._beforeTokenTransfer(from, to, tokenId);

        if (from == address(0)) {
            _addTokenToAllTokensEnumeration(tokenId);
        } else if (from != to) {
            _removeTokenFromOwnerEnumeration(from, tokenId);
        }
        if (to == address(0)) {
            _removeTokenFromAllTokensEnumeration(tokenId);
        } else if (to != from) {
            _addTokenToOwnerEnumeration(to, tokenId);
        }
    }

    /**
     * @dev Private function to add a token to this extension's ownership-tracking data structures.
     * @param to address representing the new owner of the given token ID
     * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
     */
    function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
        uint256 length = ERC721.balanceOf(to);
        _ownedTokens[to][length] = tokenId;
        _ownedTokensIndex[tokenId] = length;
    }

    /**
     * @dev Private function to add a token to this extension's token tracking data structures.
     * @param tokenId uint256 ID of the token to be added to the tokens list
     */
    function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
        _allTokensIndex[tokenId] = _allTokens.length;
        _allTokens.push(tokenId);
    }

    /**
     * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
     * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
     * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
     * This has O(1) time complexity, but alters the order of the _ownedTokens array.
     * @param from address representing the previous owner of the given token ID
     * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
     */
    function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
        // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
        uint256 tokenIndex = _ownedTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary
        if (tokenIndex != lastTokenIndex) {
            uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];

            _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
            _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
        }

        // This also deletes the contents at the last position of the array
        delete _ownedTokensIndex[tokenId];
        delete _ownedTokens[from][lastTokenIndex];
    }

    /**
     * @dev Private function to remove a token from this extension's token tracking data structures.
     * This has O(1) time complexity, but alters the order of the _allTokens array.
     * @param tokenId uint256 ID of the token to be removed from the tokens list
     */
    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
        // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = _allTokens.length - 1;
        uint256 tokenIndex = _allTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
        // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
        // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
        uint256 lastTokenId = _allTokens[lastTokenIndex];

        _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
        _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index

        // This also deletes the contents at the last position of the array
        delete _allTokensIndex[tokenId];
        _allTokens.pop();
    }
}



/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _setOwner(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _setOwner(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _setOwner(newOwner);
    }

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

/*--------------------------------------------*/
//                                            //
//      PINEAPPLE PIZZA PARTY PRESENTS        //
//                      __                    //
//                    _(__)                   //
//                  _(____)                   // 
//                 (______)                   //
//           ...//( 00  )\.....               //
//                                            //
//              CRYPTO CRABS                  //
//                                            //
/*--------------------------------------------*/

contract CryptoCrab is ERC721, ERC721Enumerable, Ownable {

    /*--------------------------------------------*/
    //         Only 10000 first gen crabs         //
    /*--------------------------------------------*/
    // 9000 publicly mintable crabs
    uint256 public constant maxSupply = 10000;
    //Mint and breed price the same
    uint256 private _price = 0.01 ether;
    // 1000 reserved crabs (for publicity and giveaways)
    uint256 private _reserved = 1000;

    uint256 public startingIndex;
    bool private _saleStarted;
    string public baseURI;
    uint256 public bredCrabs = 0;

    // address withdrawlAddress = 0x6A15A2f7EC02471C4Ee11c12F4C15B8D7AE90A00;

    struct CrabyDNA {
        bytes32 crabyDNA;
    }

    mapping( uint256 => CrabyDNA) private _tokenDetails;

    constructor() ERC721("CryptoCrabs", "CC"){
        _saleStarted = false;
    }

    modifier whenSaleStarted() {
        require(_saleStarted);
        _;
    }

    function getTokenDetails(uint256 tokenId) public view returns (CrabyDNA memory) {
        return _tokenDetails[tokenId];
    }

    /*--------------------------------------------*/
    //         Make some random Craby DNA         //
    /*--------------------------------------------*/

    /*--------------------------------------------*/
    //               DNA Structure                //
    // ------------------------------------------ //
    // | Byte |             Data                | //
    // ------------------------------------------ //
    // |                Crab Data               | //
    // ------------------------------------------ //
    // |  0   | Stage - 0=Shell 1=Baby 2=Adult  | //
    // |  1   | Has Bred - 0=No, 1=Yes          | //
    // |  2   | Generation                      | //
    // |  3   | Crab Special Reserve            | //
    // ------------------------------------------ //
    // |                Crab Stats              | //
    // ------------------------------------------ //
    // |  4   | Cuteness                        | //
    // |  5   | Sasiness                        | //
    // |  6   | Size                            | //
    // |  7   | Speed                           | //
    // |  8   | Smarts                          | //
    // |  9   | Wisdom                          | //
    // |  10  | Power                           | //
    // |  11  | Luck                            | //
    // ------------------------------------------ //
    // |                Shell Stage             | //
    // ------------------------------------------ //
    // |  12  | Background                      | //
    // |  13  | Shell Type                      | //
    // |  14  | Shell Accessory                 | //
    // ------------------------------------------ //
    // |                Baby Stage              | //
    // ------------------------------------------ //
    // |  15  | Background                      | //
    // |  16  | Shell Type                      | //
    // |  17  | Shell Accessory                 | //
    // |  18  | Crab Type                       | //
    // |  19  | Crab Claw                       | //
    // |  20  | Crab Eyes                       | //
    // |  21  | Crab Mouth                      | //
    // |  22  | Crab Accessory                  | //
    // ------------------------------------------ //
    // |      |        Adult Stage              | //
    // |  23  | Background                      | //
    // |  24  | Shell Type                      | //
    // |  25  | Shell Accessory                 | //
    // |  26  | Crab Type                       | //
    // |  27  | Crab Claw                       | //
    // |  28  | Crab Eyes                       | //
    // |  29  | Crab Mouth                      | //
    // |  30  | Crab Accessory                  | //
    // |  31  | Overflow protection             | //
    // ------------------------------------------ //
    /*--------------------------------------------*/

    function randBytes32(uint256 tokenId) internal view returns(bytes32){
        // The premmise is that even if the DNA is psudo-random but deterministic, make it impractably so.
        // Its a tad overkill, but you can add / remove bits to adjust the complexity... Good luck!
        uint256 dna = uint256(keccak256(abi.encodePacked(               // Take the hash of
            uint256(blockhash(block.number - 2))                        // the hash of the block 2 blocks ago XOR with
            // ^ uint256(blockhash(block.number - 1)                    // the hash of the last block XOR with
            ^ block.timestamp                                           // the time stamp XOR with
            ^ block.difficulty                                          // the difficulty XOR with
            // ^ block.gaslimit                                         // the gas limit XOR with
            // ^ block.number                                           // the block number XOR with
            // ^ uint256(keccak256(abi.encodePacked(block.coinbase)))   // the hash of the coinbase XOR with
            ^ uint256(keccak256(abi.encodePacked(msg.sender)))          // the hash of the calling wallet XOR with
            // ^ uint256(keccak256(abi.encodePacked(tokenId)))          // the hash of the tokenId
            + tokenId                                                   // add the tokenId
        )));

        return bytes32(dna);
    }

    /*--------------------------------------------*/
    //         Mint some random Crabs             //
    /*--------------------------------------------*/
    function internalMint(address to, uint256 tokenId, bytes1 generation, bytes1 reserve) internal {
        bytes32 x = 0xff00000000000000000000000000000000000000000000000000000000000000;

        //Start with some random bytes
        bytes32 setCrabyDNA = randBytes32(tokenId);

        // mask out the status and other unused bytes
        setCrabyDNA &= 0x00000000ffffffffffffffffffffff000000ffffffffff000000000000000000;

        //Set generation and reserve status
        setCrabyDNA ^= (x & generation) >> 16;
        setCrabyDNA ^= (x & reserve) >> 24;

        //trim attributes to leave room for growth when evolving
        for(uint i=12; i <= 22; i++){
            uint8 byteResult = uint8(setCrabyDNA[i]);

            if( i > 17 ){
                if(byteResult > 0xf0){
                    unchecked {
                        //Crab attributes only evolve once so take off the max benifit of evolving once
                        byteResult ^= (byteResult << 4);
                    }
                    if(byteResult > uint8(setCrabyDNA[i])){byteResult = 0x00;}
                    setCrabyDNA ^= (x & bytes1(byteResult)) >> (i*8);
                }
            }else{
                if(byteResult > 0xe0){
                    unchecked {
                        //Shell and background attributes can evolve twice so take off a bit more
                        byteResult = (byteResult ^ (byteResult << 4))-0x10;
                    }
                    if(byteResult > uint8(setCrabyDNA[i])){byteResult = 0x00;}
                    setCrabyDNA ^= (x & bytes1(byteResult)) >> (i*8);
                }
            }
        }

        //Ready to Mint
        _tokenDetails[tokenId] = CrabyDNA(setCrabyDNA);
        _safeMint(to, tokenId);
    }