contract BasicMultisig {
  string constant ALREADY_EXECUTED = "Operation already executed";

  VinciToken public vinci_contract;

  /// @notice Public map of owners
  mapping (address => bool) public owners;
  /// @notice Public map of admins
  mapping (address => bool) public admins;

  /// @notice multisig owners counters
  mapping (uint => uint) public ownersConfirmations;
  /// @notice multisig admins counters
  mapping (uint => uint) public adminsConfirmations;

  mapping (uint => mapping (address => bool)) public ownersSigns;
  mapping (uint => mapping (address => bool)) public adminsSigns;

  /// @notice executed tasks to prevent multiple execution
  mapping (uint => bool) public executed;

  modifier manageable() {
    require(isOwner(msg.sender) || isAdmin(msg.sender), "You're not admin or owner");
    _;
  }

  modifier shouldNotBeAlreadyExecuted(uint _operation) {
    require(!executed[_operation], ALREADY_EXECUTED);
    _;
  }

  modifier increasesConfirmationsCounter(uint _operation) {
    increaseConfirmationsCounter(_operation);
    _;
  }

  function isOwner(address who) public view returns (bool) {
    return owners[who];
  }

  function isAdmin(address who) public view returns (bool) {
    return admins[who];
  }

  uint public operation = 0;

  /// @dev Fallback function: don't accept ETH
  function() external payable {
    revert();
  }

  // common method
  modifier createsNewOperation() {
    operation++;
    if (isOwner(msg.sender)) {
      ownersConfirmations[operation] = 1;
      adminsConfirmations[operation] = 0;
      ownersSigns[operation][msg.sender] = true;
    } else {
      if (isAdmin(msg.sender)) {
        ownersConfirmations[operation] = 0;
        adminsConfirmations[operation] = 1;
        adminsSigns[operation][msg.sender] = true;
      }
    }
    _;
  }

  function increaseConfirmationsCounter(uint _operation) internal {
    if (isOwner(msg.sender)) {
      if (ownersSigns[_operation][msg.sender]) revert();
      ownersConfirmations[_operation] += 1;
    } else {
      if (isAdmin(msg.sender)) {
        if (adminsSigns[_operation][msg.sender]) revert();
        adminsConfirmations[_operation] += 1;
      }
    }
  }

  function enoughConfirmations(uint _operation) public view returns (bool) {
    uint totalConfirmations = ownersConfirmations[_operation] + adminsConfirmations[_operation];
    return ((ownersConfirmations[_operation] > 0) && (totalConfirmations > 2));
  }
  //
}
function() external payable {
  revert();
}

/// @dev Fallback function: don't accept ETH