contract IconFactory is Factory, Ownable {
    using Strings for string;

    address public proxyRegistryAddress;
    address public nftAddress;
    address public packNftAddress;
    string public baseURI = "https://www.ninjastickers.com/api/factory/";

    /**
     * Enforce the existence of only 100 MotoGP Icons.
     */
    uint256 ICON_SUPPLY = 39510;

    /**
     * Three different options for minting Icons (bronze, silver, and gold).
     */
    uint256 NUM_OPTIONS = 3;
    uint256 SINGLE_ICON_OPTION = 0;
    uint256 MULTIPLE_ICON_OPTION = 1;
    uint256 PACK_OPTION = 2;
    uint256 NUM_ICONS_IN_MULTIPLE_ICON_OPTION = 4;

    constructor(address _proxyRegistryAddress, address _nftAddress) public {
        proxyRegistryAddress = _proxyRegistryAddress;
        nftAddress = _nftAddress;
        packNftAddress = address(
            new Pack(_proxyRegistryAddress, address(this))
        );
    }

    function name() external view returns (string memory) {
        return "MotoGP NinjaStickers";
    }

    function symbol() external view returns (string memory) {
        return "MGPNS";
    }

    function supportsFactoryInterface() public view returns (bool) {
        return true;
    }

    function numOptions() public view returns (uint256) {
        return NUM_OPTIONS;
    }

    function mint(uint256 _optionId, address _toAddress) public {
        // Must be sent from the owner proxy or owner.
        ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
        assert(
            address(proxyRegistry.proxies(owner())) == msg.sender ||
                owner() == msg.sender ||
                msg.sender == packNftAddress
        );
        require(canMint(_optionId));

        Icon openSeaIcon = Icon(nftAddress);
        if (_optionId == SINGLE_ICON_OPTION) {
            //TODO create a function to get randon  ID
            openSeaIcon.mintTo(_toAddress);
        } else if (_optionId == MULTIPLE_ICON_OPTION) {
            for (uint256 i = 0; i < NUM_ICONS_IN_MULTIPLE_ICON_OPTION; i++) {
                //TODO create a function to get randon  ID
                openSeaIcon.mintTo(_toAddress);
            }
        } else if (_optionId == PACK_OPTION) {
            //Pack openSeaPack = Pack(packNftAddress);
            //openSeaPack.mintTo(_toAddress);
            for (uint256 i = 0; i < NUM_ICONS_IN_MULTIPLE_ICON_OPTION; i++) {
                //TODO create a function to get randon  ID
                openSeaIcon.mintTo(_toAddress);
            }
        }
    }

    function canMint(uint256 _optionId) public view returns (bool) {
        if (_optionId >= NUM_OPTIONS) {
            return false;
        }

        Icon openSeaIcon = Icon(nftAddress);
        uint256 iconSupply = openSeaIcon.totalSupply();

        uint256 numItemsAllocated = 0;
        if (_optionId == SINGLE_ICON_OPTION) {
            numItemsAllocated = 1;
        } else if (_optionId == MULTIPLE_ICON_OPTION) {
            numItemsAllocated = NUM_ICONS_IN_MULTIPLE_ICON_OPTION;
        } else if (_optionId == PACK_OPTION) {
            //Pack openSeaPack = Pack(packNftAddress);
            //numItemsAllocated = openSeaPack.itemsPerPack();
            numItemsAllocated = NUM_ICONS_IN_MULTIPLE_ICON_OPTION;
        }
        return iconSupply < (ICON_SUPPLY - numItemsAllocated);
    }

    function tokenURI(uint256 _optionId) external view returns (string memory) {
        return Strings.strConcat(baseURI, Strings.uint2str(_optionId));
    }

    /**
     * Hack to get things to work automatically on OpenSea.
     * Use transferFrom so the frontend doesn't have to worry about different method names.
     */
    function transferFrom(
        address _from,
        address _to,
        uint256 _tokenId
    ) public {
        mint(_tokenId, _to);
    }

    /**
     * Hack to get things to work automatically on OpenSea.
     * Use isApprovedForAll so the frontend doesn't have to worry about different method names.
     */
    function isApprovedForAll(address _owner, address _operator)
        public
        view
        returns (bool)
    {
        if (owner() == _owner && _owner == _operator) {
            return true;
        }

        ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
        if (
            owner() == _owner &&
            address(proxyRegistry.proxies(_owner)) == _operator
        ) {
            return true;
        }

        return false;
    }

    /**
     * Hack to get things to work automatically on OpenSea.
     * Use isApprovedForAll so the frontend doesn't have to worry about different method names.
     */
    function ownerOf(uint256 _tokenId) public view returns (address _owner) {
        return owner();
    }
}
function isApprovedForAll(address _owner, address _operator)
    public
    view
    returns (bool)
{
    if (owner() == _owner && _owner == _operator) {
        return true;
    }

    ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
    if (
        owner() == _owner &&
        address(proxyRegistry.proxies(_owner)) == _operator
    ) {
        return true;
    }

    return false;
}

/**
 * Hack to get things to work automatically on OpenSea.
 * Use isApprovedForAll so the frontend doesn't have to worry about different method names.
 */