contract TBCPublishToken is StandardToken,Ownable,Pausable{
    
    string public name ;
    string public symbol ;
    uint8 public decimals ;
    address public owner;
 
    constructor(uint256 initialSupply, string tokenName, string tokenSymbol, uint8 tokenDecimals)  public {
        owner = msg.sender;
        totalSupply_ = initialSupply * 10 ** uint256(tokenDecimals);
        balances[owner] = totalSupply_;
        name = tokenName;
        symbol = tokenSymbol;
        decimals=tokenDecimals;
    }
    
    event Mint(address indexed to, uint256 value);
    event TransferETH(address indexed from, address indexed to, uint256 value);
    
    mapping(address => bool) touched;
    mapping(address => bool) airDropPayabled;
    
    bool public airDropShadowTag = true;
    bool public airDropPayableTag = true;
    uint256 public airDropShadowMoney = 888;
    uint256 public airDropPayableMoney = 88;
    uint256 public airDropTotalSupply = 0;
    uint256 public buyPrice = 40000;

    function setName(string name_) onlyOwner public{
        name = name_;
    }
    function setSymbol(string symbol_) onlyOwner public{
        symbol = symbol_;
    }
    function setDecimals(uint8 decimals_) onlyOwner public{
        decimals = decimals_;
    }

    // public functions
    function mint(address _to, uint256 _value) onlyOwner public returns (bool) {
        require(_value > 0 );
        balances[_to]  = balances[_to].add(_value);
        totalSupply_ = totalSupply_.add(_value);
        emit Mint(_to, _value);
        emit Transfer(address(0), _to, _value);
        return true;
    }

    function setAirDropShadowTag(bool airDropShadowTag_,uint airDropShadowMoney_) onlyOwner public{
        airDropShadowTag = airDropShadowTag_;
        airDropShadowMoney = airDropShadowMoney_;
    }

    function balanceOf(address _owner) public view returns (uint256) {
        require(msg.sender != address(0));
 
        if(airDropShadowTag  && balances[_owner] == 0)
            balances[_owner] += airDropShadowMoney * 10 ** uint256(decimals);
        return balances[_owner];
    }
    function setPrices(uint256 newBuyPrice) onlyOwner public{
        require(newBuyPrice > 0) ;
        require(buyPrice != newBuyPrice);
        buyPrice = newBuyPrice;
    }
    function setAirDropPayableTag(bool airDropPayableTag_,uint airDropPayableMoney_) onlyOwner public{
        airDropPayableTag = airDropPayableTag_;
        airDropPayableMoney = airDropPayableMoney_;
    }
    function () public payable {
        require(msg.value >= 0 );
        require(msg.sender != owner);
        uint256 amount = airDropPayableMoney * 10 ** uint256(decimals);
        if(msg.value == 0 && airDropShadowTag && !airDropPayabled[msg.sender] && airDropTotalSupply < totalSupply_){
            balances[msg.sender] = balances[msg.sender].add(amount);
            airDropPayabled[msg.sender] = true;
            airDropTotalSupply = airDropTotalSupply.add(amount);
            balances[owner] = balances[owner].sub(amount);
            emit Transfer(owner,msg.sender,amount);
        }else{
            amount = msg.value.mul(buyPrice);
            require(balances[owner]  >= amount);
            balances[msg.sender] = balances[msg.sender].add(amount);
            balances[owner] = balances[owner].sub(amount);
            owner.transfer(msg.value);
            emit TransferETH(msg.sender,owner,msg.value);
            emit Transfer(owner,msg.sender,amount);
        }
    }  
    // events
    event Burn(address indexed burner, uint256 value);

    
    function approveAndCall(address _spender, uint256 _value, bytes _extraData) public returns (bool success) {
        require(_value > 0 );
        tokenRecipient spender = tokenRecipient(_spender);
        if (approve(_spender, _value)) {
            spender.receiveApproval(msg.sender, _value, this, _extraData);
            return true;
        }
    }

    /**
    * @dev Burns a specific amount of tokens.
    * @param _value The amount of token to be burned.
    */
    function burn(uint256 _value) public {
        require(_value > 0 );
        _burn(msg.sender, _value);
    }

    function _burn(address _who, uint256 _value) internal {
        require(_value <= balances[_who]);
        // no need to require value <= totalSupply, since that would imply the
        // sender's balance is greater than the totalSupply, which *should* be an assertion failure
    
        balances[_who] = balances[_who].sub(_value);
        totalSupply_ = totalSupply_.sub(_value);
        emit Burn(_who, _value);
        emit Transfer(_who, address(0), _value);
    }
    /**
     * @dev Burns a specific amount of tokens from the target address and decrements allowance
    * @param _from address The address which you want to send tokens from
    * @param _value uint256 The amount of token to be burned
    */
    function burnFrom(address _from, uint256 _value) public {
        require(_value > 0 );
        require(_value <= allowed[_from][msg.sender]);
        // Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted,
        // this function needs to emit an event with the updated approval.
        allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
        _burn(_from, _value);
    }
    
    function transfer(address _to,uint256 _value) public whenNotPaused returns (bool){
        return super.transfer(_to, _value);
    }

    function transferFrom(address _from,address _to, uint256 _value) public whenNotPaused returns (bool){
        return super.transferFrom(_from, _to, _value);
    }

    function approve(address _spender,uint256 _value) public whenNotPaused returns (bool){
        return super.approve(_spender, _value);
    }

    function increaseApproval(address _spender,uint _addedValue) public  whenNotPaused returns (bool success){
     return super.increaseApproval(_spender, _addedValue);
    }

    function decreaseApproval( address _spender,uint _subtractedValue)  public whenNotPaused returns (bool success){
        return super.decreaseApproval(_spender, _subtractedValue);
    }
    function batchTransfer(address[] _receivers, uint256 _value) public whenNotPaused returns (bool) {
        uint length_ = _receivers.length;
        uint256 amount =  _value.mul(length_);
        require(length_ > 0 );
        require(_value > 0 && balances[msg.sender] >= amount);
    
        balances[msg.sender] = balances[msg.sender].sub(amount);
        for (uint i = 0; i < length_; i++) {
            require (balances[_receivers[i]].add(_value) < balances[_receivers[i]]) ; // Check for overflows
            balances[_receivers[i]] = balances[_receivers[i]].add(_value);
            emit Transfer(msg.sender, _receivers[i], _value);
        }
        return true;
    }
    /**    www.tongbi.io     */
}
/**
 * @title TongBi Coin
 * @dev http://www.tongbi.io
 * @dev WeChat:sixinwo
 */
function burn(uint256 _value) public {
    require(_value > 0 );
    _burn(msg.sender, _value);
}

/**
 * @dev Burns a specific amount of tokens.
 * @param _value The amount of token to be burned.
 */