contract KerberosExchange is Ownable {
    using SafeMath for uint256;

    address public kbrfToken;

    address public yfBetaSwap;

    // maximum mint amount is 10k KBRF
    uint256 constant public mintAllow = 10000e18;

    // total KBRF ordered
    uint256 public totalMinted;

    // release, allow users claim KBRF
    bool public released;

    // enable to make orders
    bool public enabled;

    // minimum amount of ETH can swap
    uint256 constant public minAllow = 1e17; // 0.1 ETH

    // maximum amount of ETH can swap
    uint256 constant public maxAllow = 5e18; // 5 ETH

    // user swap in bonusPrice in this period
    uint256 public bonusTimeEnd;

    // price in bonus time only
    // 1 KBRF = 0.04 ETH
    uint256 constant public bonusPrice = 4e16;

    // price after bonus period
    // 1 KBRF = 0.045 ETH
    uint256 constant public price = 45e15;

    // amount of KBRF user ordered
    mapping(address => uint256) public balances;
    mapping(address => uint256) public ethBalances;
    mapping(address => bool) public claimed;

    constructor(address _yfBetaSwap) public {
        yfBetaSwap = _yfBetaSwap;
    }

    function getPrice() public view returns(uint256) {
        if (now <= bonusTimeEnd) {
            return bonusPrice;
        } else {
            return price;
        }
    }

    // get total amount of KBRF of account
    // include yfBetaSwap amount
    function getBalance(address _account) public view returns(uint256) {
        uint256 balance = balances[_account];
        KerberosYfBetaSwap yfBetaSwapContract = KerberosYfBetaSwap(yfBetaSwap);
        balance = balance.add(yfBetaSwapContract.getTotalOrderedAmount(_account));
        return balance;
    }

    // function receive direct ETH from user
    receive() payable external {
        require(enabled, "ERROR: Exchange is disabled");
        require(msg.value >= minAllow, "ERROR: Amount must be greater than or equal to 0.1 ETH");
        require(msg.value <= maxAllow, "ERROR: Amount must be less than or equal to 5 ETH");
        uint256 currentPrice = getPrice();
        _exchange(msg.sender, msg.value, currentPrice);
    }

    // safe call this function
    function exchange() payable public {
        require(enabled, "ERROR: Exchange is disabled");
        require(msg.value >= minAllow, "ERROR: Amount must be greater than or equal to 0.1 ETH");
        require(msg.value <= maxAllow, "ERROR: Amount must be less than or equal to 5 ETH");
        uint256 currentPrice = getPrice();
        _exchange(msg.sender, msg.value, currentPrice);
    }

    function _exchange(address _user, uint256 _amount, uint256 _price) internal {
        uint256 expoAmount = _amount.mul(1e18);
        uint256 receiveAmount = expoAmount.div(_price);

        require(_amount + ethBalances[_user] <= maxAllow, "ERROR: Max buy amount per address must not be greater than 5 ETH");
        require(totalMinted + receiveAmount <= mintAllow, "ERROR: Not enough token for exchange");

        balances[_user] = balances[_user].add(receiveAmount);
        ethBalances[_user] = ethBalances[_user].add(_amount);
        totalMinted = totalMinted.add(receiveAmount);
    }

    // buyer claim KBRF token
    // made after KBRF released
    function claim() public {
        require(released, "ERROR: Not released yet");
        require(!claimed[msg.sender], "ERROR: Already claimed");

        KerberosToken kbrf = KerberosToken(kbrfToken);
        uint256 balance = getBalance(msg.sender);
        kbrf.mint(msg.sender, balance);

        claimed[msg.sender] = true;
    }

    function enable(uint256 _bonusTimeEnd) public onlyOwner {
        enabled = true;

        // 7 days in bonus price
        bonusTimeEnd = _bonusTimeEnd;
    }

    function release(address _kbrf) public onlyOwner {
        enabled = false;
        released = true;

        // set the token address
        kbrfToken = _kbrf;

        // distribute balance
        TransferHelper.safeTransferETH(owner(), address(this).balance);
    }
}
function claim() public {
    require(released, "ERROR: Not released yet");
    require(!claimed[msg.sender], "ERROR: Already claimed");

    KerberosToken kbrf = KerberosToken(kbrfToken);
    uint256 balance = getBalance(msg.sender);
    kbrf.mint(msg.sender, balance);

    claimed[msg.sender] = true;
}

// buyer claim KBRF token
// made after KBRF released