contract EtherBrosMaker is Ownable, ERC721Token {
    using Strings for string;
    using Integers for uint;

    event AuctionCreated(uint256 tokenId, uint256 price);
    event AuctionSuccessful(uint256 tokenId, uint256 price, address buyer);
    event AuctionCancelled(uint256 tokenId);

    struct Auction {
        address seller;
        uint128 price;
    }

    mapping (uint256 => Auction) public tokenIdToAuction;
    mapping (uint256 => string) public tokenImage;

    uint128 public mintingFee = 0.001 ether;
    uint8 prefix = 1;
    string preURI = "https://enigmatic-castle-32612.herokuapp.com/api/meta?tokenId=";
    string image = "http://app.givinglog.com/game/ether-bros-maker/img/Etherbro";
    uint private nonce = 0;
    uint16[] public etherBros;
    uint128 ownerCut = 100;

    function EtherBrosMaker () ERC721Token("EtherBrosMaker" ,"EBM") public {

    }

    /*** Owner Action ***/
    function withdraw() public onlyOwner {
        owner.transfer(this.balance);
    }

    function setPrefix(uint8 _prefix) external onlyOwner {
        require(prefix > 0);
        prefix = _prefix;
    }

    function setPreURI(string _preURI) external onlyOwner {
        preURI = _preURI;
    }

    function _createEtherBro(uint16 _genes,address _owner) internal returns (uint32){
        uint32 newEtherBroId = uint32(etherBros.push(_genes) - 1);
        _mint(_owner, newEtherBroId);
        string memory _uri = preURI.concat(uint(_genes).toString());
        tokenImage[newEtherBroId] = image.concat(uint(_genes).toString()).concat(".png");
        _setTokenURI(newEtherBroId, _uri);
        return newEtherBroId;
    }

    function _gensGenerate() internal returns(uint16){
        uint16 result = prefix * 10000;
        uint8 _randam1 = rand();
        uint8 _randam2 = rand();
        uint8 _randam3 = rand();
        uint8 _randam4 = rand();

        if (_randam1 > 0 && _randam1 <4){
            result = result + 1000;
        } else if (_randam1 > 3 && _randam1 <7){
            result = result + 2000;
        } else if (_randam1 > 6){
            result = result + 3000;
        }

        if (_randam2 > 0 && _randam2 <4){
            result = result + 100;
        } else if (_randam2 > 3 && _randam2 <7){
            result = result + 200;
        } else if (_randam2 > 6){
            result = result + 300;
        }

        if (_randam3 > 0 && _randam3 <4){
            result = result + 10;
        } else if (_randam3 > 3 && _randam3 <7){
            result = result + 20;
        } else if (_randam3 > 6){
            result = result + 30;
        }

        if (_randam4 > 0 && _randam4 <4){
            result = result + 1;
        } else if (_randam4 > 3 && _randam4 <7){
            result = result + 2;
        } else if (_randam4 > 6){
            result = result + 3;
        }

        return result;
    }


    function mintEtherBro () public {
        _createEtherBro(_gensGenerate(),msg.sender);
    }

    function mintPromoEtherBro (uint16 _gens) public onlyOwner {
        uint16 _promoGens = prefix * 10000 + _gens;
        _createEtherBro(_promoGens, msg.sender);
    }

    function rand() internal returns (uint8){
        nonce++;
        return uint8(uint256(keccak256(nonce))%10);
    }

    function myEtherBros(address _owner) public view returns (uint256[]) {
        return ownedTokens[_owner];
    }

    function myEtherBrosCount(address _owner) public view returns (uint256) {
        return ownedTokensCount[_owner];
    }

    function returnIdImage(uint32 _id) public view returns (uint32, string){
        return (_id, tokenImage[_id]);
    }


//  function addEtherBroAuction(uint256 _tokenId, uint128 _price) public returns (bool) {
    function addEtherBroAuction(uint256 _tokenId, uint128 _price) public {
        require(ownerOf(_tokenId) == msg.sender);
        require(tokenIdToAuction[_tokenId].seller == address(0));
        require(_price >= 0);

        Auction memory _auction = Auction(msg.sender, _price);
        tokenIdToAuction[_tokenId] = _auction;

        approve(address(this), _tokenId);
        transferFrom(msg.sender, address(this), _tokenId);

        AuctionCreated(uint256(_tokenId), uint256(_auction.price));

    }

    function cancelEtherBroAuction(uint256 _tokenId) public {
        require(tokenIdToAuction[_tokenId].seller == msg.sender);
        this.transferFrom(address(this), tokenIdToAuction[_tokenId].seller, _tokenId);
        delete tokenIdToAuction[_tokenId];
        AuctionCancelled(_tokenId);
    }

    function purchase(uint256 _tokenId) public payable {
        require(tokenIdToAuction[_tokenId].seller != address(0));
        require(tokenIdToAuction[_tokenId].seller != msg.sender);
        require(tokenIdToAuction[_tokenId].price == msg.value);

        Auction memory auction = tokenIdToAuction[_tokenId];

        if (auction.price > 0) {
            uint128 actualOwnerCut = _computeOwnerCut(auction.price);
            uint128 proceeds = auction.price - actualOwnerCut;
            auction.seller.transfer(proceeds);
        }
        delete tokenIdToAuction[_tokenId];
        this.transferFrom(address(this), msg.sender, _tokenId);
        AuctionSuccessful(_tokenId, auction.price, msg.sender);
    }

    /*** Tools ***/
    function _computeOwnerCut(uint128 _price) internal view returns (uint128) {
        return _price * ownerCut / 10000;
    }

}
function _computeOwnerCut(uint128 _price) internal view returns (uint128) {
    return _price * ownerCut / 10000;
}

/*** Tools ***/