// Contract: CryptoSharesFactory
// Target function: function initToken(
endsRoundsCounter].shareholdersCounter + 1;

        uint nextShareholderToPayDividends = dividendsRound[dividendsRoundsCounter].shareholdersCounter;

        uint sumWeiToPayForOneToken = dividendsRound[dividendsRoundsCounter].sumWeiToPayForOneToken;
        uint sumXEurToPayForOneToken = dividendsRound[dividendsRoundsCounter].sumXEurToPayForOneToken;

        address payable to = shareholdersLedgerByIdNumber[nextShareholderToPayDividends].shareholderEthereumAddress;

        if (balanceOf[to] > 0) {

            if (sumWeiToPayForOneToken > 0) {

                uint sumWeiToPay = sumWeiToPayForOneToken * balanceOf[to];

                // 'send' is the low-level counterpart of 'transfer'.
                // If the execution fails, the current contract will not stop with an exception, but 'send' will return false.
                // https://solidity.readthedocs.io/en/v0.5.10/types.html?highlight=send#members-of-addresses
                // So we use 'send' and not 'transfer' to ensure that execution continues even if sending ether fails.
                bool result = to.send(sumWeiToPay);
                emit DividendsPaymentEther(
                    result,
                    to,
                    nextShareholderToPayDividends,
                    balanceOf[to],
                    sumWeiToPay,
                    dividendsRoundsCounter
                );
            }

            if (sumXEurToPayForOneToken > 0) {
                uint sumXEuroToPay = sumXEurToPayForOneToken * balanceOf[to];
                //  if (sumXEuroToPay <= xEuro.balanceOf(address(this))) {
                bool result = xEuro.transfer(to, sumXEuroToPay);
                emit DividendsPaymentXEuro(
                    result,
                    to,
                    nextShareholderToPayDividends,
                    sumXEuroToPay,
                    nextShareholderToPayDividends,
                    dividendsRoundsCounter
                );
                //  }
            }

        }

        // if the round started shareholdersCounter can not be zero
        // because to start the round we need at least one registered share and thus at least one registered shareholder

        uint feeForTxCaller = dividendsRound[dividendsRoundsCounter].weiForTxFees / shareholdersCounter;

        if (
            feeForTxCaller > 0
            && msg.sender == tx.origin // < msg.sender is not a contract (to prevent reentrancy)
        ) {

            // we use send not transfer (returns false, not fail)
            bool feePaymentSuccessful = msg.sender.send(feeForTxCaller);
            emit FeeForDividendsDistributionTxPaid(
                dividendsRoundsCounter,
                nextShareholderToPayDividends,
                to,
                msg.sender,
                feeForTxCaller,
                feePaymentSuccessful
            );
        }

        // if this is the last registered shareholder for this round
        // then FINISH the round:
        if (nextShareholderToPayDividends == shareholdersCounter) {

            dividendsRound[dividendsRoundsCounter].roundIsRunning = false;
            dividendsRound[dividendsRoundsCounter].roundFinishedOnUnixTime = now;

            emit DividendsPaymentsFinished(
                dividendsRoundsCounter
            );
        }

        return true;
    }

    /*
    * Interested party can provide funds to pay for dividends distribution.
    * @param forDividendsRound Number (Id) of dividends payout round.
    * @param sumInWei Sum in wei received.
    * @param from Address from which sum was received.
    * @param currentSum Current sum of wei to reward accounts sending dividends distributing transactions.
    */
    event FundsToPayForDividendsDistributionReceived(
        uint indexed forDividendsRound,
        uint sumInWei,
        address indexed from,
        uint currentSum
    );

    /*
    * Function to add funds to reward transactions distributing dividends in this round/
    */
    function fundDividendsPayout() public payable returns (bool success){

        /* We allow this only for running round */
        require(
            dividendsRound[dividendsRoundsCounter].roundIsRunning,
            "Dividends payout is not running"
        );

        dividendsRound[dividendsRoundsCounter].weiForTxFees = dividendsRound[dividendsRoundsCounter].weiForTxFees + msg.value;

        emit FundsToPayForDividendsDistributionReceived(
            dividendsRoundsCounter,
            msg.value,
            msg.sender,
            dividendsRound[dividendsRoundsCounter].weiForTxFees // totalSum
        );

        return true;
    }

    /*
    * @dev startDividendsPayments() and fundDividendsPayout() combined for convenience
    */
    function startDividendsPaymentsAndFundDividendsPayout() external payable returns (bool success) {
        startDividendsPayments();
        return fundDividendsPayout();
    }

    /* ============= ERC20 functions ============ */

    /**
    * dev:
    * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md#approve
    * there is an attack:
    * https://github.com/CORIONplatform/solidity/issues/6,
    * https://drive.google.com/file/d/0ByMtMw2hul0EN3NCaVFHSFdxRzA/view
    * but this function is required by ERC-20:
    * To prevent attack vectors like the one described on https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/
    * and discussed on https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 ,
    * clients SHOULD make sure to create user interfaces in such a way that they set the allowance first to 0 before
    * setting it to another value for the same spender.
    * THOUGH The contract itself shouldn't enforce it, to allow backwards compatibility with contracts deployed before
    *
    * @param _spender The address which will spend the funds.
    * @param _value The amount of tokens to be spent.
    */
    function approve(address _spender, uint _value) public returns (bool success){
        allowance[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }

    /**
    * @notice Approve another address to spend tokens from the tokenholder account
    * dev: Overloaded approve function
    *      See https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/
    * @param _spender The address which will spend the funds.
    * @param _currentValue The current value of allowance for spender
    * @param _value The amount of tokens to be spent.
    */
    function approve(address _spender, uint _currentValue, uint _value) external returns (bool success){
        require(
            allowance[msg.sender][_spender] == _currentValue,
            "Current value in contract is different than provided current value"
        );
        return approve(_spender, _value);
    }

    /**
    * dev: private function that checks and changes balances and allowances for transfer functions
    */
    function _transferFrom(address _from, address _to, uint _value) private returns (bool success) {

        require(
            _to != address(0),
            "_to was 0x0 address"
        );

        require(
            !dividendsRound[dividendsRoundsCounter].roundIsRunning,
            "Transfers blocked while dividends are distributed"
        );

        require(
            _from == msg.sender || _value <= allowance[_from][msg.sender],
            "Sender not authorized"
        );

        // check if _from account has the required amount, if not, throw an exception
        require(
            _value <= balanceOf[_from],
            "Account doesn't have required amount"
        );

        balanceOf[_from] = balanceOf[_from].sub(_value);
        balanceOf[_to] = balanceOf[_to].add(_value);

        uint fromId = shareholderID[_from];
        uint toId = shareholderID[_to];

        if (fromId > 0) {
            shareholdersLedgerByEthAddress[_from].balanceOf = balanceOf[_from];
            shareholdersLedgerByIdNumber[fromId].balanceOf = balanceOf[_from];
        }

        if (toId > 0) {
            shareholdersLedgerByEthAddress[_to].balanceOf = balanceOf[_to];
            shareholdersLedgerByIdNumber[toId].balanceOf = balanceOf[_to];
        }

        if (fromId > 0 && toId == 0) {
            // shares goes from registered address to unregistered address
            // subtract from 'registeredShares'
            registeredShares = registeredShares.sub(_value);
        } else if (fromId == 0 && toId > 0) {
            // shares goes from unregistered address to registered address
            // add to 'registeredShares'
            registeredShares = registeredShares.add(_value);
        }

        // If allowance used, change allowances correspondingly
        if (_from != msg.sender) {
            allowance[_from][msg.sender] = allowance[_from][msg.sender].sub(_value);
        }

        emit Transfer(_from, _to, _value);

        return true;
    }

    /*
    * dev: Private function, that calls 'tokenFallback' function if token receiver is a contract.
    */
    function _erc223Call(address _to, uint _value, bytes memory _data) private returns (bool success) {

        uint codeLength;

        assembly {
        // Retrieve the size of the code on target address, this needs assembly .
            codeLength := extcodesize(_to)
        }

        if (codeLength > 0) {
            ERC223ReceivingContract receiver = ERC223ReceivingContract(_to);
            receiver.tokenFallback(msg.sender, _value, _data);
            emit DataSentToAnotherContract(msg.sender, _to, _data);
        }

        return true;
    }

    /**
     * @notice Transfers tokens from one address to another.
     *         Sender can send own tokens or or those tokens that he is allowed to transfer.
     * dev: Transfer the specified amount of tokens to the specified address.
     *      Invokes the `tokenFallback` function if the recipient is a contract.
     *      The token transfer fails if the recipient is a contract
     *      but does not implement the `tokenFallback` function
     *      or the fallback function to receive funds.
     * @param _to  Receiver address.
     * @param _value Amount of tokens that will be transferred.
     */
    function transferFrom(address _from, address _to, uint _value) public returns (bool success){

        _transferFrom(_from, _to, _value);

        // see:
        // https://github.com/Dexaran/ERC223-token-standard/pull/54
        // https://github.com/Dexaran/ERC223-token-standard/issues/53
        bytes memory empty = hex"00000000";

        return _erc223Call(_to, _value, empty);

    } // end of transferFrom

    /*
    * @notice Transfer tokens from tx sender address to another address.
    *         The rest is similar to the 'transferFrom' function.
    */
    function transfer(address _to, uint _value) public returns (bool success){
        return transferFrom(msg.sender, _to, _value);
    }

    /**
    * @notice (ERC223) Transfers tokens to another address with additional info.
    * dev: Overloaded 'transfer' function (ERC223 standard)
    *      See: https://github.com/ethereum/EIPs/issues/223
    *      https://github.com/Dexaran/ERC223-token-standard/blob/Recommended/ERC223_Token.sol
    * @param _to    Receiver address.
    * @param _value Amount of tokens that will be transferred.
    * @param _data  Transaction metadata.
    */
    function transfer(address _to, uint _value, bytes calldata _data) external returns (bool success){

        _transferFrom(msg.sender, _to, _value);

        return _erc223Call(_to, _value, _data);
    }


    /* ============= VOTING ================ */

    /*
    * This smart contract implements voting for shareholders of ERC20 tokens based on the principle
    * "one share - one vote"
    * It requires external script to count votes.
    *
    * Rules:
    * To start a voting an address have to own at lest one share.
    * To start a voting, voting creator must provide:
    * 1) text of the proposal,
    * 2) number of the block on which voting will be finished and results have to be calculated.
    *
    * Every proposal for a contract receives a sequence number that serves as a proposal ID.
    * To vote 'for' or 'against' voter has to provide proposal ID.
    *
    * In most scenarios only votes 'for' can be used, who did not voted 'for' can be considered as voted 'against'.
    * But our dApp also supports votes 'against'
    *
    * To calculate results we collect all voted addresses by an external script, which is also open sourced.
    * Than we check their balances in tokens on resulting block, and and sum up the voices.
    * Thus, for the results, the number of tokens of the voter at the moment of voting does not matter
    * (it should just has at least one).
    * What matters is the number of tokens on the voter's address on the block where the results should calculated.
    *
    * It's like https://www.cryptonomica.net/eth-vote/, but:
    * 1) for this contract only
    * 2) to start voting or to vote an address has to be registered as a shareholder, not just to have tokens
    *
    */

    // Counts all voting created in this smart contract
    uint public votingCounterForContract;

    // proposal id => text of the proposal
    mapping(uint => string) public proposalText;

    // proposal id => number of voters
    mapping(uint => uint256) public numberOfVotersFor;
    mapping(uint => uint256) public numberOfVotersAgainst;

    // proposal id => (voter id => voter address)
    mapping(uint => mapping(uint256 => address)) public votedFor;
    mapping(uint => mapping(uint256 => address)) public votedAgainst;

    // proposal id => (voter address => voter has voted already)
    mapping(uint => mapping(address => bool)) public boolVotedFor;
    mapping(uint => mapping(address => bool)) public boolVotedAgainst;

    // proposal ID => block number
    mapping(uint => uint) public resultsInBlock;

    /*
    * @param proposalId Number of this voting, according to 'votingCounterForContract'
    * @param by Address that created proposal
    * @param proposalText Text of the proposal
    * @param resultsInBlock Block to calculate results of voting.
    */
    event Proposal(
        uint indexed proposalID,
        address indexed by,
        string proposalText,
        uint indexed resultsInBlock
    );

    // to run function an address has to be registered as a shareholder and own at least one share
    modifier onlyShareholder() {
        require(
            shareholdersLedgerByEthAddress[msg.sender].shareholderID != 0 && balanceOf[msg.sender] > 0,
            "Only shareholder can do that"
        );
        _;
    }

    /*
    * @notice Creates proposal for voting.
    * @param _proposalText Text of the proposal.
    * @param _resultsInBlock Number of block on which results will be counted.
    */
    function createVoting(
        string calldata _proposalText,
        uint _resultsInBlock
    ) onlyShareholder external returns (bool success){

        require(
            _resultsInBlock > block.number,
            "Block for results should be later than current block"
        );

        votingCounterForContract++;

        proposalText[votingCounterForContract] = _proposalText;
        resultsInBlock[votingCounterForContract] = _resultsInBlock;

        emit Proposal(votingCounterForContract, msg.sender, proposalText[votingCounterForContract], resultsInBlock[votingCounterForContract]);

        return true;
    }

    // Vote 'for' received
    event VoteFor(
        uint indexed proposalID,
        address indexed by
    );

    // Vote 'against' received
    event VoteAgainst(
        uint indexed proposalID,
        address indexed by
    );

    /*
    * @notice Vote for the proposal
    * @param _proposalId Id (number) of the proposal
    */
    function voteFor(uint256 _proposalId) onlyShareholder external returns (bool success){

        require(
            resultsInBlock[_proposalId] > block.number,
            "Voting already finished"
        );

        require(
            !boolVotedFor[_proposalId][msg.sender] && !boolVotedAgainst[_proposalId][msg.sender],
            "Already voted"
        );

        numberOfVotersFor[_proposalId] = numberOfVotersFor[_proposalId] + 1;

        uint voterId = numberOfVotersFor[_proposalId];

        votedFor[_proposalId][voterId] = msg.sender;

        boolVotedFor[_proposalId][msg.sender] = true;

        emit VoteFor(_proposalId, msg.sender);

        return true;
    }

    /*
    * @notice Vote against the proposal
    * @param _proposalId Id (number) of the proposal
    */
    function voteAgainst(uint256 _proposalId) onlyShareholder external returns (bool success){

        require(
            resultsInBlock[_proposalId] > block.number,
            "Voting finished"
        );

        require(
            !boolVotedFor[_proposalId][msg.sender] && !boolVotedAgainst[_proposalId][msg.sender],
            "Already voted"
        );

        numberOfVotersAgainst[_proposalId] = numberOfVotersAgainst[_proposalId] + 1;

        uint voterId = numberOfVotersAgainst[_proposalId];

        votedAgainst[_proposalId][voterId] = msg.sender;

        boolVotedAgainst[_proposalId][msg.sender] = true;

        emit VoteAgainst(_proposalId, msg.sender);

        return true;
    }

    /*
    * This contract can receive Ether from any address.
    * Received Ether will be distributed as dividends to shareholders.
    */

    function addEtherToContract() external payable {
        // gas: 21482
    }

    function() external payable {
        // gas: 21040
    }