contract PolkastarterDistributionContract is Pausable {
    using SafeMath for uint256;

    uint256 constant public decimals = 1 ether;
    address[] public tokenOwners ; /* Tracks distributions mapping (iterable) */
    uint256 public TGEDate = 0; /* Date From where the distribution starts (TGE) */
    uint256 constant public month = 30 days;
    uint256 constant public year = 365 days;
    uint256 public lastDateDistribution = 0;
  
    
    mapping(address => DistributionStep[]) public distributions; /* Distribution object */
    
    ERC20 public erc20;

    struct DistributionStep {
        uint256 amountAllocated;
        uint256 currentAllocated;
        uint256 unlockDay;
        uint256 amountSent;
    }
    
    constructor() public{
        
        /* Seed */
        setInitialDistribution(0xc97d35Dc801E6C16642b9E8b76D4ba26f30f72a6, 3000000, 0 /* No Lock */);
        setInitialDistribution(0xc97d35Dc801E6C16642b9E8b76D4ba26f30f72a6, 1500000, 1 * month); /* After 1 Month */
        setInitialDistribution(0xc97d35Dc801E6C16642b9E8b76D4ba26f30f72a6, 1500000, 2 * month); /* After 2 Months */
        setInitialDistribution(0xc97d35Dc801E6C16642b9E8b76D4ba26f30f72a6, 1500000, 3 * month); /* After 3 Months */
        setInitialDistribution(0xc97d35Dc801E6C16642b9E8b76D4ba26f30f72a6, 1500000, 4 * month); /* After 4 Months */
        setInitialDistribution(0xc97d35Dc801E6C16642b9E8b76D4ba26f30f72a6, 1500000, 5 * month); /* After 5 Months */
        setInitialDistribution(0xc97d35Dc801E6C16642b9E8b76D4ba26f30f72a6, 1500000, 6 * month); /* After 6 Months */
        setInitialDistribution(0xc97d35Dc801E6C16642b9E8b76D4ba26f30f72a6, 1500000, 7 * month); /* After 7 Months */
        setInitialDistribution(0xc97d35Dc801E6C16642b9E8b76D4ba26f30f72a6, 1500000, 8 * month); /* After 8 Months */

        /* Private Sale */
        setInitialDistribution(0xc1eF9b92A7fFD8a5be9011a626944Cd4C2810A91, 6875000, 0 /* No Lock */);
        setInitialDistribution(0xc1eF9b92A7fFD8a5be9011a626944Cd4C2810A91, 6875000, 1 * month); /* After 1 Month */
        setInitialDistribution(0xc1eF9b92A7fFD8a5be9011a626944Cd4C2810A91, 6875000, 2 * month); /* After 2 Months */
        setInitialDistribution(0xc1eF9b92A7fFD8a5be9011a626944Cd4C2810A91, 6875000, 3 * month); /* After 3 Months */

        /* Team & Advisors */
        setInitialDistribution(0x5d1c9B0B0807573B8976733dF3BaAf0102E1b3F8, 2500000, year);
        setInitialDistribution(0x5d1c9B0B0807573B8976733dF3BaAf0102E1b3F8, 2500000, year.add(3 * month)); /* After 3 Month */
        setInitialDistribution(0x5d1c9B0B0807573B8976733dF3BaAf0102E1b3F8, 2500000, year.add(6 * month)); /* After 6 Month */
        setInitialDistribution(0x5d1c9B0B0807573B8976733dF3BaAf0102E1b3F8, 2500000, year.add(9 * month)); /* After 9 Month */

        /* Network Growth Growth */
        setInitialDistribution(0x36Dc5e71304a3826C54EF6F8a19C2c4160e8ce9c, 3000000, 0 /* No Lock */);
        setInitialDistribution(0x36Dc5e71304a3826C54EF6F8a19C2c4160e8ce9c, 1000000, 1 * month); /* After 1 Month */
        setInitialDistribution(0x36Dc5e71304a3826C54EF6F8a19C2c4160e8ce9c, 1000000, 2 * month); /* After 2 Months */
        setInitialDistribution(0x36Dc5e71304a3826C54EF6F8a19C2c4160e8ce9c, 1000000, 3 * month); /* After 3 Months */
        setInitialDistribution(0x36Dc5e71304a3826C54EF6F8a19C2c4160e8ce9c, 1000000, 4 * month); /* After 4 Months */
        setInitialDistribution(0x36Dc5e71304a3826C54EF6F8a19C2c4160e8ce9c, 1000000, 5 * month); /* After 5 Months */
        setInitialDistribution(0x36Dc5e71304a3826C54EF6F8a19C2c4160e8ce9c, 1000000, 6 * month); /* After 6 Months */
        setInitialDistribution(0x36Dc5e71304a3826C54EF6F8a19C2c4160e8ce9c, 1000000, 7 * month); /* After 7 Months */
        setInitialDistribution(0x36Dc5e71304a3826C54EF6F8a19C2c4160e8ce9c, 1000000, 8 * month); /* After 8 Months */
        setInitialDistribution(0x36Dc5e71304a3826C54EF6F8a19C2c4160e8ce9c, 1000000, 9 * month); /* After 9 Months */
        setInitialDistribution(0x36Dc5e71304a3826C54EF6F8a19C2c4160e8ce9c, 1000000, 10 * month); /* After 10 Months */
        setInitialDistribution(0x36Dc5e71304a3826C54EF6F8a19C2c4160e8ce9c, 1000000, 11 * month); /* After 11 Months */
        setInitialDistribution(0x36Dc5e71304a3826C54EF6F8a19C2c4160e8ce9c, 1000000, 12 * month); /* After 12 Months */

        /* Liquidity Fund */
        setInitialDistribution(0xDD2AA97FB05aE47d1227FaAc488Ad8678e8Ea4F2, 5000000, 0 /* No Lock */);
        setInitialDistribution(0xDD2AA97FB05aE47d1227FaAc488Ad8678e8Ea4F2, 2000000, 1 * month); /* After 1 Month */
        setInitialDistribution(0xDD2AA97FB05aE47d1227FaAc488Ad8678e8Ea4F2, 2000000, 2 * month); /* After 2 Months */
        setInitialDistribution(0xDD2AA97FB05aE47d1227FaAc488Ad8678e8Ea4F2, 2000000, 3 * month); /* After 3 Months */
        setInitialDistribution(0xDD2AA97FB05aE47d1227FaAc488Ad8678e8Ea4F2, 2000000, 4 * month); /* After 4 Months */
        setInitialDistribution(0xDD2AA97FB05aE47d1227FaAc488Ad8678e8Ea4F2, 2000000, 5 * month); /* After 5 Months */
        setInitialDistribution(0xDD2AA97FB05aE47d1227FaAc488Ad8678e8Ea4F2, 1500000, 6 * month); /* After 6 Months */
        setInitialDistribution(0xDD2AA97FB05aE47d1227FaAc488Ad8678e8Ea4F2, 1000000, 7 * month); /* After 7 Months */
        setInitialDistribution(0xDD2AA97FB05aE47d1227FaAc488Ad8678e8Ea4F2, 1000000, 8 * month); /* After 8 Months */
        setInitialDistribution(0xDD2AA97FB05aE47d1227FaAc488Ad8678e8Ea4F2, 1000000, 9 * month); /* After 9 Months */
        setInitialDistribution(0xDD2AA97FB05aE47d1227FaAc488Ad8678e8Ea4F2, 1000000, 10 * month); /* After 10 Months */
        setInitialDistribution(0xDD2AA97FB05aE47d1227FaAc488Ad8678e8Ea4F2, 1000000, 11 * month); /* After 11 Months */
        setInitialDistribution(0xDD2AA97FB05aE47d1227FaAc488Ad8678e8Ea4F2, 1000000, 12 * month); /* After 12 Months */

        /* Foundational Reserve Fund */
        setInitialDistribution(0x20373581F525d1b85f9F9B5e7594eD5EE9a8Bc21, 2500000, year);
        setInitialDistribution(0x20373581F525d1b85f9F9B5e7594eD5EE9a8Bc21, 2500000, year.add(3 * month)); /* After 3 Month */
        setInitialDistribution(0x20373581F525d1b85f9F9B5e7594eD5EE9a8Bc21, 2500000, year.add(6 * month)); /* After 6 Month */
        setInitialDistribution(0x20373581F525d1b85f9F9B5e7594eD5EE9a8Bc21, 2500000, year.add(9 * month)); /* After 9 Month */
    }

    function setTokenAddress(address _tokenAddress) external onlyOwner whenNotPaused  {
        erc20 = ERC20(_tokenAddress);
    }
    
    function safeGuardAllTokens(address _address) external onlyOwner whenPaused  { /* In case of needed urgency for the sake of contract bug */
        require(erc20.transfer(_address, erc20.balanceOf(address(this))));
    }

    function setTGEDate(uint256 _time) external onlyOwner whenNotPaused  {
        TGEDate = _time;
    }

    /**
    *   Should allow any address to trigger it, but since the calls are atomic it should do only once per day
     */

    function triggerTokenSend() external whenNotPaused  {
        /* Require TGE Date already been set */
        require(TGEDate != 0, "TGE date not set yet");
        /* TGE has not started */
        require(block.timestamp > TGEDate, "TGE still hasn´t started");
        /* Test that the call be only done once per day */
        require(block.timestamp.sub(lastDateDistribution) > 1 days, "Can only be called once a day");
        lastDateDistribution = block.timestamp;
        /* Go thru all tokenOwners */
        for(uint i = 0; i < tokenOwners.length; i++) {
            /* Get Address Distribution */
            DistributionStep[] memory d = distributions[tokenOwners[i]];
            /* Go thru all distributions array */
            for(uint j = 0; j < d.length; j++){
                if( (block.timestamp.sub(TGEDate) > d[j].unlockDay) /* Verify if unlockDay has passed */
                    && (d[j].currentAllocated > 0) /* Verify if currentAllocated > 0, so that address has tokens to be sent still */
                ){
                    uint256 sendingAmount;
                    sendingAmount = d[j].currentAllocated;
                    distributions[tokenOwners[i]][j].currentAllocated = distributions[tokenOwners[i]][j].currentAllocated.sub(sendingAmount);
                    distributions[tokenOwners[i]][j].amountSent = distributions[tokenOwners[i]][j].amountSent.add(sendingAmount);
                    require(erc20.transfer(tokenOwners[i], sendingAmount));
                }
            }
        }   
    }

    function setInitialDistribution(address _address, uint256 _tokenAmount, uint256 _unlockDays) internal onlyOwner whenNotPaused {
        /* Add tokenOwner to Eachable Mapping */
        bool isAddressPresent = false;

        /* Verify if tokenOwner was already added */
        for(uint i = 0; i < tokenOwners.length; i++) {
            if(tokenOwners[i] == _address){
                isAddressPresent = true;
            }
        }
        /* Create DistributionStep Object */
        DistributionStep memory distributionStep = DistributionStep(_tokenAmount * decimals, _tokenAmount * decimals, _unlockDays, 0);
        /* Attach */
        distributions[_address].push(distributionStep);

        /* If Address not present in array of iterable token owners */
        if(!isAddressPresent){
            tokenOwners.push(_address);
        }

    }
}
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
function triggerTokenSend() external whenNotPaused  {
    /* Require TGE Date already been set */
    require(TGEDate != 0, "TGE date not set yet");
    /* TGE has not started */
    require(block.timestamp > TGEDate, "TGE still hasn´t started");
    /* Test that the call be only done once per day */
    require(block.timestamp.sub(lastDateDistribution) > 1 days, "Can only be called once a day");
    lastDateDistribution = block.timestamp;
    /* Go thru all tokenOwners */
    for(uint i = 0; i < tokenOwners.length; i++) {
        /* Get Address Distribution */
        DistributionStep[] memory d = distributions[tokenOwners[i]];
        /* Go thru all distributions array */
        for(uint j = 0; j < d.length; j++){
            if( (block.timestamp.sub(TGEDate) > d[j].unlockDay) /* Verify if unlockDay has passed */
                && (d[j].currentAllocated > 0) /* Verify if currentAllocated > 0, so that address has tokens to be sent still */
            ){
                uint256 sendingAmount;
                sendingAmount = d[j].currentAllocated;
                distributions[tokenOwners[i]][j].currentAllocated = distributions[tokenOwners[i]][j].currentAllocated.sub(sendingAmount);
                distributions[tokenOwners[i]][j].amountSent = distributions[tokenOwners[i]][j].amountSent.add(sendingAmount);
                require(erc20.transfer(tokenOwners[i], sendingAmount));
            }
        }
    }   
}

/**
 *   Should allow any address to trigger it, but since the calls are atomic it should do only once per day
 */