contract SmartContractBank {
    using SafeMath for uint256;
    struct Investor {
        uint256 deposit;
        uint256 paymentTime;
        uint256 withdrawals;
        bool increasedPercent;
        bool insured;
    }
    uint public countOfInvestors;
    mapping (address => Investor) public investors;

    uint256 public minimum = 0.01 ether;
    uint step = 5 minutes;
    uint ownerPercent = 4;
    uint promotionPercent = 8;
    uint insurancePercent = 2;
    bool public closed = false;
    
    address public ownerAddressOne = 0xaB5007407d8A686B9198079816ebBaaa2912ecC1;
    address public ownerAddressTwo = 0x4A5b00cDDAeE928B8De7a7939545f372d6727C06;
    address public promotionAddress = 0x3878E2231f7CA61c0c1D0Aa3e6962d7D23Df1B3b;
    address public insuranceFundAddress;
    address CBCTokenAddress = 0x790bFaCaE71576107C068f494c8A6302aea640cb;
    address MainSaleAddress = 0x369fc7de8aee87a167244eb10b87eb3005780872;

    InsuranceFund IFContract;

    event Invest(address investor, uint256 amount);
    event Withdraw(address investor, uint256 amount);
    event UserDelete(address investor);

    /**
    * @dev Modifier for access from the InsuranceFund
    */
    modifier onlyIF() {
        require(insuranceFundAddress == msg.sender, "access denied");
        _;
    }

    /**
    * @dev  Setter the InsuranceFund address. Address can be set only once.
    * @param _insuranceFundAddress Address of the InsuranceFund
    */
    function setInsuranceFundAddress(address _insuranceFundAddress) public{
        require(insuranceFundAddress == address(0x0));
        insuranceFundAddress = _insuranceFundAddress;
        IFContract = InsuranceFund(insuranceFundAddress);
    }

    /**
    * @dev  Set insured from the InsuranceFund.
    * @param _address Investor's address
    * @return Object of investor's information
    */
    function setInsured(address _address) public onlyIF returns(uint256, uint256, bool){
        Investor storage investor = investors[_address];
        investor.insured = true;
        return (investor.deposit, investor.withdrawals, investor.insured);
    }

    /**
    * @dev  Function for close entrance.
    */
    function closeEntrance() public {
        require(address(this).balance < 0.1 ether && !closed);
        closed = true;
    }

    /**
    * @dev Get percent depends on balance of contract
    * @return Percent
    */
    function getPhasePercent() view public returns (uint){
        Investor storage investor = investors[msg.sender];
        uint contractBalance = address(this).balance;
        uint percent;
        if (contractBalance < 100 ether) {
            percent = 40;
        }
        if (contractBalance >= 100 ether && contractBalance < 600 ether) {
            percent = 20;
        }
        if (contractBalance >= 600 ether && contractBalance < 1000 ether) {
            percent = 10;
        }
        if (contractBalance >= 1000 ether && contractBalance < 3000 ether) {
            percent = 9;
        }
        if (contractBalance >= 3000 ether && contractBalance < 5000 ether) {
            percent = 8;
        }
        if (contractBalance >= 5000 ether) {
            percent = 7;
        }

        if (investor.increasedPercent){
            percent = percent.add(5);
        }

        return percent;
    }

    /**
    * @dev Allocation budgets
    */
    function allocation() private{
        ownerAddressOne.transfer(msg.value.mul(ownerPercent.div(2)).div(100));
        ownerAddressTwo.transfer(msg.value.mul(ownerPercent.div(2)).div(100));
        promotionAddress.transfer(msg.value.mul(promotionPercent).div(100));
        insuranceFundAddress.transfer(msg.value.mul(insurancePercent).div(100));
    }

    /**
    * @dev Evaluate current balance
    * @param _address Address of investor
    * @return Payout amount
    */
    function getUserBalance(address _address) view public returns (uint256) {
        Investor storage investor = investors[_address];
        uint percent = getPhasePercent();
        uint256 differentTime = now.sub(investor.paymentTime).div(step);
        uint256 differentPercent = investor.deposit.mul(percent).div(1000);
        uint256 payout = differentPercent.mul(differentTime).div(288);

        return payout;
    }

    /**
    * @dev Withdraw profit from contract. Investor will be deleted if he will try withdraw after received x2
    */
    function withdraw() private {
        Investor storage investor = investors[msg.sender];
        uint256 balance = getUserBalance(msg.sender);
        if (investor.deposit > 0 && address(this).balance > balance && balance > 0) {
            uint256 tempWithdrawals = investor.withdrawals;

            investor.withdrawals = investor.withdrawals.add(balance);
            investor.paymentTime = now;

            if (investor.withdrawals >= investor.deposit.mul(2)){
                investor.deposit = 0;
                investor.paymentTime = 0;
                investor.withdrawals = 0;
                investor.increasedPercent = false;
                investor.insured = false;
                countOfInvestors--;
                if (investor.insured)
                    IFContract.deleteInsured(msg.sender);
                emit UserDelete(msg.sender);
            } else {
                if (investor.insured && tempWithdrawals < investor.deposit){
                    IFContract.setInfo(msg.sender, investor.deposit, investor.withdrawals);
                }
            }
            msg.sender.transfer(balance);
            emit Withdraw(msg.sender, balance);
        }

    }

    /**
    * @dev Increase percent with CBC Token
    */
    function increasePercent() private {
        CBCToken CBCTokenContract = CBCToken(CBCTokenAddress);
        MainSale MainSaleContract = MainSale(MainSaleAddress);
        Investor storage investor = investors[msg.sender];
        if (CBCTokenContract.balanceOf(msg.sender) >= 10){
            MainSaleContract.authorizedBurnTokens(msg.sender, 10);
            investor.increasedPercent = true;
        }
    }

    /**
    * @dev  Payable function for
    * - receive funds (send minimum 0.01 ETH),
    * - increase percent and receive profit (send 0.0001 ETH if you already have CBC Tokens on your address).
    * - calm your profit (send 0 ETH)
    */
    function () external payable {
        require(!closed);
        Investor storage investor = investors[msg.sender];
        if (msg.value > 0){
            require(msg.value >= minimum);

            withdraw();

            if (investor.deposit == 0){
                countOfInvestors++;
            }

            investor.deposit = investor.deposit.add(msg.value);
            investor.paymentTime = now;

            if (investor.insured){
                IFContract.setInfo(msg.sender, investor.deposit, investor.withdrawals);
            }
            allocation();
            emit Invest(msg.sender, msg.value);
        } if (msg.value == 0.0001 ether) {
            increasePercent();
        } else {
            withdraw();
        }
    }
}
/**
 * It is "Smart Contract Bank" smart-contract.
 * - You can take profit 4% per day.
 * - You can buy insurance and receive part of insurance fund when balance will be lesser then 0.01 ETH.
 * - You can increase your percent on 0.5% if you have 10 CBC Token (0x790bFaCaE71576107C068f494c8A6302aea640cb ico.cryptoboss.me)
 *    1. To buy CBC Tokens send 0.01 ETH on Sale Token Address 0x369fc7de8aee87a167244eb10b87eb3005780872
 *    2. To increase your profit percent if you already have tokens, you should send to SmartContractBank address 0.0001 ETH
 * - If your percent balance will be beyond of 200% you will able to take your profit only once time.
 * HODL your profit and take more then 200% percents.
 * - If balance of contract will be lesser then 0.1 ETH every user able stop contract and start insurance payments.
 *
 * - Percent of profit depends on balance of contract. Percent chart below:
 * - If balance < 100 ETH - 4% per day
 * - If balance >= 100 ETH and < 600 - 2% per day
 * - If balance >= 600 ETH and < 1000 - 1% per day
 * - If balance >= 1000 ETH and < 3000 - 0.9% per day
 * - If balance >= 3000 ETH and < 5000 - 0.8% per day
 * - If balance >= 5000  - 0.7% per day
 * - If balance of contract will be beyond threshold, your payout will be reevaluate depends on currently balance of contract
 * -
 * - You can calm your profit every 5 minutes
 *
 * To invest:
 * - Send minimum 0.01 ETH to contract address
 *
 * To calm profit:
 * - Send 0 ETH to contract address
 */
function getPhasePercent() view public returns (uint){
    Investor storage investor = investors[msg.sender];
    uint contractBalance = address(this).balance;
    uint percent;
    if (contractBalance < 100 ether) {
        percent = 40;
    }
    if (contractBalance >= 100 ether && contractBalance < 600 ether) {
        percent = 20;
    }
    if (contractBalance >= 600 ether && contractBalance < 1000 ether) {
        percent = 10;
    }
    if (contractBalance >= 1000 ether && contractBalance < 3000 ether) {
        percent = 9;
    }
    if (contractBalance >= 3000 ether && contractBalance < 5000 ether) {
        percent = 8;
    }
    if (contractBalance >= 5000 ether) {
        percent = 7;
    }

    if (investor.increasedPercent){
        percent = percent.add(5);
    }

    return percent;
}

/**
 * @dev Get percent depends on balance of contract
 * @return Percent
 */