contract Administrable is Mortal{
    /** the different pots */
    uint public charityPot;
    uint public highscorePot;
    uint public affiliatePot;
    uint public surprisePot;
    uint public developerPot;
    /** the Percentage of the game stake which go into a pot with one decimal (25 => 2.5%) */
    uint public charityPercent = 25;
    uint public highscorePercent = 50;
    uint public affiliatePercent = 50;
    uint public surprisePercent = 25;
    uint public developerPercent = 50;
    uint public winnerPercent = 800;
    /** the current highscore holder **/
    address public highscoreHolder;
    address public signer;
    /** balance of affiliate partners */
    mapping (address => uint) public affiliateBalance;

    uint public minStake;
    uint public maxStake;

    /** tells if a hash has already been used for withdrawal **/
    mapping (bytes32 => bool) public used;
    event Withdrawal(uint8 pot, address receiver, uint value);

    modifier validAddress(address receiver){
        require(receiver != 0x0, "invalid receiver");
        _;
    }


    /**
     * set the minimum waiting time for withdrawal of funds of a started but not-finished game
     * */
    function setMinimumWait(uint newMin) public onlyOwner{
        minimumWait = newMin;
    }

    /**
     * withdraw from the developer pot
     * */
    function withdrawDeveloperPot(address receiver) public onlyOwner validAddress(receiver){
        uint value = developerPot;
        developerPot = 0;
        receiver.transfer(value);
        emit Withdrawal(0, receiver, value);
    }

    /**
     * withdraw from the charity pot
     * */
    function donate(address charity) public onlyOwner validAddress(charity){
        uint value = charityPot;
        charityPot = 0;
        charity.transfer(value);
        emit Withdrawal(1, charity, value);
    }

    /**
     * withdraw from the highscorePot
     * */
    function withdrawHighscorePot(address receiver) public validAddress(receiver){
        require(msg.sender == highscoreHolder);
        uint value = highscorePot;
        highscorePot = 0;
        receiver.transfer(value);
        emit Withdrawal(2, receiver, value);
    }

    /**
     * withdraw from the affiliate pot
     * */
    function withdrawAffiliateBalance(address receiver) public validAddress(receiver){
        uint value = affiliateBalance[msg.sender];
        require(value > 0);
        affiliateBalance[msg.sender] = 0;
        receiver.transfer(value);
        emit Withdrawal(3, receiver, value);
    }

    /**
     * withdraw from the surprise pot
     * */
    function withdrawSurprisePot(address receiver) public onlyOwner validAddress(receiver){
        uint value = surprisePot;
        surprisePot = 0;
        receiver.transfer(value);
        emit Withdrawal(4, receiver, value);
    }

    /**
     * allows an user to withdraw from the surprise pot with a valid signature
     * */
    function withdrawSurprisePotUser(uint value, uint expiry, uint8 v, bytes32 r, bytes32 s) public{
        require(expiry >= now, "signature expired");
        bytes32 hash = keccak256(abi.encodePacked(msg.sender, value, expiry));
        require(!used[hash], "same signature was used before");
        require(ecrecover(hash, v, r, s) == signer, "invalid signer");
        require(value <= surprisePot, "not enough in the pot");
        surprisePot -= value;
        used[hash] = true;
        msg.sender.transfer(value);
        emit Withdrawal(4, msg.sender, value);
    }

    /**
     * sets the signing address
     * */
    function setSigner(address signingAddress) public onlyOwner{
        signer = signingAddress;
    }

    /**
     * sets the pot Percentages
     * */
    function setPercentages(uint affiliate, uint charity, uint dev, uint highscore, uint surprise) public onlyOwner{
        uint sum =  affiliate + charity + highscore + surprise + dev;
        require(sum < 500, "winner should not lose money");
        charityPercent = charity;
        affiliatePercent = affiliate;
        highscorePercent = highscore;
        surprisePercent = surprise;
        developerPercent = dev;
        winnerPercent = 1000 - sum;
    }

    function setMinMax(uint newMin, uint newMax) public onlyOwner{
        minStake = newMin;
        maxStake = newMax;
    }
}
function setSigner(address signingAddress) public onlyOwner{
        signer = signingAddress;
    }
/**
 * sets the signing address
 * */