contract Clan is Ownable {
    using SafeMath for uint256;

    mapping(address => uint256) public rewards;
    mapping(uint256 => uint256) public epochRewards;
    mapping(address => uint256) public epochJoined;
    mapping(uint => uint256) private membersNumForEpoch;

    mapping(address => mapping(uint => bool)) public reclaimedRewards;

    uint public lastMembersNumber = 0;

    event UserJoined(address userAddress);
    event UserLeaved(address userAddress);

    uint public startBlock;
    uint public epochLength;

    uint public ownersReward;

    EmcoToken emco;

    address public clanOwner;

    constructor(address _clanOwner, address _emcoToken, uint256 _epochLength) public {
        clanOwner = _clanOwner;
        startBlock = block.number;
        epochLength = _epochLength; 
        emco = EmcoToken(_emcoToken);
    }

    function replenish(uint amount) public onlyOwner {
        //update members number for epoch if it was not set
        //we should ensure that for each epoch that has a reward members num is set
        uint currentEpoch = getCurrentEpoch();
        if(membersNumForEpoch[currentEpoch] == 0) {
            membersNumForEpoch[currentEpoch] = lastMembersNumber;
        }
        uint ownersPart;
        if(membersNumForEpoch[currentEpoch] == 0) {
            //first user joined, mines on current epoch, but user is able to redeem for next epoch
            ownersPart = amount;
        } else {
            ownersPart = amount.div(10);
            epochRewards[currentEpoch] = epochRewards[currentEpoch].add(amount - ownersPart);
        }
        ownersReward = ownersReward.add(ownersPart);
    }

    function getMembersForEpoch(uint epochNumber) public view returns (uint membersNumber) {
        return membersNumForEpoch[epochNumber];
    }

    function getCurrentEpoch() public view returns (uint256) {
        return (block.number - startBlock) / epochLength; 
    }

    //only token can join a user to a clan. Owner is an EMCO Token contract 
    function join(address user) public onlyOwner {
        emit UserJoined(user);
        uint currentEpoch = getCurrentEpoch();
        epochJoined[user] = currentEpoch + 1;

        //increment members number
        uint currentMembersNum = lastMembersNumber;
        if(currentMembersNum == 0) {
            membersNumForEpoch[currentEpoch + 1] = currentMembersNum + 1;
        } else {
            membersNumForEpoch[currentEpoch + 1] = membersNumForEpoch[currentEpoch + 1] + 1;
        }
        //update last members num
        lastMembersNumber = membersNumForEpoch[currentEpoch + 1];
    }

    function leaveClan(address user) public onlyOwner {
        epochJoined[user] = 0;
        emit UserLeaved(user);

        //decrement members number
        uint currentEpoch = getCurrentEpoch();
        uint currentMembersNum = lastMembersNumber;
        if(currentMembersNum != 0) {
            membersNumForEpoch[currentEpoch + 1] = membersNumForEpoch[currentEpoch + 1] - 1;
        } 
        //update last members num
        lastMembersNumber = membersNumForEpoch[currentEpoch + 1];
    }

    function calculateReward(uint256 epoch) public view returns (uint256) {
        return epochRewards[epoch].div(membersNumForEpoch[epoch]);
    }

    function reclaimOwnersReward() public {
        require(msg.sender == clanOwner);
        emco.transfer(msg.sender, ownersReward);
        ownersReward = 0;
    }

    //get your bonus for specific epoch
    function reclaimReward(uint256 epoch) public {
        uint currentEpoch = getCurrentEpoch();
        require(currentEpoch > epoch);
        require(epochJoined[msg.sender] != 0);
        require(epochJoined[msg.sender] <= epoch);
        require(reclaimedRewards[msg.sender][epoch] == false);

        uint userReward = calculateReward(epoch);
        require(userReward > 0);

        require(emco.transfer(msg.sender, userReward));
        reclaimedRewards[msg.sender][epoch] = true;
    }

}
/**
 * @title EMCO Clan
 * @dev EMCO Clan
 */
function join(address user) public onlyOwner {
    emit UserJoined(user);
    uint currentEpoch = getCurrentEpoch();
    epochJoined[user] = currentEpoch + 1;

    //increment members number
    uint currentMembersNum = lastMembersNumber;
    if(currentMembersNum == 0) {
        membersNumForEpoch[currentEpoch + 1] = currentMembersNum + 1;
    } else {
        membersNumForEpoch[currentEpoch + 1] = membersNumForEpoch[currentEpoch + 1] + 1;
    }
    //update last members num
    lastMembersNumber = membersNumForEpoch[currentEpoch + 1];
}

//only token can join a user to a clan. Owner is an EMCO Token contract 