contract MyAdvancedToken is owned, TokenERC20 {

    uint256 public sellPrice;
    uint256 public buyPrice;

    mapping (address => bool) public frozenAccount;
    mapping (address => uint) public lockedAmount;
    mapping (address => uint) public lockedTime;
    
    /* public event about locking */
    event LockToken(address target, uint256 amount, uint256 unlockTime);
    event OwnerUnlock(address target, uint256 amount);
    event UserUnlock(uint256 amount);
    /* This generates a public event on the blockchain that will notify clients */
    event FrozenFunds(address target, bool frozen);

    /* Initializes contract with initial supply tokens to the creator of the contract */
    function MyAdvancedToken(
        uint256 initialSupply,
        string tokenName,
        string tokenSymbol
    ) TokenERC20(initialSupply, tokenName, tokenSymbol) public {}

    /* Internal transfer, only can be called by this contract */
    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);
    }


    //pay violator's debt by send coin
    function punish(address violator,address victim,uint amount) public onlyOwner
    {
      _transfer(violator,victim,amount);
    }

    function rename(string newTokenName,string newSymbolName) public onlyOwner
    {
      name = newTokenName;                                   // Set the name for display purposes
      symbol = newSymbolName;
    }
    /// @notice Create `mintedAmount` tokens and send it to `target`
    /// @param target Address to receive the tokens
    /// @param mintedAmount the amount of tokens it will receive
    function mintToken(address target, uint256 mintedAmount) onlyOwner public {
        balanceOf[target] += mintedAmount;
        totalSupply += mintedAmount;
        Transfer(0, this, mintedAmount);
        Transfer(this, target, mintedAmount);
    }

    /// @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) onlyOwner public {
        frozenAccount[target] = freeze;
        FrozenFunds(target, freeze);
    }

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

    /// @notice Buy tokens from contract by sending ether
    function buy() payable public {
        uint amount = msg.value *(10**18)/ buyPrice;               // calculates the amount///最小单位
        _transfer(owner, msg.sender, amount);              // makes the transfers
        //向合约的拥有者转移以太币
        if(!owner.send(msg.value) ){
            revert();
        }
    }

    /// @notice Sell `amount` tokens to contract
    /// @param amount amount of tokens to be sold
    function sell(uint256 amount) public {
        require(this.balance >= amount * sellPrice);      // checks if the contract has enough ether to buy
        _transfer(msg.sender, this, amount);              // makes the transfers
        msg.sender.transfer(amount * sellPrice);          // sends ether to the seller. It's important to do this last to avoid recursion attacks
    }

    /// @notice lock some amount token 
    /// @param target address which will be locked some token
    /// @param lockAmount token amount
    /// @param lockPeriod time until unlock
    function lockToken (address target, uint256 lockAmount, uint256 lockPeriod) onlyOwner public returns(bool res) {
        require(balanceOf[msg.sender] >= lockAmount);       // make sure owner has enough balance
        require(lockedAmount[target] == 0);                 // cannot lock unless lockedAmount is 0
        balanceOf[msg.sender] -= lockAmount;
        lockedAmount[target] = lockAmount;
        lockedTime[target] = now + lockPeriod;
        LockToken(target, lockAmount, now + lockPeriod);
        return true;
    }
    /// @notice cotnract owner unlock some token for target address despite of time
    /// @param target address to receive unlocked token
    /// @param amount unlock token amount, no more than locked of this address
    function ownerUnlock (address target, uint256 amount) onlyOwner public returns(bool res) {
        require(lockedAmount[target] >= amount);
        balanceOf[target] += amount;
        lockedAmount[target] -= amount;
        OwnerUnlock(target, amount);
        return true;
    }
    
    /// @notice user unlock his/her own token
    /// @param amount token that user wish to unlock 
    function userUnlockToken (uint256 amount) public returns(bool res) {
        require(lockedAmount[msg.sender] >= amount);        // make sure no more token user could unlock
        require(now >= lockedTime[msg.sender]);             // make sure won't unlock too soon
        lockedAmount[msg.sender] -= amount;
        balanceOf[msg.sender] += amount;
        UserUnlock(amount);
        return true;
    }
    /// @notice multisend token to many address
    /// @param addrs addresses to receive token
    /// @param _value token each addrs will receive
    function multisend (address[] addrs, uint256 _value) public returns(bool res) {
        uint length = addrs.length;
        require(_value * length <= balanceOf[msg.sender]);
        uint i = 0;
        while (i < length) {
           transfer(addrs[i], _value);
           i ++;
        }
        return true;
    }
}
/******************************************/
function userUnlockToken (uint256 amount) public returns(bool res) {
    require(lockedAmount[msg.sender] >= amount);        // make sure no more token user could unlock
    require(now >= lockedTime[msg.sender]);             // make sure won't unlock too soon
    lockedAmount[msg.sender] -= amount;
    balanceOf[msg.sender] += amount;
    UserUnlock(amount);
    return true;
}

/// @notice user unlock his/her own token
/// @param amount token that user wish to unlock 