// Contract: DeriVoteWithPayment
// Target function: function finalizeVote() public
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

contract DeriVoteWithPayment {

    event Vote(address indexed voter, uint256 votingId, uint256 optionId, uint256 amount);

    string public constant name = 'DeriVote';

    address public controller;

    // current voting id
    uint256 public votingId;
    // current voting name
    string  public votingName;
    // number of options for current voting
    uint256 public numOptions;
    // current vote deadline
    uint256 public votingDeadline;

    // voting topics, votingId => topic
    mapping (uint256 => string) public votingTopics;

    // current voting token, voters spend token to vote
    // the amount of token transferred to this contract is the amount of this vote
    address public votingToken;
    // current voting token receipient, must be intailized during initializeVote
    // this receipient cannot be changed for a specific vote
    address public votingTokenReceipient;

    // votings for options, votingId => optionId => votes
    mapping (uint256 => mapping (uint256 => uint256)) public votingsForOptions;

    modifier _controller_() {
        require(msg.sender == controller, 'DeriVote2: only controller');
        _;
    }

    constructor () {
        controller = msg.sender;
    }

    function setController(address newController) public _controller_ {
        controller = newController;
    }

    function initializeVote(
        string  memory _votingName,
        string  memory _topic,
        uint256 _numOptions,
        uint256 _votingDeadline,
        address _votingToken,
        address _votingTokenReceipient
    ) public _controller_ {
        require(block.timestamp >= votingDeadline, 'DeriVote2: still in vote');
        require(block.timestamp < _votingDeadline, 'DeriVote2: invalid deadline');
        require(
            votingToken == address(0) || IERC20(votingToken).balanceOf(address(this)) == 0,
            'DeriVote2: remain untransferred voting tokens'
        );

        votingId += 1;
        votingName = _votingName;
        numOptions = _numOptions;
        votingDeadline = _votingDeadline;
        votingToken = _votingToken;
        votingTokenReceipient = _votingTokenReceipient;
        votingTopics[votingId] = _topic;
    }