contract Controller is Ownable {
    using SafeMath for uint256;
    mapping(address => uint256) public fee;
    mapping(address => uint256) public rebalanceFriction;
    mapping(address => address) public poolStrategy;
    mapping(address => address) public poolCollateralManager;
    mapping(address => address) public feeCollector;
    mapping(address => uint256) public highWater;
    mapping(address => uint256) public lowWater;
    mapping(address => bool) public isPool;
    address[] public pools;
    mapping(address => address) public collateralToken;
    AddressProvider public ap;
    address public builderVault;
    uint256 public builderFee = 2e17;
    uint256 internal constant WAT = 10**16;

    function addPool(address _pool) public onlyOwner {
        require(_pool != address(0), "invalid-pool");
        IERC20 pool = IERC20(_pool);
        require(pool.totalSupply() == 0, "Zero supply required");
        require(!isPool[_pool], "already approved");
        isPool[_pool] = true;
        collateralToken[_pool] = IVPool(_pool).token();
        pools.push(_pool);
    }

    function removePool(uint256 _index) public onlyOwner {
        IERC20 pool = IERC20(pools[_index]);
        require(pool.totalSupply() == 0, "Zero supply required");
        isPool[pools[_index]] = false;
        if (_index < pools.length - 1) {
            pools[_index] = pools[pools.length - 1];
        }
        pools.pop();
    }

    /**
     * @dev Update Address provider address.
     * @param _addressProvider Address of address provider contract.
     */
    function updateAddressProvider(address _addressProvider) public onlyOwner {
        require(_addressProvider != address(0), "Address cannot be zero");
        ap = AddressProvider(_addressProvider);
    }

    function updateBalancingFactor(
        address _pool,
        uint256 _highWater,
        uint256 _lowWater
    ) public onlyOwner {
        require(isPool[_pool], "Pool not approved");
        require(_lowWater > 0, "Value is zero");
        require(_highWater > _lowWater, "highWater is small than lowWater");
        highWater[_pool] = _highWater.mul(WAT);
        lowWater[_pool] = _lowWater.mul(WAT);
    }

    function updateFee(address _pool, uint256 _newFee) external onlyOwner {
        require(isPool[_pool], "Pool not approved");
        require(_newFee <= 1e18, "fee limit reached");
        require(fee[_pool] != _newFee, "same-pool-fee");
        require(feeCollector[_pool] != address(0), "FeeCollector not set");
        fee[_pool] = _newFee;
    }

    function updateFeeCollector(address _pool, address _collector) external onlyOwner {
        require(isPool[_pool], "Pool not approved");
        require(_collector != address(0), "invalid-collector");
        require(feeCollector[_pool] != _collector, "same-collector");
        feeCollector[_pool] = _collector;
    }

    function updateRebalanceFriction(address _pool, uint256 _f) public onlyOwner {
        require(rebalanceFriction[_pool] != _f, "same-friction");
        rebalanceFriction[_pool] = _f;
    }

    function updateBuilderTreasure(address _builder) public onlyOwner {
        builderVault = _builder;
    }

    function adjutBuilderFee(uint256 _builderFee) public {
        // TODO: Public function for time based logic to reduce builder fee
    }

    function updatePoolCM(address _pool, address _newCM) external onlyOwner {
        require(isPool[_pool], "Pool not approved");
        require(_newCM != address(0), "invalid-address");
        require(poolCollateralManager[_pool] != _newCM, "same-cm");
        poolCollateralManager[_pool] = _newCM;
        IVPool vpool = IVPool(_pool);
        vpool.registerCollateralManager(_newCM);
    }

    function updatePoolStrategy(address _pool, address _newStrategy) external onlyOwner {
        require(isPool[_pool], "Pool not approved");
        require(_newStrategy != address(0), "invalid-address");
        require(poolStrategy[_pool] != _newStrategy, "same-pool-logic");
        poolStrategy[_pool] = _newStrategy;
    }

    function getPoolCount() public view returns (uint256) {
        return pools.length;
    }
}
function updateAddressProvider(address _addressProvider) public onlyOwner {
    require(_addressProvider != address(0), "Address cannot be zero");
    ap = AddressProvider(_addressProvider);
}

/**
 * @dev Update Address provider address.
 * @param _addressProvider Address of address provider contract.
 */