contract TokenExchanger is TokenERC20{
  using SafeMath for uint256;

    uint256 internal tokenPerEth;
    bool public opened;

    event ExchangeEtherToToken(address indexed from, uint256 etherValue, uint256 tokenPerEth);
    event ExchangeTokenToEther(address indexed from, uint256 etherValue, uint256 tokenPerEth);
    event WithdrawToken(address indexed to, uint256 value);
    event WithdrawEther(address indexed to, uint256 value);
    event SetExchangeRate(address indexed from, uint256 tokenPerEth);


    constructor(address _coOwner1,
                address _coOwner2,
                address _coOwner3,
                address _coOwner4,
                address _coOwner5)
        MultiOwnable( _coOwner1, _coOwner2, _coOwner3, _coOwner4, _coOwner5) public { opened = true; }

    /**
     * Initialize Exchanger Function
     *
     * Initialize Exchanger contract with tokenPerEth
     * and Initialize NemoCoin by calling initToken
     * It would call initToken in TokenERC20 with _tokenName, _tokenSymbol, _initalSupply
     * Last five arguments are manager account to supply currency (_marketSaleManager, _serviceOperationManager, _dividendManager, _incentiveManager, _reserveFundManager)
     *
     */
    function initExchanger(
        string calldata _tokenName,
        string calldata _tokenSymbol,
        uint256 _initialSupply,
        uint256 _tokenPerEth,
        address _marketSaleManager,
        address _serviceOperationManager,
        address _dividendManager,
        address _incentiveManager,
        address _reserveFundManager
    ) external onlyOwner committeeApproved {
        require(opened);
        //require(_tokenPerEth > 0 && _initialSupply > 0);  // [2019.03.05] Fixed for Mythril Vulerablity SWC ID:101
        require(_tokenPerEth > 0); // SmartDec Recommendations
        require(_marketSaleManager != address(0) &&
                _serviceOperationManager != address(0) &&
                _dividendManager != address(0) &&
                _incentiveManager != address(0) &&
                _reserveFundManager != address(0));
        require(_marketSaleManager != _serviceOperationManager &&
                _marketSaleManager != _dividendManager &&
                _marketSaleManager != _incentiveManager &&
                _marketSaleManager != _reserveFundManager &&
                _serviceOperationManager != _dividendManager &&
                _serviceOperationManager != _incentiveManager &&
                _serviceOperationManager != _reserveFundManager &&
                _dividendManager != _incentiveManager &&
                _dividendManager != _reserveFundManager &&
                _incentiveManager != _reserveFundManager); // SmartDec Recommendations

        super.initToken(_tokenName, _tokenSymbol, _initialSupply,
          // SmartDec Recommendations
          _marketSaleManager,
          _serviceOperationManager,
          _dividendManager,
          _incentiveManager,
          _reserveFundManager
        );
        tokenPerEth = _tokenPerEth;
        emit SetExchangeRate(msg.sender, tokenPerEth);
    }


    /**
     * Change tokenPerEth variable only by owner
     *
     * Because "TokenExchaner" is only used until be listed on the exchange,
     * tokenPerEth is needed by then and it would be managed by manager.
     */
    function setExchangeRate(uint256 _tokenPerEth) onlyOwner committeeApproved external returns (bool success){
        require(opened);
        require( _tokenPerEth > 0);
        tokenPerEth = _tokenPerEth;
        emit SetExchangeRate(msg.sender, tokenPerEth);

        success = true;
        return success;
    }

    function getExchangerRate() external view returns(uint256){
        return tokenPerEth;
    }

    /**
     * Exchange Ether To Token
     *
     * @notice Send `Nemo` tokens to msg sender as much as amount of ether received considering exchangeRate.
     */
    function exchangeEtherToToken() payable external noReentrancy returns (bool success){
        require(opened);
        uint256 tokenPayment;
        uint256 ethAmount = msg.value;

        require(ethAmount > 0);
        require(tokenPerEth != 0);
        tokenPayment = ethAmount.mul(tokenPerEth);

        super._transfer(address(this), msg.sender, tokenPayment);

        emit ExchangeEtherToToken(msg.sender, msg.value, tokenPerEth);

        success = true;
        return success;
    }

    /**
     * Exchange Token To Ether
     *
     * @notice Send Ether to msg sender as much as amount of 'Nemo' Token received considering exchangeRate.
     *
     * @param _value Amount of 'Nemo' token
     */
    function exchangeTokenToEther(uint256 _value) external noReentrancy returns (bool success){
      require(opened);
      require(tokenPerEth != 0);

      uint256 remainingEthBalance = address(this).balance;
      uint256 etherPayment = _value.div(tokenPerEth);
      uint256 remainder = _value % tokenPerEth; // [2019.03.06 Fixing Securify vulnerabilities-Division influences Transfer Amount]
      require(remainingEthBalance >= etherPayment);

      uint256 tokenAmount = _value.sub(remainder); // [2019.03.06 Fixing Securify vulnerabilities-Division influences Transfer Amount]
      super._transfer(msg.sender, address(this), tokenAmount); // [2019.03.06 Fixing Securify vulnerabilities-Division influences Transfer Amount]
      //require(address(msg.sender).send(etherPayment));
      address(msg.sender).transfer(etherPayment); // SmartDec Recommendations

      emit ExchangeTokenToEther(address(this), etherPayment, tokenPerEth);
      success = true;
      return success;
    }

    /**
     * Withdraw token from TokenExchanger contract
     *
     * @notice Withdraw charged Token to _recipient.
     *
     * @param _recipient The address to which the token was issued.
     * @param _value Amount of token to withdraw.
     */
    function withdrawToken(address _recipient, uint256 _value) onlyOwner committeeApproved noReentrancy public {
      //require(opened);
      super._transfer(address(this) ,_recipient, _value);
      emit WithdrawToken(_recipient, _value);
    }


    /**
     * Withdraw Ether from TokenExchanger contract
     *
     * @notice Withdraw charged Ether to _recipient.
     *
     * @param _recipient The address to which the Ether was issued.
     * @param _value Amount of Ether to withdraw.
     */
    function withdrawEther(address payable _recipient, uint256 _value) onlyOwner committeeApproved noReentrancy public {
        //require(opened);
        //require(_recipient.send(_value));
        _recipient.transfer(_value); // SmartDec Recommendations
        emit WithdrawEther(_recipient, _value);
    }

    /**
     * close the TokenExchanger functions permanently
     *
     * @notice This contract would be closed when the coin is actively traded and judged that its TokenExchanger function is not needed.
     */
    function closeExchanger() onlyOwner committeeApproved external {
        opened = false;
    }
}
/**
 * @title TokenExchanger
 * @notice This is for exchange between Ether and 'Nemo' token
 *          It won't be needed after being listed on the exchange.
 */
function withdrawToken(address _recipient, uint256 _value) onlyOwner committeeApproved noReentrancy public {
  //require(opened);
  super._transfer(address(this) ,_recipient, _value);
  emit WithdrawToken(_recipient, _value);
}

/**
 * Withdraw token from TokenExchanger contract
 *
 * @notice Withdraw charged Token to _recipient.
 *
 * @param _recipient The address to which the token was issued.
 * @param _value Amount of token to withdraw.
 */