contract CryptoversePreorderBonusAssets is Pausable, ERC721 {

	struct Item {
		ItemType typeId;
		ItemModel model;
		ItemManufacturer manufacturer;
		ItemRarity rarity;
		uint createTime;
		uint amount;
	}

	enum ItemType {VRCBox, VCXVault, SaiHead, SaiBody, SaiEarrings, MechHead, MechBody, MechLegs, MechRailgun, MechMachineGun, MechRocketLauncher}

	enum ItemModel {NC01, MK1, V1, V1_1, V2_1, M442_1, BG, Q3, TRFL405, BC, DES1, PlasmaS, BD, DRL, Casper, Kilo, Mega, Giga, Tera, Peta, Exa, EA}

	enum ItemManufacturer {BTC, VRC, ETH, Satoshipowered}

	enum ItemRarity {Common, Uncommon, Rare, Superior, Epic, Legendary, Unique}

	function name() public view returns (string){
		return "Cryptoverse Preorder Bonus Assets";
	}

	function symbol() public view returns (string){
		return "CPBA";
	}

	Item[] public items;

	mapping(uint => address) public itemIndexToOwner;

	mapping(address => uint) public ownershipTokenCount;

	mapping(uint => address) public itemIndexToApproved;

	function reclaimToken(ERC20 token) external onlyOwner {
		uint256 balance = token.balanceOf(this);
		token.transfer(owner, balance);
	}

	function _transfer(address from, address to, uint tokenId) internal {
		ownershipTokenCount[from]--;
		ownershipTokenCount[to]++;
		itemIndexToOwner[tokenId] = to;
		delete itemIndexToApproved[tokenId];

		Transfer(from, to, tokenId);
	}

	event CreateItem(uint id, ItemType typeId, ItemModel model, ItemManufacturer manufacturer, ItemRarity rarity, uint createTime, uint amount, address indexed owner);

	function createItem(ItemType typeId, ItemModel model, ItemManufacturer manufacturer, ItemRarity rarity, uint amount, address owner) internal returns (uint) {
		require(owner != address(0));

		Item memory item = Item(typeId, model, manufacturer, rarity, now, amount);

		uint newItemId = items.length;

		items.push(item);

		CreateItem(newItemId, typeId, model, manufacturer, rarity, now, amount, owner);

		ownershipTokenCount[owner]++;
		itemIndexToOwner[newItemId] = owner;

		return newItemId;
	}

	function tokensOfOwner(address owner) external view returns (uint[] ownerTokens) {
		uint tokenCount = balanceOf(owner);

		if (tokenCount == 0) {
			return new uint[](0);
		} else {
			ownerTokens = new uint[](tokenCount);
			uint totalItems = totalSupply();
			uint resultIndex = 0;

			for (uint itemId = 0; itemId < totalItems; itemId++) {
				if (itemIndexToOwner[itemId] == owner) {
					ownerTokens[resultIndex] = itemId;
					resultIndex++;
				}
			}

			return ownerTokens;
		}
	}

	ERC721Metadata public erc721Metadata;

	bytes4 constant InterfaceSignature_ERC165 =
	bytes4(keccak256('supportsInterface(bytes4)'));

	bytes4 constant InterfaceSignature_ERC721 =
	bytes4(keccak256('name()')) ^
	bytes4(keccak256('symbol()')) ^
	bytes4(keccak256('totalSupply()')) ^
	bytes4(keccak256('balanceOf(address)')) ^
	bytes4(keccak256('ownerOf(uint)')) ^
	bytes4(keccak256('approve(address,uint)')) ^
	bytes4(keccak256('transfer(address,uint)')) ^
	bytes4(keccak256('transferFrom(address,address,uint)')) ^
	bytes4(keccak256('tokensOfOwner(address)')) ^
	bytes4(keccak256('tokenMetadata(uint,string)'));

	function supportsInterface(bytes4 contractID) external view returns (bool)
	{
		return ((contractID == InterfaceSignature_ERC165) || (contractID == InterfaceSignature_ERC721));
	}

	function setMetadataAddress(address contractAddress) public onlyOwner {
		erc721Metadata = ERC721Metadata(contractAddress);
	}

	function _owns(address claimant, uint tokenId) internal view returns (bool) {
		return itemIndexToOwner[tokenId] == claimant;
	}

	function _approvedFor(address claimant, uint tokenId) internal view returns (bool) {
		return itemIndexToApproved[tokenId] == claimant;
	}

	function _approve(uint tokenId, address approved) internal {
		itemIndexToApproved[tokenId] = approved;
	}

	function balanceOf(address owner) public view returns (uint count) {
		return ownershipTokenCount[owner];
	}

	function transfer(address to, uint tokenId) public {
		require(to != address(0));
		require(_owns(msg.sender, tokenId));
		require(!_owns(to, tokenId));
		_transfer(msg.sender, to, tokenId);
	}

	function approve(address to, uint tokenId) external {
		require(_owns(msg.sender, tokenId));
		_approve(tokenId, to);
		Approval(msg.sender, to, tokenId);
	}

	function transferFrom(address from, address to, uint tokenId) external {
		require(to != address(0));
		require(to != address(this));
		require(_approvedFor(msg.sender, tokenId));
		require(_owns(from, tokenId));
		_transfer(from, to, tokenId);
	}

	function totalSupply() public view returns (uint) {
		return items.length;
	}

	function ownerOf(uint tokenId) external view returns (address owner)   {
		owner = itemIndexToOwner[tokenId];

		require(owner != address(0));
	}

	/// @dev Adapted from memcpy() by @arachnid (Nick Johnson <arachnid@notdot.net>)
	///  This method is licenced under the Apache License.
	///  Ref: https://github.com/Arachnid/solidity-stringutils/blob/2f6ca9accb48ae14c66f1437ec50ed19a0616f78/strings.sol
	function _memcpy(uint _dest, uint _src, uint _len) private pure {
		// Copy word-length chunks while possible
		for (; _len >= 32; _len -= 32) {
			assembly {
				mstore(_dest, mload(_src))
			}
			_dest += 32;
			_src += 32;
		}

		// Copy remaining bytes
		uint mask = 256 ** (32 - _len) - 1;
		assembly {
			let srcpart := and(mload(_src), not(mask))
			let destpart := and(mload(_dest), mask)
			mstore(_dest, or(destpart, srcpart))
		}
	}

	/// @dev Adapted from toString(slice) by @arachnid (Nick Johnson <arachnid@notdot.net>)
	///  This method is licenced under the Apache License.
	///  Ref: https://github.com/Arachnid/solidity-stringutils/blob/2f6ca9accb48ae14c66f1437ec50ed19a0616f78/strings.sol
	function _toString(bytes32[4] _rawBytes, uint _stringLength) private pure returns (string) {
		var outputString = new string(_stringLength);
		uint outputPtr;
		uint bytesPtr;

		assembly {
			outputPtr := add(outputString, 32)
			bytesPtr := _rawBytes
		}

		_memcpy(outputPtr, bytesPtr, _stringLength);

		return outputString;
	}

	/// @notice Returns a URI pointing to a metadata package for this token conforming to
	///  ERC-721 (https://github.com/ethereum/EIPs/issues/721)
	/// @param _tokenId The ID number of the Kitty whose metadata should be returned.
	function tokenMetadata(uint _tokenId, string _preferredTransport) public view returns (string infoUrl) {
		require(erc721Metadata != address(0));
		bytes32[4] memory buffer;
		uint count;
		(buffer, count) = erc721Metadata.getMetadata(_tokenId, _preferredTransport);

		return _toString(buffer, count);
	}
}
function tokenMetadata(uint _tokenId, string _preferredTransport) public view returns (string infoUrl) {
	require(erc721Metadata != address(0));
	bytes32[4] memory buffer;
	uint count;
	(buffer, count) = erc721Metadata.getMetadata(_tokenId, _preferredTransport);

	return _toString(buffer, count);
}

/// @notice Returns a URI pointing to a metadata package for this token conforming to
///  ERC-721 (https://github.com/ethereum/EIPs/issues/721)
/// @param _tokenId The ID number of the Kitty whose metadata should be returned.