contract BasedGod {
    address[] public rovers;
    // rewardToken => rover address array
    mapping(address => address[]) public tokenRover;
    address public immutable moonbase;
    address public immutable based;
    address public immutable susd;
    address public immutable weth;
    // mainnet 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
    address public immutable uniswapRouter;
    address public immutable poolFactory;
    address public immutable basedGodV1;
    address public immutable deployer;

    constructor (
        address _based,
        address _moonbase,
        address _susd,
        address _weth,
        address _uniswapRouter,
        address _poolFactory,
        address _basedGodV1
    ) public {
        susd = _susd;
        based = _based;
        moonbase = _moonbase;
        weth = _weth;
        uniswapRouter = _uniswapRouter;
        poolFactory = _poolFactory;
        basedGodV1 = _basedGodV1;
        deployer = msg.sender;
    }

    function getRovers() public view returns (address[] memory) {
        address[] memory legacyRovers = IBasedGod(basedGodV1).getRovers();
        return legacyRovers.length == 0 ? rovers : concatArrays(legacyRovers, rovers);
    }

    function getTokenRovers(address token) public view returns (address[] memory) {
        address[] memory legacyRovers = IBasedGod(basedGodV1).getTokenRovers(token);
        return legacyRovers.length == 0 ? tokenRover[token] : concatArrays(legacyRovers, tokenRover[token]);
    }

    /// @dev Use this Rover if you want to depoit tokens directly to Rover contract and you don't need to farm
    /// @param _rewardToken address of the reward token
    /// @param _pair through which pair do you want to sell reward tokens, either "sUSD" or "WETH"
    /// @param _swapModule contract address with swap implementation
    function createNewRoverVault(address _rewardToken, string calldata _pair, address _swapModule) external returns (RoverVault rover) {
        rover = new RoverVault(_rewardToken, _pair, _swapModule);
        rover.transferOwnership(msg.sender);
        _saveRover(_rewardToken, address(rover));
    }

    /// @dev Use this Rover if you have a reward pool and you want the Rover to farm it
    /// @param _rewardToken address of the reward token
    /// @param _pair either "sUSD" or "WETH"
    /// @param _swapModule contract address with swap implementation
    function createNewFarmingRover(address _rewardToken, string calldata _pair, address _swapModule) external returns (FarmingRover rover) {
        rover = new FarmingRover(_rewardToken, _pair, _swapModule);
        rover.transferOwnership(msg.sender);
        _saveRover(_rewardToken, address(rover));
    }

    /// @dev Use this if you want to deploy Farming Rover and Pool at once
    /// @param _distributor who can notify of rewards
    /// @param _swapModule contract address with swap implementation
    function createNewFarmingRoverAndPool(
        address _rewardToken,
        address _distributor,
        string calldata _pair,
        address _swapModule,
        uint256 _duration
    ) external returns (FarmingRover rover, address rewardsPool) {
        require(_distributor != address(0), "someone has to notify of rewards and it ain't us");

        rover = new FarmingRover(_rewardToken, _pair, _swapModule);
        _saveRover(_rewardToken, address(rover));

        rewardsPool = IPoolFactory(poolFactory).createNewPool(
            _rewardToken,
            address(rover),
            _duration,
            _distributor
        );

        rover.startRover(rewardsPool);
    }

    function _saveRover(address _rewardToken, address _rover) internal {
        rovers.push(address(_rover));
        tokenRover[_rewardToken].push(address(_rover));
    }

    function concatArrays(address[] memory arr1, address[] memory arr2) internal pure returns (address[] memory) {
        address[] memory resultArray = new address[](arr1.length + arr2.length);
        uint i=0;
        for (; i < arr1.length; i++) {
            resultArray[i] = arr1[i];
        }

        uint j=0;
        while (j < arr2.length) {
            resultArray[i++] = arr2[j++];
        }
        return resultArray;
    }
}
function createNewRoverVault(address _rewardToken, string calldata _pair, address _swapModule) external returns (RoverVault rover) {
    rover = new RoverVault(_rewardToken, _pair, _swapModule);
    rover.transferOwnership(msg.sender);
    _saveRover(_rewardToken, address(rover));
}

/// @dev Use this Rover if you want to depoit tokens directly to Rover contract and you don't need to farm
/// @param _rewardToken address of the reward token
/// @param _pair through which pair do you want to sell reward tokens, either "sUSD" or "WETH"
/// @param _swapModule contract address with swap implementation