contract IMCToken is ERC20Interface, Owned {
    using SafeMath for uint;

    string public symbol;
    string public  name;
    uint8 public decimals;
    uint _totalSupply;

    mapping(address => uint) balances;
    mapping(address => mapping(address => uint)) allowed;

    address public externalContractAddress;


    /**
     * 构造函数
     */
    constructor() public {
        symbol = "IMC";
        name = "IMC";
        decimals = 8;
        _totalSupply = 1000000000 * (10 ** uint(decimals));
        balances[owner] = _totalSupply;
        
        emit Transfer(address(0), owner, _totalSupply);
    }

    /**
     * 查询代币总发行量
     * @return unit 余额
     */
    function totalSupply() public view returns (uint) {
        return _totalSupply.sub(balances[address(0)]);
    }

    /**
     * 查询代币余额
     * @param _owner address 查询代币的地址
     * @return balance 余额
     */
    function balanceOf(address _owner) public view returns (uint balance) {
        return balances[_owner];
    }

    /**
     * 私有方法从一个帐户发送给另一个帐户代币
     * @param _from address 发送代币的地址
     * @param _to address 接受代币的地址
     * @param _value uint 接受代币的数量
     */
    function _transfer(address _from, address _to, uint _value) internal{
        // 确保目标地址不为0x0，因为0x0地址代表销毁
        require(_to != 0x0);
        // 检查发送者是否拥有足够余额
        require(balances[_from] >= _value);
        // 检查是否溢出
        require(balances[_to] + _value > balances[_to]);

        // 保存数据用于后面的判断
        uint previousBalance = balances[_from].add(balances[_to]);

        // 从发送者减掉发送额
        balances[_from] = balances[_from].sub(_value);
        // 给接收者加上相同的量
        balances[_to] = balances[_to].add(_value);

        // 通知任何监听该交易的客户端
        emit Transfer(_from, _to, _value);

        // 判断发送、接收方的数据是否和转换前一致
        assert(balances[_from].add(balances[_to]) == previousBalance);
    }

    /**
     * 从合约调用者发送给别人代币
     * @param _to address 接受代币的地址
     * @param _value uint 接受代币的数量
     * @return success 交易成功
     */
    function transfer(address _to, uint _value) public returns (bool success) {
        _transfer(msg.sender, _to, _value);

        return true;
    }

    /**
     * 账号之间代币交易转移，调用过程，会检查设置的允许最大交易额
     * @param _from address 发送者地址
     * @param _to address 接受者地址
     * @param _value uint 要转移的代币数量
     * @return success 交易成功
     */
    function transferFrom(address _from, address _to, uint _value) public returns (bool success) {
        
        if (_from == msg.sender) {
            // 自己转账时不需要approve，可以直接进行转账
            _transfer(_from, _to, _value);

        } else {
            // 授权给第三方时，需检查发送者是否拥有足够余额
            require(allowed[_from][msg.sender] >= _value);
            allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);

            _transfer(_from, _to, _value);

        }

        return true;
    }

    /**
     * 从主帐户合约发行代币
     * @param _to address 接受代币的地址
     * @param _value uint 接受代币的数量
     * @return success 交易成功
     */
    function issue(address _to, uint _value) public returns (bool success) {
        // 外部合约调用，需满足合约调用者和代币合约所设置的外部调用合约地址一致性
        require(msg.sender == externalContractAddress);

        _transfer(owner, _to, _value);

        return true;
    }

    /**
    * 允许帐户授权其他帐户代表他们提取代币
    * @param _spender 授权帐户地址
    * @param _value 代币数量
    * @return success 允许成功
    */
    function approve(address _spender, uint _value) public returns (bool success) {
        allowed[msg.sender][_spender] = _value;

        emit Approval(msg.sender, _spender, _value);

        return true;
    }

    /**
    * 查询被授权帐户的允许提取的代币数
    * @param _owner 授权者帐户地址
    * @param _spender 被授权者帐户地址
    * @return remaining 代币数量
    */
    function allowance(address _owner, address _spender) public view returns (uint remaining) {
        return allowed[_owner][_spender];
    }

    /**
     * 设置允许一个地址（合约）以我（创建交易者）的名义可最多花费的代币数。
     * @param _spender 被授权的地址（合约）
     * @param _value 最大可花费代币数
     * @param _extraData 发送给合约的附加数据
     * @return success 设置成功
     */
    function approveAndCall(address _spender, uint _value, bytes _extraData) public returns (bool success) {
        tokenRecipient spender = tokenRecipient(_spender);
        if (approve(_spender, _value)) {
            // 通知合约
            spender.receiveApproval(msg.sender, _value, this, _extraData);
            return true;
        }
    }

    /**
     * 设置允许外部合约地址调用当前合约
     * @param _contractAddress 合约地址
     * @return success 设置成功
     */
    function approveContractCall(address _contractAddress) public onlyOwner returns (bool){
        externalContractAddress = _contractAddress;
        
        return true;
    }

    /**
     * 不接收 Ether
     */
    function () public payable {
        revert();
    }
}
// ----------------------------------------------------------------------------
// ERC20 Token, with the addition of symbol, name and decimals and a
// fixed supply
// ----------------------------------------------------------------------------
function approve(address _spender, uint _value) public returns (bool success) {
    allowed[msg.sender][_spender] = _value;

    emit Approval(msg.sender, _spender, _value);

    return true;
}

/**
 * 允许帐户授权其他帐户代表他们提取代币
 * @param _spender 授权帐户地址
 * @param _value 代币数量
 * @return success 允许成功
 */