contract RoyalStables is Ownable,ERC721Token {
    /**
        @dev Structure to hold Horsey collectible information
        @dev should be as small as possible but since its already greater than 256
        @dev lets keep it <= 512
    */
    struct Horsey {
        address race;       /// @dev Stores the original race address this horsey was claimed from
        bytes32 dna;        /// @dev Stores the horsey dna
        uint8 feedingCounter;   /// @dev Boils down to how many times has this horsey been fed
        uint8 tier;         /// @dev Used internaly to assess chances of a rare trait developing while feeding
    }

    /// @dev Maps all token ids to a unique Horsey
    mapping(uint256 => Horsey) public horseys;

    /// @dev Maps addresses to the amount of carrots they own
    mapping(address => uint32) public carrot_credits;

    /// @dev Maps a horsey token id to the horsey name
    mapping(uint256 => string) public names;

    /// @dev Master is the current Horsey contract using this library
    address public master;

    /**
        @dev Contracts constructor
    */
    constructor() public
    Ownable()
    ERC721Token("HORSEY","HRSY") {
    }

    /**
        @dev Allows to change the address of the current Horsey contract
        @param newMaster Address of the current Horsey contract
    */
    function changeMaster(address newMaster) public
    validAddress(newMaster)
    onlyOwner() {
        master = newMaster;
    }

    /**
        @dev Gets the complete list of token ids which belongs to an address
        @param eth_address The address you want to lookup owned tokens from
        @return List of all owned by eth_address tokenIds
    */
    function getOwnedTokens(address eth_address) public view returns (uint256[]) {
        return ownedTokens[eth_address];
    }

    /**
        @dev Stores a horsey name
        @param tokenId Horsey token id
        @param newName New horsey name
    */
    function storeName(uint256 tokenId, string newName) public
    onlyMaster() {
        require(exists(tokenId),"token not found");
        names[tokenId] = newName;
    }

    /**
        @dev Stores carrot credits on the clients account
        @param client Client we need to update the balance of
        @param amount Amount of carrots to store
    */
    function storeCarrotsCredit(address client, uint32 amount) public
    onlyMaster()
    validAddress(client) {
        carrot_credits[client] = amount;
    }

    function storeHorsey(address client, uint256 tokenId, address race, bytes32 dna, uint8 feedingCounter, uint8 tier) public
    onlyMaster()
    validAddress(client) {
        //_mint checks if the token exists before minting already, so we dont have to here
        _mint(client,tokenId);
        modifyHorsey(tokenId,race,dna,feedingCounter,tier);
    }

    function modifyHorsey(uint256 tokenId, address race, bytes32 dna, uint8 feedingCounter, uint8 tier) public
    onlyMaster() {
        require(exists(tokenId),"token not found");
        Horsey storage hrsy = horseys[tokenId];
        hrsy.race = race;
        hrsy.dna = dna;
        hrsy.feedingCounter = feedingCounter;
        hrsy.tier = tier;
    }

    function modifyHorseyDna(uint256 tokenId, bytes32 dna) public
    onlyMaster() {
        require(exists(tokenId),"token not found");
        horseys[tokenId].dna = dna;
    }

    function modifyHorseyFeedingCounter(uint256 tokenId, uint8 feedingCounter) public
    onlyMaster() {
        require(exists(tokenId),"token not found");
        horseys[tokenId].feedingCounter = feedingCounter;
    }

    function modifyHorseyTier(uint256 tokenId, uint8 tier) public
    onlyMaster() {
        require(exists(tokenId),"token not found");
        horseys[tokenId].tier = tier;
    }

    function unstoreHorsey(uint256 tokenId) public
    onlyMaster()
    {
        require(exists(tokenId),"token not found");
        _burn(ownerOf(tokenId),tokenId);
        delete horseys[tokenId];
        delete names[tokenId];
    }

    /// @dev requires the address to be non null
    modifier validAddress(address addr) {
        require(addr != address(0),"Address must be non zero");
        _;
    }

     /// @dev requires the caller to be the master
    modifier onlyMaster() {
        require(master == msg.sender,"Address must be non zero");
        _;
    }
}
/**
 @title RoyalStables Holding HRSY token
 */
function getOwnedTokens(address eth_address) public view returns (uint256[]) {
    return ownedTokens[eth_address];
}

/**
 @dev Gets the complete list of token ids which belongs to an address
 @param eth_address The address you want to lookup owned tokens from
 @return List of all owned by eth_address tokenIds
 */