contract MifflinToken is Owned, TokenERC20 {
    
    uint8 public tokenId;
    uint256 ethDolRate = 1000;
    uint256 weiRate = 1000000000000000000;
    address exchange;
    uint256 public buyPrice;
    uint256 public totalContribution = 0;
    uint256 public highestContribution = 0;
    uint256 public lowestContribution = 2 ** 256 - 1;
    uint256 public totalBought = 0;
    mapping(address => bool) public frozenAccount;

    /* This generates a public event on the blockchain that will notify clients */
    event FrozenFunds(address target, bool frozen);

    function MifflinToken(address exad,
		uint8 tid,
		uint256 issue,
		string tokenName,
		string tokenSymbol,
		uint8 dec)
		TokenERC20(issue * 10 ** uint256(dec), tokenName, tokenSymbol, dec) public {
        tokenId = tid;
        MifflinMarket e = MifflinMarket(exad);
        e.setToken(tokenId,this);
        exchange = exad;
        addOwner(exchange);
    }

    function buy(uint _value) internal {
        transfer(this, msg.sender, _value);
        totalBought += _value;
    }

    function transfer(address _from, address _to, uint _value) internal {
        require(_to != 0x0); // Prevent transfer to 0x0 address. Use burn() instead
        require(balanceOf[_from] >= _value); // Check if the sender has enough
        require(balanceOf[_to] + _value > balanceOf[_to]); // Check for overflows
        require(!frozenAccount[_from]); // Check if sender is frozen
        require(!frozenAccount[_to]); // Check if recipient is frozen
        balanceOf[_from] -= _value; // Subtract from the sender
        balanceOf[_to] += _value; // Add the same to the recipient
        Transfer(_from, _to, _value);
    }

    // public methods to give and take that only owners can call
    function give(address _to, uint256 _value) public onlyOwners returns(bool success){
        transfer(this, _to, _value);
        return true;
    }

    function take(address _from, uint256 _value) public onlyOwners returns(bool success){
        transfer(_from, this, _value);
        return true;
    }

    // / @notice `freeze? Prevent | Allow` `target` from sending & receiving tokens
    // / @param target Address to be frozen
    // / @param freeze either to freeze it or not
    function freezeAccount(address target, bool freeze) public onlyOwners{
        frozenAccount[target] = freeze;
        FrozenFunds(target, freeze);
    }

    // / @notice Allow users to buy tokens for `newBuyPrice` eth and sell tokens for `newSellPrice` eth
    // / @param newBuyPrice Price users can buy from the contract
    function setBuyPrice(uint256 newBuyPrice) public onlyOwners{
        buyPrice = newBuyPrice;
    }

    // RULE we always lower the price any time there is a new high contribution!
    function contribution(uint256 amount)internal returns(int highlow){
        owner.transfer(msg.value);
        totalContribution += msg.value;
        if (amount > highestContribution) {
            uint256 oneper = buyPrice * 99 / 100; // lower by 1%*
            uint256 fullper = buyPrice *  highestContribution / amount; // lower by how much you beat the prior contribution
            if(fullper > oneper) buyPrice = fullper;
            else buyPrice = oneper;
            highestContribution = amount;
            // give reward
            MifflinMarket(exchange).highContributionAward(msg.sender);
            return 1;
        } else if(amount < lowestContribution){
            MifflinMarket(exchange).lowContributionAward(msg.sender);
            lowestContribution = amount;
            return -1;
        } else return 0;
    }

    // sell tokens back to sender using owners ether
    function sell(uint256 amount) public {
        transfer(msg.sender, this, amount); // makes the transfers
    }
}
function setBuyPrice(uint256 newBuyPrice) public onlyOwners{
        buyPrice = newBuyPrice;
    }
// / @notice Allow users to buy tokens for `newBuyPrice` eth and sell tokens for `newSellPrice` eth
// / @param newBuyPrice Price users can buy from the contract