contract CryptoArte is ERC721Token, Ownable {

    // Token id to painting image file hash mapping
    mapping (uint256 => uint256) public tokenIdToHash;

    constructor() ERC721Token("CryptoArte", "CARTE") public { }

    /**
    * @dev Mints a token to an address with a tokenURI and tokenHash.
    * @param _to address of the future owner of the token
    * @param _tokenId uint256 token ID (painting number)
    * @param _tokenURI string token metadata URI
    * @param _tokenHash uint256 token image Hash
    */
    function mintTo(address _to, string _tokenURI, uint256 _tokenId, uint256 _tokenHash) public onlyOwner {
        _mint(_to, _tokenId);
        _setTokenURI(_tokenId, _tokenURI);
        tokenIdToHash[_tokenId] = _tokenHash;
    }    

    /**
    * @dev Mints many tokens to an address with their tokenURIs and tokenHashes.
    * @param _to address of the future owner of the tokens
    * @param _tokenIds uint256 array of token IDs (painting numbers)
    * @param _tokenURIPrefix string prefix for token metadata URI
    * @param _tokenHashes uint256 array of token image Hashes
    */
    function mintManyTo(address _to, string _tokenURIPrefix, uint256[] _tokenIds, uint256[] _tokenHashes) public onlyOwner {
        require(_tokenIds.length >= 1);
        require(_tokenIds.length == _tokenHashes.length);

        for (uint i = 0; i < _tokenIds.length; i++) { 
            _mint(_to, _tokenIds[i]);
            _setTokenURI(_tokenIds[i], strConcat(_tokenURIPrefix, uint256Tostr(_tokenIds[i])));
            tokenIdToHash[_tokenIds[i]] = _tokenHashes[i];
        }
    }    

    /**
    * @dev Updates tokenURI for tokenId - to be used to correct errors
    * @dev Throws if the tokenId does not exist
    * @param _tokenId uint256 token ID (painting number)
    * @param _tokenURI string token metadata URI
    */
    function setTokenURI(string _tokenURI, uint256 _tokenId) public onlyOwner {
        _setTokenURI(_tokenId, _tokenURI);
    }    

    /**
    * @dev Updates tokenHash for tokenId - to be used only to correct errors
    * @dev Throws if the tokenId does not exist    
    * @param _tokenId uint256 token ID (painting number)
    * @param _tokenHash uint256 token image Hash
    */
    function setTokenHash(uint256 _tokenHash, uint256 _tokenId) public onlyOwner {
        require(exists(_tokenId));
        tokenIdToHash[_tokenId] = _tokenHash;
    }    
    
    /**
    * @dev Contatenates two strings
    * @param _a string first (left)
    * @param _b string second (right)
    */
    function strConcat(string _a, string _b) internal pure returns (string) {
        bytes memory _ba = bytes(_a);
        bytes memory _bb = bytes(_b);
        string memory ab = new string(_ba.length + _bb.length);
        bytes memory bab = bytes(ab);
        uint k = 0;
        for (uint i = 0; i < _ba.length; i++) bab[k++] = _ba[i];
        for (i = 0; i < _bb.length; i++) bab[k++] = _bb[i];
        return string(bab);
    }

    /**
    * @dev Converts a uint256 to string
    * @param _i uint256 the uint to convert
    */
    function uint256Tostr(uint256 _i) internal pure returns (string) {
        if (_i == 0) return "0";
        uint256 j = _i;
        uint256 len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint256 k = len - 1;
        while (_i != 0){
            bstr[k--] = byte(48 + _i % 10);
            _i /= 10;
        }
        return string(bstr);
    }    

}
/**
 * @title CryptoArte
 * CryptoArte - a non-fungible token smart contract for 
 * paintings from the www.cryptoarte.io collection
 */
function uint256Tostr(uint256 _i) internal pure returns (string) {
    if (_i == 0) return "0";
    uint256 j = _i;
    uint256 len;
    while (j != 0) {
        len++;
        j /= 10;
    }
    bytes memory bstr = new bytes(len);
    uint256 k = len - 1;
    while (_i != 0){
        bstr[k--] = byte(48 + _i % 10);
        _i /= 10;
    }
    return string(bstr);
}    

/**
 * @dev Converts a uint256 to string
 * @param _i uint256 the uint to convert
 */