contract RigCraftPresalePackageToken is ERC721Basic, Administration, ERC721Metadata {
    bytes4 constant ERC721_RECEIVED = 0xf0b9e5ba;
    
    struct PresalePackage
    {
        uint8 packageId;
        uint16 serialNumber;
    }
    
    PresalePackage[] packages;
    
    // Mapping from token ID to owner
    mapping (uint256 => address) internal tokenOwner;
    mapping (uint256 => address) internal tokenApprovals;
    mapping (address => uint256) internal ownedTokensCount;
    mapping (address => mapping (address => bool)) internal operatorApprovals;
    
    RigCraftPresalePackageManager private presaleHandler;
    string URIBase;
    
    string public constant name = "RigCraftPresalePackage";
    string public constant symbol = "RCPT";
    
    function SetPresaleHandler(address addr) external onlyOwner
    {
        presaleHandler = RigCraftPresalePackageManager(addr);
    }
    
    function setURIBase(string _base) external onlyOwner
    {
        URIBase = _base;
    }
    
    modifier onlyOwnerOf(uint256 _tokenId) {
        require(ownerOf(_tokenId) == msg.sender);
        _;
    }

    modifier canTransfer(uint256 _tokenId) {
        require(isApprovedOrOwner(msg.sender, _tokenId));
        _;
    }
    
    /**
    * PUBLIC INTERFACE
    **/
    function balanceOf(address _owner) public view isOpen returns (uint256) {
        require(_owner != address(0));
        return ownedTokensCount[_owner];
    }

    function ownerOf(uint256 _tokenId) public view isOpen returns (address) {
        address owner = tokenOwner[_tokenId];
        require(owner != address(0));
        return owner;
    }

    function exists(uint256 _tokenId) public view isOpen returns (bool) {
        address owner = tokenOwner[_tokenId];
        return owner != address(0);
    }
    
    function totalSupply() public view returns (uint256) {
        return packages.length;
    }

    function approve(address _to, uint256 _tokenId) public
    isOpen
    isActive
    {
        address owner = ownerOf(_tokenId);
        require(_to != owner);
        require(msg.sender == owner || isApprovedForAll(owner, msg.sender));
        
        if (getApproved(_tokenId) != address(0) || _to != address(0)) {
            tokenApprovals[_tokenId] = _to;
            emit Approval(owner, _to, _tokenId);
        }
    }
    
    function getApproved(uint256 _tokenId) public view isOpen returns (address) {
        return tokenApprovals[_tokenId];
    }
    
    function setApprovalForAll(address _to, bool _approved) public
    isActive
    isOpen
    {
        require(_to != msg.sender);
        operatorApprovals[msg.sender][_to] = _approved;
        emit ApprovalForAll(msg.sender, _to, _approved);
    }

    function isApprovedForAll( address _owner, address _operator) public view
    isOpen
    returns (bool)
    {
        return operatorApprovals[_owner][_operator];
    }

    function transferFrom(address _from, address _to, uint256 _tokenId) public
    canTransfer(_tokenId)
    isActive
    isOpen
    {
        require(_from != address(0));
        require(_to != address(0));
        
        clearApproval(_from, _tokenId);
        removeTokenFrom(_from, _tokenId);
        addTokenTo(_to, _tokenId);
        
        emit Transfer(_from, _to, _tokenId);
    }
    
    function safeTransferFrom(address _from, address _to, uint256 _tokenId)
    public
    canTransfer(_tokenId)
    isActive
    isOpen
    {
        safeTransferFrom(_from, _to, _tokenId, "");
    }

    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes _data)
    public
    canTransfer(_tokenId)
    isActive
    isOpen
    {
        transferFrom(_from, _to, _tokenId);
        require(checkAndCallSafeTransfer(_from, _to, _tokenId, _data));
    }

    /**
    * INTERNALS
    **/
    function isApprovedOrOwner(address _spender,uint256 _tokenId) internal view
    returns (bool)
    {
        address owner = ownerOf(_tokenId);
        return (_spender == owner || getApproved(_tokenId) == _spender || isApprovedForAll(owner, _spender));
    }
    
    function clearApproval(address _owner, uint256 _tokenId) internal {
        require(ownerOf(_tokenId) == _owner);
        if (tokenApprovals[_tokenId] != address(0)) {
            tokenApprovals[_tokenId] = address(0);
            emit Approval(_owner, address(0), _tokenId);
        }
    }

    function addTokenTo(address _to, uint256 _tokenId) internal 
    {
        require(tokenOwner[_tokenId] == address(0));
        tokenOwner[_tokenId] = _to;
        ownedTokensCount[_to] += 1;
    }

    function removeTokenFrom(address _from, uint256 _tokenId) internal 
    {
        require(ownerOf(_tokenId) == _from);
        require(ownedTokensCount[_from] > 0);
        ownedTokensCount[_from] -= 1;
        tokenOwner[_tokenId] = address(0);
    }

    function checkAndCallSafeTransfer(address _from, address _to, uint256 _tokenId, bytes _data)
    internal
    returns (bool)
    {
        uint256 codeSize;
        assembly { codeSize := extcodesize(_to) }
        if (codeSize == 0) {
            return true;
        }
        bytes4 retval = ERC721Receiver(_to).onERC721Received(_from, _tokenId, _data);
        return (retval == ERC721_RECEIVED);
    }
    
    function tokenURI(uint256 _tokenId) external view returns (string)
    {
        string memory tokenNumber = uint2str(_tokenId);
        
        uint pos = bytes(URIBase).length;
        bytes memory retVal  = new bytes(bytes(tokenNumber).length + bytes(URIBase).length);
        uint i = 0;
        
        for(i = 0; i < bytes(URIBase).length; ++i)
        {
            retVal[i] = bytes(URIBase)[i];
        }
        for(i = 0; i < bytes(tokenNumber).length; ++i)
        {
            retVal[pos + i] = bytes(tokenNumber)[i];
        }
        
        return string(retVal);
    }
    
    function uint2str(uint256 i) internal pure returns (string)
    {
        if (i == 0) return "0";
        uint j = i;
        uint length;
        while (j != 0){
            length++;
            j /= 10;
        }
        bytes memory bstr = new bytes(length);
        uint k = length - 1;
        while (i != 0){
            bstr[k--] = byte(48 + i % 10);
            i /= 10;
        }
        return string(bstr);
    }
    
    // Get all token IDs of address
    function tokensOfOwner(address _owner) external view returns(uint256[] ownerTokens) 
    {
        uint256 tokenCount = balanceOf(_owner);
        
        if (tokenCount == 0) 
        {
            // Return an empty array
            return new uint256[](0);
        } else 
        {
            uint256[] memory result = new uint256[](tokenCount);
            uint256 resultIndex = 0;
            
            // We count on the fact that all cats have IDs starting at 1 and increasing
            // sequentially up to the totalCat count.
            uint256 tokenId;
            
            for (tokenId = 0; tokenId < packages.length; tokenId++) 
            {
                if (tokenOwner[tokenId] == _owner) 
                {
                    result[resultIndex] = tokenId;
                    resultIndex++;
                }
            }
        
            return result;
        }
    }
    
    /**
    * EXTERNALS
    **/
    function GetTokenData(uint256 _tokenId) external view returns(uint8 presalePackadeId, uint16 serialNO) 
    {
        require(_tokenId < packages.length);
        
        presalePackadeId = packages[_tokenId].packageId;
        serialNO = packages[_tokenId].serialNumber;
    }
    
    function CreateToken(address _owner, uint8 _packageId, uint16 _serial) external
    isActive
    isOpen
    {
        require(msg.sender == address(presaleHandler));
        uint256 tokenId = packages.length;
        packages.length += 1;
        
        packages[tokenId].packageId = _packageId;
        packages[tokenId].serialNumber = _serial;
        
        addTokenTo(_owner, tokenId);
    }
}
// core
function isApprovedOrOwner(address _spender,uint256 _tokenId) internal view
    returns (bool)
    {
        address owner = ownerOf(_tokenId);
        return (_spender == owner || getApproved(_tokenId) == _spender || isApprovedForAll(owner, _spender));
    }
/**
 * INTERNALS
 **/