pragma solidity ^0.6.0;

contract RoseRent {
    
    address owner;
    address admin;
    
    struct ledger {
        
        uint initTimestamp;
        uint nextPaymentTimestamp;
        uint currentWithdrawAllowance;
        string reasonForUnemployement;
    }

    mapping (address => uint256) private studentRentPaid; // Mapping of students address => ammount the students paid for rent
    mapping (address => ledger) private unemploymentAccounts; // Mapping of students address => their account (ledger struct)
    address[] studentsAddresses; // Needed to loop over all the students


    /*
    * startUnemployment(): adds an account to the unemployment ledger so the owner can collect, 
    *                      and initializes all the relevant variables. Made for users to call and can only affect the address calling it.
    * @arg _reasonForUnemployment - a string describing why.
    * @returns nothing
    */
    function startUnemployment (string memory _reasonForUnemployement) public {
        require(unemploymentAccounts[msg.sender].initTimestamp == 0); // If they asked for it in the past, they can not again
        studentsAddresses.push(msg.sender); // saves keys to look up in the future
        unemploymentAccounts[msg.sender].initTimestamp = now;
        unemploymentAccounts[msg.sender].nextPaymentTimestamp = 604800 + unemploymentAccounts[msg.sender].initTimestamp; //604800 is the number of seconds in a week.
        unemploymentAccounts[msg.sender].currentWithdrawAllowance = 1000000000000000000; //1e18: Native value is in wei
        unemploymentAccounts[msg.sender].reasonForUnemployement = _reasonForUnemployement;
    }

    /*
    * claimUnemployment(): allows the account to collect unemployment.
    * @arg _amountToWithdraw - value that the user wants to withdraw.
    * @returns nothing
    */
    function claimUnemployment (uint _amountToWithdraw) public { 
        // We are checking to make sure the amount withdrawn is positive and wont result in a negative balance.
        require(unemploymentAccounts[msg.sender].currentWithdrawAllowance > 0);
        require(unemploymentAccounts[msg.sender].currentWithdrawAllowance - _amountToWithdraw > 0);
        unemploymentAccounts[msg.sender].currentWithdrawAllowance -= _amountToWithdraw; 
        msg.sender.transfer(_amountToWithdraw); 
        
    }
    
    /*
    * checkUnemploymentAllowance(): allows the account owner to check there account allowance.
    * @returns uint256 - available allowance.
    */
    function checkUnemploymentAllowence() public view returns (uint256){
        return unemploymentAccounts[msg.sender].currentWithdrawAllowance;
        
    }
    
    /*
    * getMoreAllowance(): allows the account to collect more unemployment after 1 week.
    * @returns nothing
    */
    function getMoreAllowance() public{
        require(unemploymentAccounts[msg.sender].nextPaymentTimestamp < now);// Checks if 1 weeks has passed.
        unemploymentAccounts[msg.sender].initTimestamp = now;
        unemploymentAccounts[msg.sender].nextPaymentTimestamp = 604800 + unemploymentAccounts[msg.sender].initTimestamp; //604800 is the number of seconds in a week.
        unemploymentAccounts[msg.sender].currentWithdrawAllowance += 1000000000000000000;  // 1e18 Native value is in wei
    }
    

    /*
    * depositRent(): allows the sender to pay rent conveniently here.
    * @returns nothing
    */
    function depositRent () public payable{ // realistically, we would reset the 'paid' status of students periodically, but won't here for simplicity.
        studentRentPaid[msg.sender] += msg.value;
        
    }
    
    /*
    * checkIfPaid(): allows for anyone to check if an address has paid rent.
    * @arg _studentAddress - the address to check if they paid.
    * @returns bool - true if they paid the minimum rent, false if they did not.
    */
    function checkIfPaid (address _studentAddress) public view returns (bool){
        if (studentRentPaid[_studentAddress] >= 4000000000000000000){ // 4 ETH Native value is in wei
            return true;
        }else{
            return false;   
        }
        
    }
    

    //---------------------------Not part of the lab---------------------------
    
    
    /*
    * fundContract(): allows the additional funding of the smart contract easily. Anyone can call it.
    * @returns nothing
    */
    function fundContract() public payable{
    }
    
    /*
    * initialize(): first function to be called by the managers.
    *               Sets the owner and admin and allows funding of the smart contract.
    * @arg _owner - address of the owner (Professor).
    * @arg _admin - address of the admin (TA).
    * @returns nothing
    */
    function initialize(address _owner, address _admin) public payable{
        // address(0) means a address of all 0's (0x000000000000000000000) and that is the default address. Meaning they have not been set yet.
        require ( (owner == address(0) && admin == address(0)) || msg.sender == admin || msg.sender == owner);
        owner = _owner;
        admin = _admin;
        
    }

    /*
    * restartAllAccounts(): allows the restart of all users who have called "startUnemployment()". Used by admins to reset all students when it is needed.
    * @returns nothing
    */
    function restartAllAccounts() public payable{ //Will reset contract for everyone. Could send money here to add to the total balance
        require(msg.sender == admin || msg.sender == owner);
        for (uint i=0; i<studentsAddresses.length; i++) {
            restartAccount(studentsAddresses[i]);
        }
    }

    /*
    * restartAccount(): allows the restart of a specific user given. As long a manager. Used by admins to reset a spesific students when it is needed. 
    * @arg _studentAddress - the students address which should be restarted.
    * @returns nothing
    */
    function restartAccount(address _studentAddress) public{ //Note: the keyword delete does not work on mapping or structs, so we must iterate over a know key list.
        // since it has "_studentAddress" passed in, it does not rely on msg.sender. So the admins can reset any student, unlike startUnemployment which is caller restrictive.
        require(msg.sender == admin || msg.sender == owner);
        unemploymentAccounts[_studentAddress].initTimestamp = now;
        unemploymentAccounts[_studentAddress].nextPaymentTimestamp = 604800 + unemploymentAccounts[_studentAddress].initTimestamp; //604800 is the number of seconds in a week.
        unemploymentAccounts[_studentAddress].currentWithdrawAllowance = 1000000000000000000; //1e18 - Native value is in wei
        studentRentPaid[_studentAddress] = 0;
    }

}