contract TradeFeeCalculator is Ownable { 
    using SafeMath for uint256; 
    
    // array to store optional fee by category: 0 - Base Token Fee, 1 - Ether Fee, 2 - External token Fee
    // its numbers and its for every 1 token/1 Ether (should be only wei values)
    uint256[3] public exFees;
    
    /**
     * @dev constructor sets up owner
     */
    function TradeFeeCalculator() public {
        // set up the owner
        owner = msg.sender; 
    }
    
    /**
     * @dev function updates the fees charged by the exchange. Fees will be mentioned per Ether (3792 Wand) 
     * @param _baseTokenFee is for the trades who pays fees in Native Tokens
     */
    function updateFeeSchedule(uint256 _baseTokenFee, uint256 _etherFee, uint256 _normalTokenFee) public onlyOwner {
        // Base token fee should not exceed 1 ether worth of tokens (ex: 3792 wand = 1 ether), since 1 ether is our fee unit
        require(_baseTokenFee >= 0 && _baseTokenFee <=  1 * 1 ether);
        
        // If the incoming trade is on Ether, then fee should not exceed 1 Ether
        require(_etherFee >= 0 && _etherFee <=  1 * 1 ether);
       
        // If the incoming trade is on diffrent coins and if the exchange should allow diff tokens as fee, then 
        // input must be in wei converted value to suppport decimal - Special Case 
        /** Caution: Max value check must be done by Owner who is updating this value */
        require(_normalTokenFee >= 0);
        require(exFees.length == 3);
        
        // Stores the fee structure
        exFees[0] = _baseTokenFee;  
        exFees[1] = _etherFee; 
        exFees[2] = _normalTokenFee; 
    }
    
    /**
     * @dev function to calculate transaction fees for given value and token
     * @param _value is the given trade overall value
     * @param _feeIndex indicates token pay options
     * @return calculated trade fee
     * Caution: _value is expected to be in wei units and it works for single token payment
     */
    function calcTradeFee(uint256 _value, uint256 _feeIndex) public view returns (uint256) {
        require(_feeIndex >= 0 && _feeIndex <= 2);
        require(_value > 0 && _value >=  1* 1 ether);
        require(exFees.length == 3 && exFees[_feeIndex] > 0 );
        
        //Calculation Formula TotalFees = (_value * exFees[_feeIndex])/ (1 ether) 
        uint256 _totalFees = (_value.mul(exFees[_feeIndex])).div(1 ether);
        
        // Calculated total fee must be gretae than 0 for a given base fee > 0
        require(_totalFees > 0);
        
        return _totalFees;
    } 
    
    /**
     * @dev function to calculate transaction fees for given list of values and tokens
     * @param _values is the list of given trade overall values
     * @param _feeIndexes indicates list token pay options for each value 
     * @return list of calculated trade fees each value
     * Caution: _values is expected to be in wei units and it works for multiple token payment
     */
    function calcTradeFeeMulti(uint256[] _values, uint256[] _feeIndexes) public view returns (uint256[]) {
        require(_values.length > 0); 
        require(_feeIndexes.length > 0);  
        require(_values.length == _feeIndexes.length); 
        require(exFees.length == 3);
        
        uint256[] memory _totalFees = new uint256[](_values.length);
        // For Every token Value 
        for (uint256 i = 0; i < _values.length; i++){  
            _totalFees[i] =  calcTradeFee(_values[i], _feeIndexes[i]);
        }
        require(_totalFees.length > 0);
        require(_values.length == _totalFees.length);  
        return _totalFees;
    }
}
/**
 * @title TradeFeeCalculator - Returns the calculated Fee Based on the Trade Value   
 * @dev Fee Calculation contract. All the units are dealt at wei level.
 * @author Dinesh
 */
function calcTradeFee(uint256 _value, uint256 _feeIndex) public view returns (uint256) {
    require(_feeIndex >= 0 && _feeIndex <= 2);
    require(_value > 0 && _value >=  1* 1 ether);
    require(exFees.length == 3 && exFees[_feeIndex] > 0 );
        
    //Calculation Formula TotalFees = (_value * exFees[_feeIndex])/ (1 ether) 
    uint256 _totalFees = (_value.mul(exFees[_feeIndex])).div(1 ether);
        
    // Calculated total fee must be gretae than 0 for a given base fee > 0
    require(_totalFees > 0);
        
    return _totalFees;
} 

/**
 * @dev function to calculate transaction fees for given value and token
 * @param _value is the given trade overall value
 * @param _feeIndex indicates token pay options
 * @return calculated trade fee
 * Caution: _value is expected to be in wei units and it works for single token payment
 */