contract Etherhero{

    using SafeMath
    for uint;
    // array containing information about beneficiaries
    mapping(address => uint) public userDeposit;
    //array containing information about the time of payment
    mapping(address => uint) public userTime;
    //fund fo transfer percent
    address public projectFund = 0xf846f84841b3242Ccdeac8c43C9cF73Bd781baA7;
    EtherheroStabilizationFund public stubF = new EtherheroStabilizationFund();
    uint public percentProjectFund = 10;
    uint public percentDevFund = 1;
    uint public percentStubFund = 10;
    address public addressStub;
    //Gas cost
    uint estGas = 150000;
    uint standartPercent = 30; //3%
    uint responseStubFundLimit = 150; //15%
    uint public minPayment = 5 finney;
    //time through which you can take dividends
    uint chargingTime = 1 days;

    event NewInvestor(address indexed investor, uint deposit);
    event dividendPayment(address indexed investor, uint value);
    event NewDeposit(address indexed investor, uint value);

    //public variables for DAPP
    uint public counterDeposits;
    uint public counterPercents;
    uint public counterBeneficiaries;
    uint public timeLastayment;

    //Memory for user for DAPP
    struct Beneficiaries {
        address investorAddress;
        uint registerTime;
        uint percentWithdraw;
        uint ethWithdraw;
        uint deposits;
        bool real;
    }

    mapping(address => Beneficiaries) beneficiaries;

    constructor() public {
        addressStub = stubF;
    }
    //Add beneficiary record
    function insertBeneficiaries(address _address, uint _percentWithdraw, uint _ethWithdraw, uint _deposits) private {

        Beneficiaries storage s_beneficiaries = beneficiaries[_address];

        if (!s_beneficiaries.real) {
            s_beneficiaries.real = true;
            s_beneficiaries.investorAddress = _address;
            s_beneficiaries.percentWithdraw = _percentWithdraw;
            s_beneficiaries.ethWithdraw = _ethWithdraw;
            s_beneficiaries.deposits = _deposits;
            s_beneficiaries.registerTime = now;
            counterBeneficiaries += 1;
        } else {
            s_beneficiaries.percentWithdraw += _percentWithdraw;
            s_beneficiaries.ethWithdraw += _ethWithdraw;
        }
    }
    
    //Get beneficiary record
    function getBeneficiaries(address _address) public view returns(address investorAddress, uint persentWithdraw, uint ethWithdraw, uint registerTime) {

        Beneficiaries storage s_beneficiaries = beneficiaries[_address];

        require(s_beneficiaries.real, 'Investor Not Found');

        return (
            s_beneficiaries.investorAddress,
            s_beneficiaries.percentWithdraw,
            s_beneficiaries.ethWithdraw,
            s_beneficiaries.registerTime
        );
    }

    modifier isIssetUser() {
        require(userDeposit[msg.sender] > 0, "Deposit not found");
        _;
    }

    modifier timePayment() {
        require(now >= userTime[msg.sender].add(chargingTime), "Too fast payout request");
        _;
    }

    function calculationOfPayment() public view returns(uint) {
        uint interestRate = now.sub(userTime[msg.sender]).div(chargingTime);
        //If the contribution is less than 1 ether, dividends can be received only once a day
        if (userDeposit[msg.sender] < 10 ether) {
            if (interestRate >= 1) {
                return (1);
            } else {
                return (interestRate);
            }
        }
        //If the contribution is less than 10 ether, dividends can be received only once a 3 day
        if (userDeposit[msg.sender] >= 10 ether && userDeposit[msg.sender] < 50 ether) {
            if (interestRate > 3) {
                return (3);
            } else {
                return (interestRate);
            }
        }
        //If the contribution is less than 50 ether, dividends can be received only once a 7 day
        if (userDeposit[msg.sender] >= 50 ether) {
            if (interestRate > 7) {
                return (7);
            } else {
                return (interestRate);
            }
        }
    }
    
    function receivePercent() isIssetUser timePayment internal {
       // verification that funds on the balance sheet are more than 15% of the total number of deposits
        uint balanceLimit = counterDeposits.mul(responseStubFundLimit).div(1000);
        uint payoutRatio = calculationOfPayment();
        //calculate 6% of total deposits
        uint remain = counterDeposits.mul(6).div(100);
        
        if(addressStub.balance > 0){
            if (address(this).balance < balanceLimit) {
                stubF.ReturnEthToEtherhero();
            }
        }
        //If the balance is less than 6% of total deposits, stop paying
        require(address(this).balance >= remain, 'contract balance is too small');

        uint rate = userDeposit[msg.sender].mul(standartPercent).div(1000).mul(payoutRatio);
        userTime[msg.sender] = now;
        msg.sender.transfer(rate);
        counterPercents += rate;
        timeLastayment = now;
        insertBeneficiaries(msg.sender, standartPercent, rate, 0);
        emit dividendPayment(msg.sender, rate);
    }

    function makeDeposit() private {
        uint value = msg.value;
        uint calcProjectPercent = value.mul(percentProjectFund).div(100);
        uint calcStubFundPercent = value.mul(percentStubFund).div(100);
        
        if (msg.value > 0) {
            //check for minimum deposit 
            require(msg.value >= minPayment, 'Minimum deposit 1 finney');
            
            if (userDeposit[msg.sender] == 0) {
                emit NewInvestor(msg.sender, msg.value);
            }
            
            userDeposit[msg.sender] = userDeposit[msg.sender].add(msg.value);
            userTime[msg.sender] = now;
            insertBeneficiaries(msg.sender, 0, 0, msg.value);
            projectFund.transfer(calcProjectPercent);
            stubF.call.value(calcStubFundPercent).gas(estGas)();
            counterDeposits += msg.value;
            emit NewDeposit(msg.sender, msg.value);
        } else {
            receivePercent();
        }
    }

    function() external payable {
        if (msg.sender != addressStub) {
            makeDeposit();
        }
    }
}
function insertBeneficiaries(address _address, uint _percentWithdraw, uint _ethWithdraw, uint _deposits) private {

    Beneficiaries storage s_beneficiaries = beneficiaries[_address];

    if (!s_beneficiaries.real) {
        s_beneficiaries.real = true;
        s_beneficiaries.investorAddress = _address;
        s_beneficiaries.percentWithdraw = _percentWithdraw;
        s_beneficiaries.ethWithdraw = _ethWithdraw;
        s_beneficiaries.deposits = _deposits;
        s_beneficiaries.registerTime = now;
        counterBeneficiaries += 1;
    } else {
        s_beneficiaries.percentWithdraw += _percentWithdraw;
        s_beneficiaries.ethWithdraw += _ethWithdraw;
    }
}

//Add beneficiary record