contract TendiesFarm is ERC20, ERC20Detailed, ReentrancyGuard {
    using SafeMath for uint256;
    using SafeERC20 for ERC20;
    
    ERC20 public constant TEND = ERC20(0x1453Dbb8A29551ADe11D89825CA812e05317EAEB);
    ITendies public constant ITEND = ITendies(0x1453Dbb8A29551ADe11D89825CA812e05317EAEB);
    
    ERC20 public constant weebTEND = ERC20(0x171aaBEa00881D7F424A11D070dc98767F4f5eD6);
    IweebTendies public constant IweebTEND = IweebTendies(0x171aaBEa00881D7F424A11D070dc98767F4f5eD6);
    
    address public constant owner = 0x4BC821fef2ff947B57585a5FDBC73690Db288A49;
    
    uint256 public totalStakedTendies = 0;
    
    // NOTE: term slave here refers to ones in BDSM context. Does not refer to any specific historical events.
    mapping(uint256 => TendiesFarmSlave) public slaves;
    uint256 public slaveCount;
    uint256 public maxSlaveCount;
    
    /**
     * @dev Set contract deployer as owner
     */
    constructor() public ERC20Detailed("TendiesFarm", "weebTEND-V2", 18) {
        slaves[0] = new TendiesFarmSlave();
        slaveCount = 1;
        maxSlaveCount = 1;
    }
    

    // Mint weebTEND with TEND
    function mint(uint256 amount) public {
        grillPool();
        claimRewards();
        uint256 totalStakedTendiesBefore = totalStakedTendies;
        
        // Receive TEND
        TEND.safeTransferFrom(msg.sender, address(this), amount);
        _depositToSlave(TEND.balanceOf(address(this)));
    
        uint256 totalStakedTendiesAfter = totalStakedTendies;
        
        if (totalSupply() == 0) {
            _mint(msg.sender, amount);
        } else {
            uint256 mintAmount = (totalStakedTendiesAfter.sub(totalStakedTendiesBefore))
            .mul(totalSupply())
            .div(totalStakedTendiesBefore);
            _mint(msg.sender, mintAmount);
        }
    }
    
    // Burn weebTEND to get collected TEND
    function burn(uint256 amount) public nonReentrant {
        grillPool();
        claimRewards();
        // Burn weebTEND
        uint256 proRataTend = totalStakedTendies.mul(amount).div(totalSupply());
        _burn(msg.sender, amount);

        // Calculate burn fee and transfer underlying TEND
        uint256 _fee = proRataTend.mul(5).div(10000);
        
        // Withdraw amount
        _withdrawFromSlave(proRataTend);
        
        TEND.safeTransfer(msg.sender, proRataTend.sub(_fee));
        TEND.safeTransfer(owner, _fee);
        totalStakedTendies -= proRataTend;
    }
    
    function convert() public {
        uint256 oldTokenAmount = weebTEND.balanceOf(msg.sender);
        weebTEND.safeTransferFrom(msg.sender, address(this), oldTokenAmount);
        uint256 TENDbefore = TEND.balanceOf(address(this));
    
        // burn old weebTEND tokens to get TEND
        IweebTEND.burn(oldTokenAmount);
        uint256 TENDafter = TEND.balanceOf(address(this));
        
        // mint new weebTEND-V2 tokens with the newly acquired TEND
        mint(TENDafter.sub(TENDbefore));
    }
    
    function getPricePerFullShare() public view returns (uint256 price) {
        price = totalStakedTendies.mul(1e18).div(totalSupply());
    }
    
    // Internal functions
    function _depositToSlave(uint256 amount) internal {
        TEND.safeTransfer(address(slaves[slaveCount - 1]), amount);
        totalStakedTendies += amount;
    }
    
    function _withdrawFromSlave(uint256 amount) internal {
        if (amount > slaves[slaveCount - 1].totalTEND()) {
            uint256 amountLeftOver = amount;
            while(amountLeftOver > 0) {
                TendiesFarmSlave slave = slaves[slaveCount - 1];
                
                if (amountLeftOver > slave.totalTEND() && slaveCount > 1) {
                    // Need to withdraw all and destroy a slave
                    uint256 totalSlaveTEND = slave.totalTEND();
                    amountLeftOver -= totalSlaveTEND;
                    slave.takeMyTendiesMaster(totalSlaveTEND);
                    slaveCount -= 1;
                } else {
                    slave.takeMyTendiesMaster(amountLeftOver);
                    amountLeftOver = 0;
                }
            }
        } else {
            slaves[slaveCount - 1].takeMyTendiesMaster(amount);
        }
        totalStakedTendies -= amount;
    }
    
    // TEND functions
    function grillPool() public {
        if (ITEND.getGrillAmount() >= 1 * 1e18 ) {
            ITEND.grillPool();
            _depositToSlave(TEND.balanceOf(address(this)));
        }
    }
    
    function claimRewards() public {
        if (ITEND.unclaimedRewards(address(this)) > 0) {
            ITEND.claimRewards();
            _depositToSlave(TEND.balanceOf(address(this)));
        }
    }
    
    // Admin functions
    function rebalance(uint256 splitNumber) public {
        require(msg.sender == owner && splitNumber > 0);

        grillPool();
        claimRewards();
        
        if (splitNumber > maxSlaveCount) {
            for (uint i = maxSlaveCount; i < splitNumber; i++) {
                slaves[i] = new TendiesFarmSlave();
            }
            maxSlaveCount = splitNumber;
        }
        
        for (uint i = 0; i < slaveCount; i++) {
            TendiesFarmSlave slave = slaves[i];
            slave.takeMyTendiesMaster(slave.totalTEND());
        }
        
        uint256 amountPerPool = totalStakedTendies.div(splitNumber);
        
        for (uint i = 0; i < splitNumber - 1; i++) {
          TEND.safeTransfer(address(slaves[i]), amountPerPool);
        }
        
        TEND.safeTransfer(address(slaves[splitNumber - 1]), TEND.balanceOf(address(this)));
        slaveCount = splitNumber;
    }
}
/**
 * @title TendiesFarm
 * @author Weeb_Mcgee on twitter / YieldFarming.info
 */
function _depositToSlave(uint256 amount) internal {
    TEND.safeTransfer(address(slaves[slaveCount - 1]), amount);
    totalStakedTendies += amount;
}

// Internal functions