contract Hat is ERC721Tradable {
    uint256 public hardCap;
    uint256 public softCap;
    address payable wallet;
    bool public locked;
    mapping (uint256 => uint256) initialPrice;
    string public ipfsIndex;

    constructor(address payable _wallet, string memory _ipfsIndex, address _proxyRegistryAddress)
        public
        ERC721Tradable("THEM Hats", "HAT", _proxyRegistryAddress)
    {
        wallet = _wallet;
        locked = true;
        softCap = 421;
        hardCap = 666;
        ipfsIndex = _ipfsIndex;
    }

    /**
     * Buy a token and mint it in the process. (Only 1 - softCap).
     * @param _tokenId id of the token to be minted
     */
    function buy(uint256 _tokenId) external payable {
        uint256 payed = msg.value;
        uint256 price = getInitialPrice(_tokenId); 

        require(!locked, 'Buying hats is not unlocked yet. Soon™');
        require(_tokenId >= 1 && _tokenId <= hardCap, '_tokenId is invalid');
        require(_tokenId <= softCap, 'Hat not for sale yet');
        require(!_exists(_tokenId), 'Hat already sold');
        require(price <= payed, 'Price must be equal to or larger than the sales price');

        _mint(msg.sender, _tokenId);
        wallet.transfer(msg.value);
    }

    /**
     * Owner can change wallet.
     */
    function changeWallet(address payable _newWallet) public onlyOwner {
        wallet = _newWallet;
    }

    /**
     * Update IPFS Index.
     */
    function changeIpfsIndex(string memory _newIpfsIndex) public onlyOwner {
        ipfsIndex = _newIpfsIndex;
    }

    /**
     * Allow to offer more hats up to the hard cap of 666.
     */
    function changeSoftCap(uint256 _newCap) public onlyOwner {
        require(_newCap <= hardCap, 'Hardcap is at 666.');
        softCap = _newCap;
    }

    /**
     * Irreversably unlock buying.
     */
    function unlock() public onlyOwner {
        require(locked, 'Contract is already unlocked');
        locked = false;
    }

    function exists(uint256 _tokenId) public view returns (bool) {
        return _exists(_tokenId);
    }

    /**
     * @dev Mints a token to an address with a _tokenId.
     * @param _to address of the future owner of the token
     */
    function mintTo(uint256 _tokenId, address _to) public onlyOwner {
        require(_tokenId >= 1 && _tokenId <= hardCap, '_tokenId is invalid');
        _mint(_to, _tokenId);
    }


    function setInitialPrice(uint256 _tokenId, uint256 _price) public onlyOwner {
        require(!_exists(_tokenId), 'Hat already sold');
        require(_price >= 0.01 ether, 'Price needs to be equal to or larger than 0.01 ETH');
        require(_tokenId >= 1 && _tokenId <= hardCap, '_tokenId is invalid');
        initialPrice[_tokenId] = _price;
    }

    function getInitialPrice(uint256 _tokenId) public view returns (uint256) {
        uint256 price;

        if (initialPrice[_tokenId] < 0.01 ether) {
            price = 1 ether;
        } else {
            price = initialPrice[_tokenId];
        }

        return price;
    }

    function baseTokenURI() public pure returns (string memory) {
        return "https://api.them.af/api/hats/";
    }

    function contractURI() public pure returns (string memory) {
        return "https://api.them.af/api/contracts/hats";
    }
}
/**
 * @title Hat
 * Hat - a contract for non-fungible hats.
 */
function changeWallet(address payable _newWallet) public onlyOwner {
    wallet = _newWallet;
}

/**
 * Owner can change wallet.
 */