// Contract: CryptoSharesFactory
// Target function: function payDividendsToNext() external returns (bool success)
al code, city, street, house/building number,
    * apartment/office number)
    * @param signedOnUnixTime Timestamp of the signature
    */
    struct Signature {
        uint signatureNumber;
        uint shareholderId;
        address signatoryRepresentedBy;
        string signatoryName;
        string signatoryRegistrationNumber;
        string signatoryAddress;
        uint signedOnUnixTime;
    }

    // signature number => signature data (struct)
    mapping(uint256 => Signature) public disputeResolutionAgreementSignaturesByNumber;

    // shareholder address => number of signatures made from this address
    mapping(address => uint) public addressSignaturesCounter;

    // shareholder address => ( signature number for this shareholder => signature data)
    mapping(address => mapping(uint => Signature)) public signaturesByAddress;

    /**
    * dev: Event to be emitted when Dispute Resolution agreement was signed by a new person (we call this person 'signatory')
    *
    * @param signatureNumber Number of the signature (see 'disputeResolutionAgreementSignaturesCounter')
    * @param signatoryRepresentedBy Ethereum address of the person who signed disputeResolution agreement
    * @param signatoryName Name of the person who signed disputeResolution agreement
    * @param signatoryShareholderId Id of the shareholder that made this signature
    * @param signatoryRegistrationNumber Registration number of legal entity, or ID number of physical person (string)
    * @param signatoryAddress Address of the signatory (country/State, ZIP/postal code, city, street, house/building number, apartment/office number)
    * @param signedOnUnixTime Signature timestamp
    */
    event disputeResolutionAgreementSigned(
        uint256 indexed signatureNumber,
        address indexed signatoryRepresentedBy,
        string signatoryName,
        uint indexed signatoryShareholderId,
        string signatoryRegistrationNumber,
        string signatoryAddress,
        uint signedOnUnixTime
    );

    /**
    * @dev This is the function to make a signature of the shareholder under arbitration agreement.
    * The identity of a person (ETH address) who make a signature has to be verified via Cryptonomica.net verification.
    * This verification identifies the physical person who owns the key of ETH address. It this physical person is
    * a representative of a legal person or an other physical person, it's a responsibility of a person who makes transaction
    * (i.e. verified person) to provide correct data of a person he/she represents, if not he/she considered as acting
    * in his/her own name and not as representative.
    *
    * @param _shareholderId Id of the shareholder
    * @param _signatoryName Name of the person who signed disputeResolution agreement
    * @param _signatoryRegistrationNumber Registration number of legal entity, or ID number of physical person
    * @param _signatoryAddress Address of the signatory (country/State, ZIP/postal code, city, street, house/building number, apartment/office number)
    */
    function signDisputeResolutionAgreement(
        uint _shareholderId,
        string memory _signatoryName,
        string memory _signatoryRegistrationNumber,
        string memory _signatoryAddress
    ) private {

        require(
            addressIsVerifiedByCryptonomica(msg.sender),
            "Signer has to be verified on Cryptonomica.net"
        );

        disputeResolutionAgreementSignaturesCounter++;
        addressSignaturesCounter[msg.sender] = addressSignaturesCounter[msg.sender] + 1;

        disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatureNumber = disputeResolutionAgreementSignaturesCounter;
        disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].shareholderId = _shareholderId;
        disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatoryRepresentedBy = msg.sender;
        disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatoryName = _signatoryName;
        disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatoryRegistrationNumber = _signatoryRegistrationNumber;
        disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatoryAddress = _signatoryAddress;
        disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signedOnUnixTime = now;

        signaturesByAddress[msg.sender][addressSignaturesCounter[msg.sender]] = disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter];

        emit disputeResolutionAgreementSigned(
            disputeResolutionAgreementSignaturesCounter,
            disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatoryRepresentedBy,
            disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatoryName,
            disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].shareholderId,
            disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatoryRegistrationNumber,
            disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signatoryAddress,
            disputeResolutionAgreementSignaturesByNumber[disputeResolutionAgreementSignaturesCounter].signedOnUnixTime
        );

    }

    /* ===== Shareholders management =============== */

    /**
    * dev: counts all shareholders in smart contract history
    */
    uint public shareholdersCounter;

    /*
    * Shares hold by registered shareholders, i.e. not "in transfer"
    * like 'totalSupply' but counts tokens of registered shareholders only
    */
    uint public registeredShares;

    /**
    * dev: keeps address for each shareholder ID/number (according to shareholdersCounter)
    * if zero -> not a registered shareholder
    */
    mapping(address => uint) public shareholderID;

    /*
    * @param shareholderID The same as in shareholderID mapping
    * @param shareholderEthereumAddress Ethereum address of the shareholder
    * @param shareholderName Legal name of the shareholder, it can be name of the legal person, or fist and last name
    * for the physical person
    * @param shareholderRegistrationNumber Registration number of the legal person or personal ID of the physical person
    * @param shareholderAddress Shareholder's legal address (house number, street, city, zip, country)
    * @param  shareholderIsLegalPerson True if shareholder is a legal person, false if shareholder is a physical person
    * @param linkToSignersAuthorityToRepresentTheShareholder Link to ledger/register record or to document that
    * contains information about person's that manages ETH address  authority to represent the shareholder. If shareholder
    * is a physical person that represents himself/herself can contain "no representation" string
    * @param balanceOf This is the same as balanceOf(shareholderEthereumAddress), stored here for convenience
    * (to get all shareholder's data in one request)
    */
    struct Shareholder {
        uint shareholderID;                                     // 1
        address payable shareholderEthereumAddress;             // 2
        string shareholderName;                                 // 3
        string shareholderRegistrationNumber;                   // 4
        string shareholderAddress;                              // 5
        bool shareholderIsLegalPerson;                          // 6
        string linkToSignersAuthorityToRepresentTheShareholder; // 7
        uint balanceOf;                                         // 8
    }

    mapping(uint => Shareholder) public shareholdersLedgerByIdNumber;

    mapping(address => Shareholder) public shareholdersLedgerByEthAddress;

    event shareholderAddedOrUpdated(
        uint indexed shareholderID,
        address shareholderEthereumAddress,
        bool indexed isLegalPerson,
        string shareholderName,
        string shareholderRegistrationNumber,
        string shareholderAddress,
        uint shares,
        bool indexed newRegistration
    );

    /*
    * @notice Using this function a token holder can register himself as shareholder.
    * Any share (token) not owned of registered shareholder is considered 'in transfer'.
    * Shares 'in transfer' can not vote and does not receive dividends.
    * In the ledger (variables: 'shareholderID', 'shareholderEthereumAddress' and so on ) we store data of all
    * historical shareholders,
    * and they persist even if a shareholder transferred all his shares and his 'balanceOf' is zero.
    * @param _isLegalPerson This indicates if new shareholder is a legal person or physical person.
    * @param _shareholderName Legal name of the shareholder. If this is different from name registered in Cryptonomica
    * verification smart contract, we consider a person registered in Cryptonomica smart contract representative of the
    * shareholder.
    * @param _shareholderRegistrationNumber Registration number of a legal person or personal ID number for physical person.
    * @param  _shareholderAddress Shareholder's legal address (country/state, street, building/house number, apartment/office number)
    *
    * we allow allow change/update shareholder data (if entered incorrectly or some data changed) by calling
    * this function again by existing shareholder
    */
    function registerAsShareholderAndSignArbitrationAgreement(
        bool _isLegalPerson,
        string calldata _shareholderName,
        string calldata _shareholderRegistrationNumber,
        string calldata _shareholderAddress,
        string calldata _linkToSignersAuthorityToRepresentTheShareholder
    ) external returns (bool success){

        require(
            balanceOf[msg.sender] > 0,
            "To be registered address has to hold at least one token/share"
        );

        require(
            addressIsVerifiedByCryptonomica(msg.sender),
            "Shareholder address has to be verified on Cryptonomica"
        );

        bool newShareholder;
        uint id;

        if (shareholderID[msg.sender] == 0) {
            shareholdersCounter++;
            id = shareholdersCounter;
            shareholderID[msg.sender] = id;
            newShareholder = true;
            /* add these shares to shares of registered shareholders (i.e. not "in transfer"*/
            registeredShares = registeredShares.add(balanceOf[msg.sender]);
        } else {
            id = shareholderID[msg.sender];
            newShareholder = false;
        }

        // 1
        shareholdersLedgerByIdNumber[id].shareholderID = id;
        // 2
        shareholdersLedgerByIdNumber[id].shareholderEthereumAddress = msg.sender;
        // 3
        shareholdersLedgerByIdNumber[id].shareholderName = _shareholderName;
        // 4
        shareholdersLedgerByIdNumber[id].shareholderRegistrationNumber = _shareholderRegistrationNumber;
        // 5
        shareholdersLedgerByIdNumber[id].shareholderAddress = _shareholderAddress;
        // 6
        shareholdersLedgerByIdNumber[id].shareholderIsLegalPerson = _isLegalPerson;
        // 7
        shareholdersLedgerByIdNumber[id].linkToSignersAuthorityToRepresentTheShareholder = _linkToSignersAuthorityToRepresentTheShareholder;
        // 8
        shareholdersLedgerByIdNumber[id].balanceOf = balanceOf[msg.sender];

        /* copy struct  */
        shareholdersLedgerByEthAddress[msg.sender] = shareholdersLedgerByIdNumber[id];

        emit shareholderAddedOrUpdated(
            shareholdersLedgerByIdNumber[id].shareholderID,
            shareholdersLedgerByIdNumber[id].shareholderEthereumAddress,
            shareholdersLedgerByIdNumber[id].shareholderIsLegalPerson,
            shareholdersLedgerByIdNumber[id].shareholderName,
            shareholdersLedgerByIdNumber[id].shareholderRegistrationNumber,
            shareholdersLedgerByIdNumber[id].shareholderAddress,
            shareholdersLedgerByIdNumber[id].balanceOf,
            newShareholder
        );

        /*
        * even if shareholder updates data he makes new signature under dispute resolution agreement
        */
        signDisputeResolutionAgreement(
            id,
            shareholdersLedgerByIdNumber[id].shareholderName,
            shareholdersLedgerByIdNumber[id].shareholderRegistrationNumber,
            shareholdersLedgerByIdNumber[id].shareholderAddress
        );

        return true;
    }

    /* ---------------- Dividends --------------- */

    /**
    * Time in seconds between dividends distribution rounds.
    * Next round can be started only if the specified number of seconds has elapsed since the end of the previous round.
    * See: https://en.wikipedia.org/wiki/Dividend#Dividend_frequency
    */
    uint public dividendsPeriod;

    /*
    * @param roundIsRunning Shows if this dividends payouts round is running.
    * @param sumWeiToPayForOneToken Sum in wei to pay for one token in this round.
    * @param sumXEurToPayForOneToken Sum in xEUR to pay for one token in this round.
    * @param allRegisteredShareholders Number of all shareholder registered in whole smart contract.
    * history, at the moment this round was started.
    * @shareholdersCounter Number (id) of shareholder to whom last payment was made.
    * On the start it will be 0, and on the end of the round shareholdersCounter == allRegisteredShareholders.
    * @registeredShares Number of shares that will receive dividends in this round, i.e. number of shares,
    * hold by registered shareholder (that's all shares minus shares 'in transfer')
    * @param roundStartedOnUnixTime Timestamp.
    * @param roundFinishedOnUnixTime Timestamp.
    * @param weiForTxFees Amount in wei deposited for this round to reward those who make transactions to distribute
    * dividends.
    */
    struct DividendsRound {
        bool roundIsRunning; //............0
        uint sumWeiToPayForOneToken; //....1
        uint sumXEurToPayForOneToken; //...2
        uint allRegisteredShareholders; //.3
        uint shareholdersCounter; //.......4
        uint registeredShares; //..........5
        uint roundStartedOnUnixTime; //....6
        uint roundFinishedOnUnixTime; //...7
        uint weiForTxFees; //..............8
    }

    /**
    * 'dividendsRoundsCounter' holds the sequence number of the last (or current) round of dividends payout
    * We record all historical dividends payouts data
    */
    uint public dividendsRoundsCounter;
    mapping(uint => DividendsRound) public dividendsRound;

    /*
    * @param dividendsRound Number of dividends distribution round.
    * @param startedBy ETH address that started round (if time to pay dividends, can be started by any ETH address)
    * @param totalWei Sum in wei that has to be distributed in this round.
    * @param totalXEur Sum in xEUR that has to be distributed in this round.
    * @param sharesToPayDividendsTo The same as 'registeredShares' in struct DividendsRound.
    * @param sumWeiToPayForOneShare Sum in wei to pay for one token in this round.
    * @param sumXEurToPayForOneShare Sum in xEUR to pay for one token in this round.
    */
    event DividendsPaymentsStarted(
        uint indexed dividendsRound, //..0
        address indexed startedBy, //...1
        uint totalWei, //................2
        uint totalXEur, //...............3
        uint sharesToPayDividendsTo, //..4
        uint sumWeiToPayForOneShare, //..5
        uint sumXEurToPayForOneShare //..6
    );

    /**
    * @param dividendsRound Number of dividends distribution round
    */
    event DividendsPaymentsFinished(
        uint indexed dividendsRound
    );

    /**
    * dev: Info about the payment in ETH made to next shareholder
    */
    event DividendsPaymentEther (
        bool indexed success,
        address indexed to,
        uint shareholderID,
        uint shares,
        uint sumWei,
        uint indexed dividendsRound
    );

    /**
    * dev: Info about the payment in xEUR made to next shareholder
    */
    event DividendsPaymentXEuro (
        bool indexed success,
        address indexed to,
        uint shareholderID,
        uint shares,
        uint sumXEuro,
        uint indexed dividendsRound
    );

    /*
    * @notice This function starts dividend payout round, and can be started from ANY address if the time has come.
    */
    function startDividendsPayments() public returns (bool success) {

        require(
            dividendsRound[dividendsRoundsCounter].roundIsRunning == false,
            "Already running"
        );

        // dividendsRound[dividendsRoundsCounter].roundFinishedOnUnixTime is zero for first round
        // so it can be started right after contract deploy
        require(now.sub(dividendsRound[dividendsRoundsCounter].roundFinishedOnUnixTime) > dividendsPeriod,
            "To early to start"
        );

        require(registeredShares > 0,
            "No registered shares to distribute dividends to"
        );

        uint sumWeiToPayForOneToken = address(this).balance / registeredShares;
        uint sumXEurToPayForOneToken = xEuro.balanceOf(address(this)) / registeredShares;

        require(
            sumWeiToPayForOneToken > 0 || sumXEurToPayForOneToken > 0,
            "Nothing to pay"
        );

        // here we start the next dividends payout round:
        dividendsRoundsCounter++;

        dividendsRound[dividendsRoundsCounter].roundIsRunning = true;
        dividendsRound[dividendsRoundsCounter].roundStartedOnUnixTime = now;
        dividendsRound[dividendsRoundsCounter].registeredShares = registeredShares;
        dividendsRound[dividendsRoundsCounter].allRegisteredShareholders = shareholdersCounter;

        dividendsRound[dividendsRoundsCounter].sumWeiToPayForOneToken = sumWeiToPayForOneToken;
        dividendsRound[dividendsRoundsCounter].sumXEurToPayForOneToken = sumXEurToPayForOneToken;

        emit DividendsPaymentsStarted(
            dividendsRoundsCounter,
            msg.sender,
            address(this).balance,
            xEuro.balanceOf(address(this)),
            registeredShares,
            sumWeiToPayForOneToken,
            sumXEurToPayForOneToken
        );

        return true;
    }

    /*
    * @dev Reward for tx distributing dividends was paid
    * @dividendsRoundNumber Number (Id) of dividends round.
    * @dividendsToShareholderNumber Shareholder ID, to whom payment was made by the transaction
    * @dividendsToShareholderAddress Shareholder ETH address, to whom payment was made by the transaction
    * @feePaidTo Address (ETH), who received the reward (this is the address who send tx to pay dividends to above
    * stated shareholder
    * @feeInWei Amount of the reward paid.
    * @paymentSuccesful Shows if fee payment was successful (msg.sender.send == true)
    */
    event FeeForDividendsDistributionTxPaid(
        uint indexed dividendsRoundNumber,
        uint dividendsToShareholderNumber,
        address dividendsToShareholderAddress,
        address indexed feePaidTo,
        uint feeInWei,
        bool feePaymentSuccesful
    );