contract Dividends is ERC20Base, Ownable {

  DAppDEXI public DEX;

  address[] public tokens;
  mapping (address => uint) public tokensIndex;
  
  mapping (uint => mapping (address => uint)) public dividends;
  mapping (address => mapping (address => uint)) public ownersbal;  
  mapping (uint => mapping (address => mapping (address => bool))) public AlreadyReceived;

  uint public multiplier = 100000; // precision to ten thousandth percent (0.001%)

  event Payment(address indexed sender, uint amount);
  event setDEXContractEvent(address dex);
   
  function AddToken(address token) public {
    require(msg.sender == address(DEX));
    tokens.push(token);
    tokensIndex[token] = tokens.length-1;
  }

  function DelToken(address token) public {
    require(msg.sender == address(DEX));
    require(tokens[tokensIndex[token]] != 0);    
    tokens[tokensIndex[token]] = tokens[tokens.length-1];
    tokens.length = tokens.length-1;
  }

  // Take profit for dividends from DEX contract
  function TakeProfit(uint offset, uint limit) external {
    require (limit <= tokens.length);
    require (offset < limit);

    uint N = (block.timestamp - start) / period;
    
    require (N > 0);
    
    for (uint k = offset; k < limit; k++) {
      if(dividends[N][tokens[k]] == 0 ) {
          uint amount = DEX.balanceOf(tokens[k], address(this));
          if (k == 0) {
            DEX.withdraw(amount);
            dividends[N][tokens[k]] = amount;
          } else {
            DEX.withdrawToken(tokens[k], amount);
            dividends[N][tokens[k]] = amount;
          }
      }
    }
  }

  function () public payable {
      emit Payment(msg.sender, msg.value);
  }
  
  // PayDividends to owners
  function PayDividends(address token, uint offset, uint limit) external {
    //require (address(this).balance > 0);
    require (limit <= owners.length);
    require (offset < limit);

    uint N = (block.timestamp - start) / period; // current - 1
    uint date = start + N * period - 1;
    
    require(dividends[N][token] > 0);

    uint share = 0;
    uint k = 0;
    for (k = offset; k < limit; k++) {
      if (!AlreadyReceived[N][token][owners[k]]) {
        share = safeMul(balanceOf(owners[k], date), multiplier);
        share = safeDiv(safeMul(share, 100), totalSupply_); // calc the percentage of the totalSupply_ (from 100%)

        share = safePerc(dividends[N][token], share);
        share = safeDiv(share, safeDiv(multiplier, 100));  // safeDiv(multiplier, 100) - convert to hundredths
        
        ownersbal[owners[k]][token] = safeAdd(ownersbal[owners[k]][token], share);
        AlreadyReceived[N][token][owners[k]] = true;
      }
    }
  }

  // PayDividends individuals to msg.sender
  function PayDividends(address token) external {
    //require (address(this).balance > 0);

    uint N = (block.timestamp - start) / period; // current - 1
    uint date = start + N * period - 1;

    require(dividends[N][token] > 0);
    
    if (!AlreadyReceived[N][token][msg.sender]) {      
      uint share = safeMul(balanceOf(msg.sender, date), multiplier);
      share = safeDiv(safeMul(share, 100), totalSupply_); // calc the percentage of the totalSupply_ (from 100%)

      share = safePerc(dividends[N][token], share);
      share = safeDiv(share, safeDiv(multiplier, 100));  // safeDiv(multiplier, 100) - convert to hundredths
        
      ownersbal[msg.sender][token] = safeAdd(ownersbal[msg.sender][token], share);
      AlreadyReceived[N][token][msg.sender] = true;
    }
  }

  // withdraw dividends
  function withdraw(address token, uint _value) external {    
    require(ownersbal[msg.sender][token] >= _value);
    ownersbal[msg.sender][token] = safeSub(ownersbal[msg.sender][token], _value);
    if (token == address(0)) {
      msg.sender.transfer(_value);
    } else {
      ERC20I(token).transfer(msg.sender, _value);
    }
  }
  
  // withdraw dividends to address
  function withdraw(address token, uint _value, address _receiver) external {    
    require(ownersbal[msg.sender][token] >= _value);
    ownersbal[msg.sender][token] = safeSub(ownersbal[msg.sender][token], _value);
    if (token == address(0)) {
      _receiver.transfer(_value);
    } else {
      ERC20I(token).transfer(_receiver, _value);
    }    
  }

  function setMultiplier(uint _value) external onlyOwner {
    require(_value > 0);
    multiplier = _value;
  }
  
  function getMultiplier() external view returns (uint ) {
    return multiplier;
  }  

  // link to DEX contract
  function setDEXContract(address _contract) external onlyOwner {
    DEX = DAppDEXI(_contract);
    emit setDEXContractEvent(_contract);
  }
}
/**
 * @title Dividend Distribution Contract for DAO
 */
function TakeProfit(uint offset, uint limit) external {
    require (limit <= tokens.length);
    require (offset < limit);

    uint N = (block.timestamp - start) / period;
    
    require (N > 0);
    
    for (uint k = offset; k < limit; k++) {
      if(dividends[N][tokens[k]] == 0 ) {
          uint amount = DEX.balanceOf(tokens[k], address(this));
          if (k == 0) {
            DEX.withdraw(amount);
            dividends[N][tokens[k]] = amount;
          } else {
            DEX.withdrawToken(tokens[k], amount);
            dividends[N][tokens[k]] = amount;
          }
      }
    }
  }
// Take profit for dividends from DEX contract