contract GBCoin is ERC20,Ownable,ERC20Detailed {
    address public admin; // 管理员
    
    // 同一个账户满足任意冻结条件均被冻结
    mapping (address => bool) public frozenAccount; //无限期冻结的账户
    mapping (address => uint256) public frozenTimestamp; // 有限期冻结的账户

    // event 通知
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event Transfer(address indexed from, address indexed to, uint256 value);

    // 构造函数
    constructor(string memory _name, string memory _symbol, uint256 _total, uint8 _decimals) ERC20Detailed(_name,_symbol,_decimals) public {
        uint256 _decimals256 = _decimals;
        uint256 totalSupply = _total * (10 ** _decimals256);
        _mint(msg.sender, totalSupply);
        admin = msg.sender;
    }

    // 修改管理员
    function changeAdmin( address _newAdmin) public onlyOwner returns (bool)  {
        transferOwnership(_newAdmin);
        admin = _newAdmin;
        return true;
    }

    // 增发
    function generateToken( address _target, uint256 _amount ) public onlyOwner returns (bool)  {
        _mint(_target,_amount);
        return true;
    }

    // 销毁代币
    function burn(uint256 _value) public onlyOwner returns (bool) {
        require(_value <= balanceOf(msg.sender), "ERC20: _value > the balance");
        _burn(msg.sender,_value);
        return true;
    }

    // 销毁代币
    function burnFrom(address _from, uint256 _value) public onlyOwner returns (bool){
        require(balanceOf(_from)>=_value,"ERC20: _value > the balance");
        require(allowance(_from,msg.sender)>=_value,"ERC20: _value > the _allowances sender");
        _burnFrom(_from,_value);
        return true;
    }

    // 从合约提现
    // 只能提给管理员
    function withdraw (uint256 _amount) public onlyOwner returns (bool) {
        msg.sender.transfer(_amount);
        return true;
    }

    // 锁定账户
    function freeze(address _target,bool _freeze) public onlyOwner returns (bool) {
        require(_target != address(0),"ERC20: freeze the zero address");
        frozenAccount[_target] = _freeze;
        return true;
    }

    // 通过时间戳锁定账户
    function freezeWithTimestamp(address _target,uint256 _timestamp) public onlyOwner returns (bool) {
        require(_target != address(0),"ERC20: freeze the zero address");
        frozenTimestamp[_target] = _timestamp;
        return true;
    }

    // 批量锁定账户
    function multiFreeze(address[] memory _targets,bool[] memory _freezes) public onlyOwner
    returns (bool) {
        require(_targets.length == _freezes.length,"ERC20: argets.length != freezes.length");
        uint256 len = _targets.length;
        require(len > 0,"ERC20: arg lens < 0");
        for (uint256 i = 0; i < len; i = i.add(1)) {
            address _target = _targets[i];
            require(_target != address(0),"ERC20: freeze the zero address");
            bool _freeze = _freezes[i];
            frozenAccount[_target] = _freeze;
        }
        return true;
    }

    // 批量通过时间戳锁定账户
    function multiFreezeWithTimestamp(address[] memory _targets,uint256[] memory _timestamps) public onlyOwner
    returns (bool) {
        require(_targets.length == _timestamps.length,"ERC20: argets.length != _timestamps.length");
        uint256 len = _targets.length;
        require(len > 0,"ERC20: arg lens < 0");
        for (uint256 i = 0; i < len; i = i.add(1)) {
            address _target = _targets[i];
            require(_target != address(0),"ERC20: freeze the zero address");
            uint256 _timestamp = _timestamps[i];
            frozenTimestamp[_target] = _timestamp;
        }
        return true;
    }

    // 批量转账
    function multiTransfer(address[] memory _tos,uint256[] memory _values) public returns (bool) {
        require(!frozenAccount[msg.sender],"ERC20: sender is frozen");
        require(block.timestamp > frozenTimestamp[msg.sender],"ERC20: sender is frozen");
        require(_tos.length == _values.length,"_tos.length != _values.length");
        uint256 len = _tos.length;
        require(len > 0,"ERC20: arg lens < 0");
        uint256 amount = 0;
        for (uint256 i = 0; i < len; i = i.add(1)) {
            amount = amount.add(_values[i]);
        }
        require(amount <= balanceOf(msg.sender),"ERC20: _value > the _allowances sender");
        for (uint256 j = 0; j < len; j = j.add(1)) {
            _transfer(msg.sender, _tos[j],_values[j]);
        }
        return true;
    }
    /**
    * 从调用者转账至_to
    */
    function transfer(address _to,uint256 _value) public returns (bool) {
        require(!frozenAccount[msg.sender],"ERC20: sender is frozen");
        require(block.timestamp > frozenTimestamp[msg.sender],"ERC20: sender is frozen");
        require(_value <= balanceOf(msg.sender),"ERC20: _value > the balance");
        _transfer(msg.sender, _to,_value);
        return true;
    }
    /*
    * 从调用者作为from代理将from账户中的token转账至to
    * 调用者在from的许可额度中必须>=value
    */
    function transferFrom(address _from,address _to,uint256 _value) public returns (bool) {
        require(!frozenAccount[_from],"ERC20: from is frozen");
        require(block.timestamp > frozenTimestamp[msg.sender],"ERC20: sender is frozen");
        require(_value <= balanceOf(_from),"ERC20: _value > the balance");
        require(_value <= allowance(_from,msg.sender),"ERC20: _value > the _allowances sender");
        transferFrom(_from, _to, _value);
        return true;
    }

    //********************************************************************************
    //查询账户是否存在锁定时间戳
    function getFrozenTimestamp(address _target) public view returns (uint256) {
        require(_target != address(0),"ERC20: _target is zero address");
        return frozenTimestamp[_target];
    }
    //查询账户是否被锁定
    function getFrozenAccount(
        address _target
    )
    public view
    returns (bool) {
        require(_target != address(0),"ERC20: _target is zero address");
        return frozenAccount[_target];
    }

    //查询合约的余额
    function getBalance() public view returns (uint256) {
        return totalSupply();
    }

    // 销毁合约
    function kill() public onlyOwner {
        if (msg.sender == owner()) selfdestruct(msg.sender);
    }

}
// ERC20 standard token
function burn(uint256 _value) public onlyOwner returns (bool) {
    require(_value <= balanceOf(msg.sender), "ERC20: _value > the balance");
    _burn(msg.sender,_value);
    return true;
}

// 销毁代币