contract ArtworkUnique {

    //mapping with unique key
    mapping  (bytes32 => bool) internal uniqueArtworks;
    
    //Creates a unique key based on the artwork name, author, and series
    function getUniqueKey(string name, string author, uint32 _version)  internal pure returns(bytes32) {
        string memory version = _uintToString(_version);
        string memory main = _strConcat(name, author, version, "$%)");
        string memory lowercased = _toLower(main);
        return keccak256(lowercased);
    }
    
    //https://gist.github.com/thomasmaclean/276cb6e824e48b7ca4372b194ec05b97
    //transform to lowercase
    function _toLower(string str) internal pure returns (string)  {
		bytes memory bStr = bytes(str);
		bytes memory bLower = new bytes(bStr.length);
		for (uint i = 0; i < bStr.length; i++) {
			// Uppercase character...
			if ((bStr[i] >= 65) && (bStr[i] <= 90)) {
				// So we add 32 to make it lowercase
				bLower[i] = bytes1(int(bStr[i]) + 32);
			} else {
				bLower[i] = bStr[i];
			}
		}
		return string(bLower);
	}
	
    //creates a unique key from all variables
    function _strConcat(string _a, string _b, string _c, string _separator) internal pure returns (string) {
        bytes memory _ba = bytes(_a);
        bytes memory _bb = bytes(_separator);
        bytes memory _bc = bytes(_b);
        bytes memory _bd = bytes(_separator);
        bytes memory _be = bytes(_c);
        string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length);
        bytes memory babcde = bytes(abcde);
        uint k = 0;
        for (uint i = 0; i < _ba.length; i++) babcde[k++] = _ba[i];
        for (i = 0; i < _bb.length; i++) babcde[k++] = _bb[i];
        for (i = 0; i < _bc.length; i++) babcde[k++] = _bc[i];
        for (i = 0; i < _bd.length; i++) babcde[k++] = _bd[i];
        for (i = 0; i < _be.length; i++) babcde[k++] = _be[i];
        return string(babcde);
    }

    //convert uint To String
    function _uintToString(uint v) internal pure returns (string) {
        bytes32 data = _uintToBytes(v);
        return _bytes32ToString(data);
    }

    /// title String Utils - String utility functions
    /// @author Piper Merriam - <pipermerriam@gmail.com>
    ///https://github.com/pipermerriam/ethereum-string-utils
    function _uintToBytes(uint v) private pure returns (bytes32 ret) {
        if (v == 0) {
            ret = "0";
        } else {
            while (v > 0) {
                ret = bytes32(uint(ret) / (2 ** 8));
                ret |= bytes32(((v % 10) + 48) * 2 ** (8 * 31));
                v /= 10;
            }
        }
        return ret;
    }

    function _bytes32ToString(bytes32 x) private pure returns (string) {
        bytes memory bytesString = new bytes(32);
        uint charCount = 0;
        for (uint j = 0; j < 32; j++) {
            byte char = byte(bytes32(uint(x) * 2 ** (8 * j)));
            if (char != 0) {
                bytesString[charCount] = char;
                charCount++;
            }
        }
        bytes memory bytesStringTrimmed = new bytes(charCount);
        for (j = 0; j < charCount; j++) {
            bytesStringTrimmed[j] = bytesString[j];
        }
        return string(bytesStringTrimmed);
    }
}
// Creates dictionary with unique keys, if the key is already used then its value will be true.
// It is not possible to create a duplicate.
function _uintToString(uint v) internal pure returns (string) {
    bytes32 data = _uintToBytes(v);
    return _bytes32ToString(data);
}

//convert uint To String