fix voting logic errors

fix voting logic errors

pragma solidity ^0.4.13;

contract Voting {

    enum Role { OWNER, COMPANY, RESIDENT}
    enum State { INITIAL, FUNDED, OPEN, APPROVED, CLOSED }

    mapping (address => Role) roles;
    State public state;

    event Funded(address addr, uint amount);
    event VotingOpened(uint threshold);
    event Approved(address addr, uint total);
    event VotingClosedSuccess(uint total);
    //event VotingClosedFailure();
    event Withdrawn(address addr, uint amount);

    mapping (address => bool) approved;
    uint numApproved;   // number of residents who approved
    uint threshold;     // required support in persent (1 to 100)

	// Addresses generated from seed.txt
    address[] private testAddresses;

    function assignTestAddresses(bool isRpc) internal {
        if (isRpc) {
    		testAddresses.push(0x0120fe6e3aa2c936e6d2f88062b266c46c408f98);
    		testAddresses.push(0xa8fc189694dc8ba03c027d470b77c09b7d13471e);
    		testAddresses.push(0xdbf73038f3e4a5d27e38004c36dc6ce82165794f);
    		testAddresses.push(0x692b50dc6d0021a73ec50fcd3ad78d3c121be360);
    		testAddresses.push(0xc396dfc357c849c5e4fbbe1f130eb469675af895);
    		testAddresses.push(0x07efc80760137f58a43e44a9bede15da8053d730);
    		testAddresses.push(0xfe8699b505180f51966e56f118e66544dea311bd);
    		testAddresses.push(0x276ae02aa2710bebc571f3647d64d9b440f998d6);
    		testAddresses.push(0x43882f2be5ccf7ba1cf848e202683385d5fb93bb);
    		testAddresses.push(0x76c780eb591481c086e1a0574b16c4f52e5aa352);
        } else {
            testAddresses.push(0xca35b7d915458ef540ade6068dfe2f44e8fa733c);
            testAddresses.push(0x14723a09acff6d2a60dcdf7aa4aff308fddc160c);
            testAddresses.push(0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db);
            testAddresses.push(0x583031d1113ad414f02576bd6afabfb302140225);
            testAddresses.push(0xdd870fa1b7c4700f2bd7f44238821c26f7392148);
        }
    }

	function assignRoles() internal {
	    require(msg.sender == testAddresses[0]);
	    require(testAddresses.length > 2);
		roles[testAddresses[0]] = Role.OWNER;
		roles[testAddresses[1]] = Role.COMPANY;
		for (uint8 i = 2; i < testAddresses.length; i++) {
		    roles[testAddresses[i]] = Role.RESIDENT;
		}
	}

	function Voting(bool isRpc) {
	    assignTestAddresses(isRpc);
	    assignRoles();
	    state = State.INITIAL;
	}

	function fund() payable {
	    require(roles[msg.sender] == Role.OWNER);
	    require(state == State.INITIAL);
	    state = State.FUNDED;
	    Funded(msg.sender, msg.value);
	}

	// TODO: add deadline
	function startVoting(uint _thresholdPercent) {
	    require(roles[msg.sender] == Role.OWNER);
	    require(_thresholdPercent > 0 && _thresholdPercent <= 100);
	    require(state == State.FUNDED);
	    threshold = (_thresholdPercent * (testAddresses.length - 2) / 100) + 1;
	    state = State.OPEN;
	    VotingOpened(threshold);
	}

	function approve() {
	    require(roles[msg.sender] == Role.RESIDENT);
	    require(state == State.OPEN);
	    approved[msg.sender] = true;
	    numApproved += 1;
	    Approved(msg.sender, numApproved);
	    if (numApproved >= threshold) {
	        state = State.APPROVED;
	        VotingClosedSuccess(numApproved);
	    }
	}

	function withdraw() {
	    require(roles[msg.sender] == Role.COMPANY);
	    require(state == State.APPROVED);
	    msg.sender.transfer(this.balance);
	    state = State.CLOSED;
	    Withdrawn(msg.sender, this.balance);
	}

}

pragma solidity ^0.4.13;

contract Voting {

    enum Role { OWNER, COMPANY, RESIDENT}
    enum State { INITIAL, FUNDED, OPEN, APPROVED, CLOSED }

    mapping (address => Role) roles;
    State public state;

    event Funded(address addr, uint amount);
    event VotingOpened();
    event Approved(address addr);
    event VotingClosedSuccess();
    //event VotingClosedFailure();
    event Withdrawn(address addr, uint amount);

    mapping (address => bool) approved;
    uint numApproved;   // number of residents who approved
    uint threshold;     // required support in persent (1 to 100)

	// Addresses generated from seed.txt
    address[] private testAddresses;

    function assignTestAddresses(bool isRpc) internal {
        if (isRpc) {
    		testAddresses.push(0x0120fe6e3aa2c936e6d2f88062b266c46c408f98);
    		testAddresses.push(0xa8fc189694dc8ba03c027d470b77c09b7d13471e);
    		testAddresses.push(0xdbf73038f3e4a5d27e38004c36dc6ce82165794f);
    		testAddresses.push(0x692b50dc6d0021a73ec50fcd3ad78d3c121be360);
    		testAddresses.push(0xc396dfc357c849c5e4fbbe1f130eb469675af895);
    		testAddresses.push(0x07efc80760137f58a43e44a9bede15da8053d730);
    		testAddresses.push(0xfe8699b505180f51966e56f118e66544dea311bd);
    		testAddresses.push(0x276ae02aa2710bebc571f3647d64d9b440f998d6);
    		testAddresses.push(0x43882f2be5ccf7ba1cf848e202683385d5fb93bb);
    		testAddresses.push(0x76c780eb591481c086e1a0574b16c4f52e5aa352);
        } else {
            testAddresses.push(0xca35b7d915458ef540ade6068dfe2f44e8fa733c);
            testAddresses.push(0x14723a09acff6d2a60dcdf7aa4aff308fddc160c);
            testAddresses.push(0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db);
            testAddresses.push(0x583031d1113ad414f02576bd6afabfb302140225);
            testAddresses.push(0xdd870fa1b7c4700f2bd7f44238821c26f7392148);
        }
    }

	function assignRoles() internal {
	    require(msg.sender == testAddresses[0]);
	    require(testAddresses.length > 2);
		roles[testAddresses[0]] = Role.OWNER;
		roles[testAddresses[1]] = Role.COMPANY;
		for (uint8 i = 2; i < testAddresses.length; i++) {
		    roles[testAddresses[i]] = Role.RESIDENT;
		}
	}

	function Voting(bool isRpc) {
	    assignTestAddresses(isRpc);
	    assignRoles();
	    state = State.INITIAL;
	}

	function fund() payable {
	    require(roles[msg.sender] == Role.OWNER);
	    require(state == State.INITIAL);
	    state = State.FUNDED;
	    Funded(msg.sender, msg.value);
	}

	// TODO: add deadline
	function startVoting(uint _threshold) {
	    require(roles[msg.sender] == Role.OWNER);
	    require(_threshold > 0 && _threshold <= 100);
	    require(state == State.FUNDED);
	    state = State.OPEN;
	    VotingOpened();
	}

	function approve() {
	    require(roles[msg.sender] == Role.RESIDENT);
	    require(state == State.OPEN);
	    approved[msg.sender] = true;
	    numApproved += 1;
	    Approved(msg.sender);
	    if (numApproved > threshold * testAddresses.length) {
	        state = State.APPROVED;
	        VotingClosedSuccess();
	    }
	}

	function withdraw() {
	    require(roles[msg.sender] == Role.COMPANY);
	    require(state == State.APPROVED);
	    msg.sender.transfer(this.balance);
	    state = State.CLOSED;
	    Withdrawn(msg.sender, this.balance);
	}

}


fix typos

fix typos

pragma solidity ^0.5.0;

/**
 * @dev Interface of the ERC777Token standard as defined in the EIP.
 *
 * This contract uses the
 * [ERC1820 registry standard](https://eips.ethereum.org/EIPS/eip-1820) to let
 * token holders and recipients react to token movements by using setting implementers
 * for the associated interfaces in said registry. See `IERC1820Registry` and
 * `ERC1820Implementer`.
 */
interface IERC777 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the smallest part of the token that is not divisible. This
     * means all token operations (creation, movement and destruction) must have
     * amounts that are a multiple of this number.
     *
     * For most token contracts, this value will equal 1.
     */
    function granularity() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by an account (`owner`).
     */
    function balanceOf(address owner) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * If send or receive hooks are registered for the caller and `recipient`,
     * the corresponding functions will be called with `data` and empty
     * `operatorData`. See `IERC777Sender` and `IERC777Recipient`.
     *
     * Emits a `Sent` event.
     *
     * Requirements
     *
     * - the caller must have at least `amount` tokens.
     * - `recipient` cannot be the zero address.
     * - if `recipient` is a contract, it must implement the `tokensReceived`
     * interface.
     */
    function send(address recipient, uint256 amount, bytes calldata data) external;

    /**
     * @dev Destroys `amount` tokens from the caller's account, reducing the
     * total supply.
     *
     * If a send hook is registered for the caller, the corresponding function
     * will be called with `data` and empty `operatorData`. See `IERC777Sender`.
     *
     * Emits a `Burned` event.
     *
     * Requirements
     *
     * - the caller must have at least `amount` tokens.
     */
    function burn(uint256 amount, bytes calldata data) external;

    /**
     * @dev Returns true if an account is an operator of `tokenHolder`.
     * Operators can send and burn tokens on behalf of their owners. All
     * accounts are their own operator.
     *
     * See `operatorSend` and `operatorBurn`.
     */
    function isOperatorFor(address operator, address tokenHolder) external view returns (bool);

    /**
     * @dev Make an account an operator of the caller.
     *
     * See `isOperatorFor`.
     *
     * Emits an `AuthorizedOperator` event.
     *
     * Requirements
     *
     * - `operator` cannot be calling address.
     */
    function authorizeOperator(address operator) external;

    /**
     * @dev Make an account an operator of the caller.
     *
     * See `isOperatorFor` and `defaultOperators`.
     *
     * Emits a `RevokedOperator` event.
     *
     * Requirements
     *
     * - `operator` cannot be calling address.
     */
    function revokeOperator(address operator) external;

    /**
     * @dev Returns the list of default operators. These accounts are operators
     * for all token holders, even if `authorizeOperator` was never called on
     * them.
     *
     * This list is immutable, but individual holders may revoke these via
     * `revokeOperator`, in which case `isOperatorFor` will return false.
     */
    function defaultOperators() external view returns (address[] memory);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must
     * be an operator of `sender`.
     *
     * If send or receive hooks are registered for `sender` and `recipient`,
     * the corresponding functions will be called with `data` and
     * `operatorData`. See `IERC777Sender` and `IERC777Recipient`.
     *
     * Emits a `Sent` event.
     *
     * Requirements
     *
     * - `sender` cannot be the zero address.
     * - `sender` must have at least `amount` tokens.
     * - the caller must be an operator for `sender`.
     * - `recipient` cannot be the zero address.
     * - if `recipient` is a contract, it must implement the `tokensReceived`
     * interface.
     */
    function operatorSend(
        address sender,
        address recipient,
        uint256 amount,
        bytes calldata data,
        bytes calldata operatorData
    ) external;

    /**
     * @dev Destoys `amount` tokens from `account`, reducing the total supply.
     * The caller must be an operator of `account`.
     *
     * If a send hook is registered for `account`, the corresponding function
     * will be called with `data` and `operatorData`. See `IERC777Sender`.
     *
     * Emits a `Burned` event.
     *
     * Requirements
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     * - the caller must be an operator for `account`.
     */
    function operatorBurn(
        address account,
        uint256 amount,
        bytes calldata data,
        bytes calldata operatorData
    ) external;

    event Sent(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256 amount,
        bytes data,
        bytes operatorData
    );

    event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData);

    event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData);

    event AuthorizedOperator(address indexed operator, address indexed tokenHolder);

    event RevokedOperator(address indexed operator, address indexed tokenHolder);
}

pragma solidity ^0.5.0;

/**
 * @dev Interface of the ERC777Token standard as defined in the EIP.
 *
 * This contract uses the
 * [ERC1820 registry standard](https://eips.ethereum.org/EIPS/eip-1820) to let
 * token holders and recipients react to token movements by using setting implementers
 * for the associated interfaces in said registry. See `IERC1820Registry` and
 * `ERC1820Implementer`.
 */
interface IERC777 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the smallest part of the token that is not divisible. This
     * means all token operations (creation, movement and destruction) must have
     * amounts that are a multiple of this number.
     *
     * For most token contracts, this value will equal 1.
     */
    function granularity() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by an account (`owner`).
     */
    function balanceOf(address owner) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * If send or receive hooks are registered for the caller and `recipient`,
     * the corresponding functions will be called with `data` and empty
     * `operatorData`. See `IERC777Sender` and `IERC777Recipient`.
     *
     * Emits a `Sent` event.
     *
     * Requirements
     *
     * - the caller must have at least `amount` tokens.
     * - `recipient` cannot be the zero address.
     * - if `recipient` is a contract, it must implement the `tokensReceived`
     * interface.
     */
    function send(address recipient, uint256 amount, bytes calldata data) external;

    /**
     * @dev Destoys `amount` tokens from the caller's account, reducing the
     * total supply.
     *
     * If a send hook is registered for the caller, the corresponding function
     * will be called with `data` and empty `operatorData`. See `IERC777Sender`.
     *
     * Emits a `Burned` event.
     *
     * Requirements
     *
     * - the caller must have at least `amount` tokens.
     */
    function burn(uint256 amount, bytes calldata data) external;

    /**
     * @dev Returns true if an account is an operator of `tokenHolder`.
     * Operators can send and burn tokens on behalf of their owners. All
     * accounts are their own operator.
     *
     * See `operatorSend` and `operatorBurn`.
     */
    function isOperatorFor(address operator, address tokenHolder) external view returns (bool);

    /**
     * @dev Make an account an operator of the caller.
     *
     * See `isOperatorFor`.
     *
     * Emits an `AuthorizedOperator` event.
     *
     * Requirements
     *
     * - `operator` cannot be calling address.
     */
    function authorizeOperator(address operator) external;

    /**
     * @dev Make an account an operator of the caller.
     *
     * See `isOperatorFor` and `defaultOperators`.
     *
     * Emits a `RevokedOperator` event.
     *
     * Requirements
     *
     * - `operator` cannot be calling address.
     */
    function revokeOperator(address operator) external;

    /**
     * @dev Returns the list of default operators. These accounts are operators
     * for all token holders, even if `authorizeOperator` was never called on
     * them.
     *
     * This list is immutable, but individual holders may revoke these via
     *`revokeOperator`, in which case `isOperatorFor` will return false.
     */
    function defaultOperators() external view returns (address[] memory);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must
     * be an operator of `sender`.
     *
     * If send or receive hooks are registered for `sender` and `recipient`,
     * the corresponding functions will be called with `data` and
     * `operatorData`. See `IERC777Sender` and `IERC777Recipient`.
     *
     * Emits a `Sent` event.
     *
     * Requirements
     *
     * - `sender` cannot be the zero address.
     * - `sender` must have at least `amount` tokens.
     * - the caller must be an operator for `sender`.
     * - `recipient` cannot be the zero address.
     * - if `recipient` is a contract, it must implement the `tokensReceived`
     * interface.
     */
    function operatorSend(
        address sender,
        address recipient,
        uint256 amount,
        bytes calldata data,
        bytes calldata operatorData
    ) external;

    /**
     * @dev Destoys `amount` tokens from `account`, reducing the total supply.
     * The caller must be an operator of `account`.
     *
     * If a send hook is registered for `account`, the corresponding function
     * will be called with `data` and `operatorData`. See `IERC777Sender`.
     *
     * Emits a `Burned` event.
     *
     * Requirements
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     * - the caller must be an operator for `account`.
     */
    function operatorBurn(
        address account,
        uint256 amount,
        bytes calldata data,
        bytes calldata operatorData
    ) external;

    event Sent(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256 amount,
        bytes data,
        bytes operatorData
    );

    event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData);

    event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData);

    event AuthorizedOperator(address indexed operator, address indexed tokenHolder);

    event RevokedOperator(address indexed operator, address indexed tokenHolder);
}


fixed issues with return value for cost

fixed issues with return value for cost

/*
    Copyright 2017 Phillip A. Elsasser

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

pragma solidity ^0.4.18;

import "./oraclizeAPI.sol";
import "../libraries/MathLib.sol";

/// @title QueryTest small contract to allow users to test query structure prior to contract deployment
/// @author Phil Elsasser <phil@marketprotocol.io>
contract OraclizeQueryTest is usingOraclize {
    using MathLib for uint;

    // constants
    uint constant public QUERY_CALLBACK_GAS = 150000;

    // state variables
    mapping(bytes32 => bool) validScheduledQueryIDs;
    mapping(bytes32 => string) queryResults;

    // events
    event QueryCompleted(bytes32 indexed queryIDCompleted);
    event QueryScheduled(bytes32 indexed queryIDScheduled);
    event QueryPrice(uint value);

    function OraclizeQueryTest() public {
        oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); //set proof to match main contracts
    }

    /*
    // PUBLIC METHODS
    */

    /// @notice allows a user to create a query and get a callback asap as to the result to ensure their query
    /// is structured as expected
    /// @param oracleDataSource a data-source such as "URL", "WolframAlpha", "IPFS"
    /// see http://docs.oraclize.it/#ethereum-quick-start-simple-query
    /// @param oracleQuery see http://docs.oraclize.it/#ethereum-quick-start-simple-query for examples
    /// @return unique identifier to allow them to retrieve the query results once completed.
    function testOracleQuery(string oracleDataSource, string oracleQuery) external payable returns (bytes32) {
        uint cost = oraclize_getPrice(oracleDataSource, QUERY_CALLBACK_GAS);
        require(msg.value >= cost); // user must pay enough to cover query and callback
        bytes32 queryId = oraclize_query(
            oracleDataSource,
            oracleQuery,
            QUERY_CALLBACK_GAS
        );
        validScheduledQueryIDs[queryId] = true;
        QueryScheduled(queryId);
        return queryId;
    }

    /// @notice allows a user to retrieve results from their test query.
    /// @param queryID unique identifier for the query.
    /// @return results (if any) from the query
    function getQueryResults(bytes32 queryID) external view returns (string) {
        return queryResults[queryID];
    }

    /// @notice allows a user to retrieve current pricing from oraclize API
    /// @param oracleDataSource a data-source such as "URL", "WolframAlpha", "IPFS"
    /// see http://docs.oraclize.it/#ethereum-quick-start-simple-query
    /// @return cost in wei of query
    function getQueryCost(string oracleDataSource) external returns (uint) {
        return oraclize_getPrice(oracleDataSource, QUERY_CALLBACK_GAS);
    }

    /// @notice only public for callbacks from oraclize, do not call
    /// @param queryID of the returning query, this should match our own internal mapping
    /// @param result query to be processed
    /// @param proof result proof
    function __callback(bytes32 queryID, string result, bytes proof) public {
        require(msg.sender == oraclize_cbAddress());
        require(validScheduledQueryIDs[queryID]);
        delete validScheduledQueryIDs[queryID];
        queryResults[queryID] = result; //save result
        QueryCompleted(queryID);    // fire event so user can retrieve the result.
    }
}

/*
    Copyright 2017 Phillip A. Elsasser

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

pragma solidity ^0.4.18;

import "./oraclizeAPI.sol";
import "../libraries/MathLib.sol";

/// @title QueryTest small contract to allow users to test query structure prior to contract deployment
/// @author Phil Elsasser <phil@marketprotocol.io>
contract OraclizeQueryTest is usingOraclize {
    using MathLib for uint;

    // constants
    uint constant public QUERY_CALLBACK_GAS = 150000;

    // state variables
    mapping(bytes32 => bool) validScheduledQueryIDs;
    mapping(bytes32 => string) queryResults;

    // events
    event QueryCompleted(bytes32 indexed queryIDCompleted);
    event QueryScheduled(bytes32 indexed queryIDScheduled);

    function OraclizeQueryTest() public {
        oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); //set proof to match main contracts
    }

    /*
    // PUBLIC METHODS
    */

    /// @notice allows a user to create a query and get a callback asap as to the result to ensure their query
    /// is structured as expected
    /// @param oracleDataSource a data-source such as "URL", "WolframAlpha", "IPFS"
    /// see http://docs.oraclize.it/#ethereum-quick-start-simple-query
    /// @param oracleQuery see http://docs.oraclize.it/#ethereum-quick-start-simple-query for examples
    /// @return unique identifier to allow them to retrieve the query results once completed.
    function testOracleQuery(string oracleDataSource, string oracleQuery) external payable returns (bytes32) {
        uint cost = oraclize_getPrice(oracleDataSource, QUERY_CALLBACK_GAS);
        require(msg.value >= cost); // user must pay enough to cover query and callback
        bytes32 queryId = oraclize_query(
            oracleDataSource,
            oracleQuery,
            QUERY_CALLBACK_GAS
        );
        validScheduledQueryIDs[queryId] = true;
        QueryScheduled(queryId);
        return queryId;
    }

    /// @notice allows a user to retrieve results from their test query.
    /// @param queryID unique identifier for the query.
    /// @return results (if any) from the query
    function getQueryResults(bytes32 queryID) external view returns (string) {
        return queryResults[queryID];
    }

    /// @notice allows a user to retrieve current pricing from oraclize API
    /// @param oracleDataSource a data-source such as "URL", "WolframAlpha", "IPFS"
    /// see http://docs.oraclize.it/#ethereum-quick-start-simple-query
    /// @return cost in wei of query
    function getQueryCost(string oracleDataSource) external returns (uint cost) {
        oraclize_getPrice(oracleDataSource, QUERY_CALLBACK_GAS);
    }

    /// @notice only public for callbacks from oraclize, do not call
    /// @param queryID of the returning query, this should match our own internal mapping
    /// @param result query to be processed
    /// @param proof result proof
    function __callback(bytes32 queryID, string result, bytes proof) public {
        require(msg.sender == oraclize_cbAddress());
        require(validScheduledQueryIDs[queryID]);
        delete validScheduledQueryIDs[queryID];
        queryResults[queryID] = result; //save result
        QueryCompleted(queryID);    // fire event so user can retrieve the result.
    }
}


Now setting the finalized flag before doing finalization to prevent possbile reentrancy issues. (#1447)

pragma solidity ^0.4.24;

import "../../math/SafeMath.sol";
import "../validation/TimedCrowdsale.sol";

/**
 * @title FinalizableCrowdsale
 * @dev Extension of Crowdsale with a one-off finalization action, where one
 * can do extra work after finishing.
 */
contract FinalizableCrowdsale is TimedCrowdsale {
  using SafeMath for uint256;

  bool private _finalized;

  event CrowdsaleFinalized();

  constructor() internal {
    _finalized = false;
  }

  /**
   * @return true if the crowdsale is finalized, false otherwise.
   */
  function finalized() public view returns (bool) {
    return _finalized;
  }

  /**
   * @dev Must be called after crowdsale ends, to do some extra finalization
   * work. Calls the contract's finalization function.
   */
  function finalize() public {
    require(!_finalized);
    require(hasClosed());

    _finalized = true;

    _finalization();
    emit CrowdsaleFinalized();
  }

  /**
   * @dev Can be overridden to add finalization logic. The overriding function
   * should call super._finalization() to ensure the chain of finalization is
   * executed entirely.
   */
  function _finalization() internal {
  }
}

pragma solidity ^0.4.24;

import "../../math/SafeMath.sol";
import "../validation/TimedCrowdsale.sol";

/**
 * @title FinalizableCrowdsale
 * @dev Extension of Crowdsale with a one-off finalization action, where one
 * can do extra work after finishing.
 */
contract FinalizableCrowdsale is TimedCrowdsale {
  using SafeMath for uint256;

  bool private _finalized;

  event CrowdsaleFinalized();

  constructor() internal {
    _finalized = false;
  }

  /**
   * @return true if the crowdsale is finalized, false otherwise.
   */
  function finalized() public view returns (bool) {
    return _finalized;
  }

  /**
   * @dev Must be called after crowdsale ends, to do some extra finalization
   * work. Calls the contract's finalization function.
   */
  function finalize() public {
    require(!_finalized);
    require(hasClosed());

    _finalization();
    emit CrowdsaleFinalized();

    _finalized = true;
  }

  /**
   * @dev Can be overridden to add finalization logic. The overriding function
   * should call super._finalization() to ensure the chain of finalization is
   * executed entirely.
   */
  function _finalization() internal {
  }

}


Fix doxygen.

Fix doxygen.

pragma solidity ^0.5.9;

import "./item_store_interface.sol";
import "./item_store_constants.sol";
import "./item_store_registry.sol";

/**
 * @title ItemStoreIpfsSha256
 * @author Jonathan Brown <jbrown@mix-blockchain.org>
 * @dev ItemStore implementation where each item revision is a SHA256 IPFS hash.
 */
contract ItemStoreIpfsSha256 is ItemStoreInterface, ItemStoreConstants {

    /**
     * @dev Single slot structure of item state.
     */
    struct ItemState {
        bool inUse;             // Has this itemId ever been used.
        byte flags;             // Packed item settings.
        uint32 revisionCount;   // Number of revisions including revision 0.
        uint32 timestamp;       // Timestamp of revision 0.
        address owner;          // Who owns this item.
    }

    /**
     * @dev Mapping of itemId to item state.
     */
    mapping (bytes32 => ItemState) itemState;

    /**
     * @dev Mapping of itemId to mapping of packed slots of eight 32-bit timestamps.
     */
    mapping (bytes32 => mapping (uint => bytes32)) itemPackedTimestamps;

    /**
     * @dev Mapping of itemId to mapping of revision number to IPFS hash.
     */
    mapping (bytes32 => mapping (uint => bytes32)) itemRevisionIpfsHashes;

    /**
     * @dev Mapping of itemId to mapping of transfer recipient addresses to enabled.
     */
    mapping (bytes32 => mapping (address => bool)) itemTransferEnabled;

    /**
     * @dev ItemStoreRegistry contract.
     */
    ItemStoreRegistry public itemStoreRegistry;

    /**
     * @dev Id of this instance of ItemStore. Stored as bytes32 instead of bytes8 to reduce gas usage.
     */
    bytes32 contractId;

    /**
     * @dev Revert if the itemId is not in use.
     * @param itemId itemId of the item.
     */
    modifier inUse(bytes32 itemId) {
        require (itemState[itemId].inUse);
        _;
    }

    /**
     * @dev Revert if the owner of the item is not the message sender.
     * @param itemId itemId of the item.
     */
    modifier isOwner(bytes32 itemId) {
        require (itemState[itemId].owner == msg.sender);
        _;
    }

    /**
     * @dev Revert if the item is not updatable.
     * @param itemId itemId of the item.
     */
    modifier isUpdatable(bytes32 itemId) {
        require (itemState[itemId].flags & UPDATABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not enforcing revisions.
     * @param itemId itemId of the item.
     */
    modifier isNotEnforceRevisions(bytes32 itemId) {
        require (itemState[itemId].flags & ENFORCE_REVISIONS == 0);
        _;
    }

    /**
     * @dev Revert if the item is not retractable.
     * @param itemId itemId of the item.
     */
    modifier isRetractable(bytes32 itemId) {
        require (itemState[itemId].flags & RETRACTABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not transferable.
     * @param itemId itemId of the item.
     */
    modifier isTransferable(bytes32 itemId) {
        require (itemState[itemId].flags & TRANSFERABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not transferable to a specific user.
     * @param itemId itemId of the item.
     * @param recipient Address of the user.
     */
    modifier isTransferEnabled(bytes32 itemId, address recipient) {
        require (itemTransferEnabled[itemId][recipient]);
        _;
    }

    /**
     * @dev Revert if the item only has one revision.
     * @param itemId itemId of the item.
     */
    modifier hasAdditionalRevisions(bytes32 itemId) {
        require (itemState[itemId].revisionCount > 1);
        _;
    }

    /**
     * @dev Revert if a specific item revision does not exist.
     * @param itemId itemId of the item.
     * @param revisionId Id of the revision.
     */
    modifier revisionExists(bytes32 itemId, uint revisionId) {
        require (revisionId < itemState[itemId].revisionCount);
        _;
    }

    /**
     * @param _itemStoreRegistry Address of the ItemStoreRegistry contract.
     */
    constructor(ItemStoreRegistry _itemStoreRegistry) public {
        // Store the address of the ItemStoreRegistry contract.
        itemStoreRegistry = _itemStoreRegistry;
        // Register this contract.
        contractId = itemStoreRegistry.register();
    }

    /**
     * @dev Generates an itemId from owner and nonce and checks that it is unused.
     * @param owner Address that will own the item.
     * @param nonce Nonce that this owner has never used before.
     * @return itemId itemId of the item with this owner and nonce.
     */
    function getNewItemId(address owner, bytes32 nonce) public view returns (bytes32 itemId) {
        // Combine contractId with hash of sender and nonce.
        itemId = (keccak256(abi.encodePacked(address(this), owner, nonce)) & ITEM_ID_MASK) | contractId;
        // Make sure this itemId has not been used before.
        require (!itemState[itemId].inUse);
    }

    /**
     * @dev Creates an item with no parents. It is guaranteed that different users will never receive the same itemId, even before consensus has been reached. This prevents itemId sniping.
     * @param flagsNonce Nonce that this address has never passed before; first byte is creation flags.
     * @param ipfsHash Hash of the IPFS object where revision 0 is stored.
     * @return itemId itemId of the new item.
     */
    function create(bytes32 flagsNonce, bytes32 ipfsHash) external returns (bytes32 itemId) {
        // Determine the itemId.
        itemId = getNewItemId(msg.sender, flagsNonce);
        // Extract the flags.
        byte flags = byte(flagsNonce);
        // Determine the owner.
        address owner = (flags & DISOWN == 0) ? msg.sender : address(0);
        // Store item state.
        ItemState storage state = itemState[itemId];
        state.inUse = true;
        state.flags = flags;
        state.revisionCount = 1;
        state.timestamp = uint32(block.timestamp);
        state.owner = owner;
        // Store the IPFS hash.
        itemRevisionIpfsHashes[itemId][0] = ipfsHash;
        // Log item creation.
        emit Create(itemId, owner, flags);
        // Log the first revision.
        emit PublishRevision(itemId, owner, 0);
    }

    /**
     * @dev Store an item revision timestamp in a packed slot.
     * @param itemId itemId of the item.
     * @param offset The offset of the timestamp that should be stored.
     */
    function _setPackedTimestamp(bytes32 itemId, uint offset) internal {
        // Get the slot.
        bytes32 slot = itemPackedTimestamps[itemId][offset / 8];
        // Calculate the shift.
        uint shift = (offset % 8) * 32;
        // Wipe the previous timestamp.
        slot &= ~(bytes32(uint256(uint32(-1))) << shift);
        // Insert the current timestamp.
        slot |= bytes32(uint256(uint32(block.timestamp))) << shift;
        // Store the slot.
        itemPackedTimestamps[itemId][offset / 8] = slot;
    }

    /**
     * @dev Create a new item revision.
     * @param itemId itemId of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     * @return revisionId The revisionId of the new revision.
     */
    function createNewRevision(bytes32 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) returns (uint revisionId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Increment the number of revisions.
        revisionId = state.revisionCount++;
        // Store the IPFS hash.
        itemRevisionIpfsHashes[itemId][revisionId] = ipfsHash;
        // Store the timestamp.
        _setPackedTimestamp(itemId, revisionId - 1);
        // Log the revision.
        emit PublishRevision(itemId, state.owner, revisionId);
    }

    /**
     * @dev Update an item's latest revision.
     * @param itemId itemId of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     */
    function updateLatestRevision(bytes32 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Determine the revisionId.
        uint revisionId = state.revisionCount - 1;
        // Update the IPFS hash.
        itemRevisionIpfsHashes[itemId][revisionId] = ipfsHash;
        // Update the timestamp.
        if (revisionId == 0) {
            state.timestamp = uint32(block.timestamp);
        }
        else {
            _setPackedTimestamp(itemId, revisionId - 1);
        }
        // Log the revision.
        emit PublishRevision(itemId, state.owner, revisionId);
    }

    /**
     * @dev Retract an item's latest revision. Revision 0 cannot be retracted.
     * @param itemId itemId of the item.
     */
    function retractLatestRevision(bytes32 itemId) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) hasAdditionalRevisions(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Decrement the number of revisions.
        uint revisionId = --state.revisionCount;
        // Delete the IPFS hash.
        delete itemRevisionIpfsHashes[itemId][revisionId];
        // Delete the packed timestamp slot if it is no longer required.
        if (revisionId % 8 == 1) {
            delete itemPackedTimestamps[itemId][revisionId / 8];
        }
        // Log the revision retraction.
        emit RetractRevision(itemId, state.owner, revisionId);
    }

    /**
     * @dev Delete all of an item's packed revision timestamps.
     * @param itemId itemId of the item.
     */
    function _deleteAllPackedRevisionTimestamps(bytes32 itemId) internal {
        // Determine how many slots should be deleted.
        // Timestamp of the first revision is stored in the item state, so the first slot only needs to be deleted if there are at least 2 revisions.
        uint slotCount = (itemState[itemId].revisionCount + 6) / 8;
        // Delete the slots.
        for (uint i = 0; i < slotCount; i++) {
            delete itemPackedTimestamps[itemId][i];
        }
    }

    /**
     * @dev Delete all an item's revisions and replace it with a new item.
     * @param itemId itemId of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     */
    function restart(bytes32 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) {
        // Get item state and IPFS hashes.
        ItemState storage state = itemState[itemId];
        mapping (uint => bytes32) storage ipfsHashes = itemRevisionIpfsHashes[itemId];
        // Log and delete all the IPFS hashes except the first one.
        for (uint revisionId = state.revisionCount - 1; revisionId > 0; revisionId--) {
            delete ipfsHashes[revisionId];
            emit RetractRevision(itemId, state.owner, revisionId);
        }
        // Delete all the packed revision timestamps.
        _deleteAllPackedRevisionTimestamps(itemId);
        // Update the item state.
        state.revisionCount = 1;
        state.timestamp = uint32(block.timestamp);
        // Update the first IPFS hash.
        ipfsHashes[0] = ipfsHash;
        // Log the revision.
        emit PublishRevision(itemId, state.owner, 0);
    }

    /**
     * @dev Retract an item.
     * @param itemId itemId of the item. This itemId can never be used again.
     */
    function retract(bytes32 itemId) external isOwner(itemId) isRetractable(itemId) {
        // Get item state and IPFS hashes.
        ItemState storage state = itemState[itemId];
        mapping (uint => bytes32) storage ipfsHashes = itemRevisionIpfsHashes[itemId];
        // Log and delete all the IPFS hashes.
        for (uint revisionId = state.revisionCount - 1; revisionId < state.revisionCount; revisionId--) {
            delete ipfsHashes[revisionId];
            emit RetractRevision(itemId, state.owner, revisionId);
        }
        // Delete all the packed revision timestamps.
        _deleteAllPackedRevisionTimestamps(itemId);
        // Mark this item as retracted.
        state.inUse = true;
        state.flags = 0;
        state.revisionCount = 0;
        state.timestamp = 0;
        state.owner = address(0);
        // Log the item retraction.
        emit Retract(itemId, state.owner);
    }

    /**
     * @dev Enable transfer of an item to the current user.
     * @param itemId itemId of the item.
     */
    function transferEnable(bytes32 itemId) external isTransferable(itemId) {
        // Record in state that the current user will accept this item.
        itemTransferEnabled[itemId][msg.sender] = true;
        // Log that transfer to this user is enabled.
        emit EnableTransfer(itemId, itemState[itemId].owner, msg.sender);
    }

    /**
     * @dev Disable transfer of an item to the current user.
     * @param itemId itemId of the item.
     */
    function transferDisable(bytes32 itemId) external isTransferEnabled(itemId, msg.sender) {
        // Record in state that the current user will not accept this item.
        itemTransferEnabled[itemId][msg.sender] = false;
        // Log that transfer to this user is disabled.
        emit DisableTransfer(itemId, itemState[itemId].owner, msg.sender);
    }

    /**
     * @dev Transfer an item to a new user.
     * @param itemId itemId of the item.
     * @param recipient Address of the user to transfer to item to.
     */
    function transfer(bytes32 itemId, address recipient) external isOwner(itemId) isTransferable(itemId) isTransferEnabled(itemId, recipient) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Log the transfer.
        emit Transfer(itemId, state.owner, recipient);
        // Update ownership of the item.
        state.owner = recipient;
        // Disable this transfer in future and free up the slot.
        itemTransferEnabled[itemId][recipient] = false;
    }

    /**
     * @dev Disown an item.
     * @param itemId itemId of the item.
     */
    function disown(bytes32 itemId) external isOwner(itemId) isTransferable(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Log that the item has been disowned.
        emit Disown(itemId, state.owner);
        // Remove the owner from the item's state.
        delete state.owner;
    }

    /**
     * @dev Set an item as not updatable.
     * @param itemId itemId of the item.
     */
    function setNotUpdatable(bytes32 itemId) external isOwner(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Record in state that the item is not updatable.
        state.flags &= ~UPDATABLE;
        // Log that the item is not updatable.
        emit SetNotUpdatable(itemId, state.owner);
    }

    /**
     * @dev Set an item to enforce revisions.
     * @param itemId itemId of the item.
     */
    function setEnforceRevisions(bytes32 itemId) external isOwner(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Record in state that all changes to this item must be new revisions.
        state.flags |= ENFORCE_REVISIONS;
        // Log that the item now enforces new revisions.
        emit SetEnforceRevisions(itemId, state.owner);
    }

    /**
     * @dev Set an item to not be retractable.
     * @param itemId itemId of the item.
     */
    function setNotRetractable(bytes32 itemId) external isOwner(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Record in state that the item is not retractable.
        state.flags &= ~RETRACTABLE;
        // Log that the item is not retractable.
        emit SetNotRetractable(itemId, state.owner);
    }

    /**
     * @dev Set an item to not be transferable.
     * @param itemId itemId of the item.
     */
    function setNotTransferable(bytes32 itemId) external isOwner(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Record in state that the item is not transferable.
        state.flags &= ~TRANSFERABLE;
        // Log that the item is not transferable.
        emit SetNotTransferable(itemId, state.owner);
    }

    /**
     * @dev Get the ABI version for this ItemStore contract.
     * @return ABI version.
     */
    function getAbiVersion() external view returns (uint) {
        return ABI_VERSION;
    }

    /**
     * @dev Get the id for this ItemStore contract.
     * @return Id of the contract.
     */
    function getContractId() external view returns (bytes8) {
        return bytes8(contractId << 192);
    }

    /**
     * @dev Check if an itemId is in use.
     * @param itemId itemId of the item.
     * @return True if the itemId is in use.
     */
    function getInUse(bytes32 itemId) external view returns (bool) {
        return itemState[itemId].inUse;
    }

    /**
     * @dev Get the IPFS hashes for all of an item's revisions.
     * @param itemId itemId of the item.
     * @return ipfsHashes Revision IPFS hashes.
     */
    function _getAllRevisionIpfsHashes(bytes32 itemId) internal view returns (bytes32[] memory ipfsHashes) {
        uint revisionCount = itemState[itemId].revisionCount;
        ipfsHashes = new bytes32[](revisionCount);
        for (uint revisionId = 0; revisionId < revisionCount; revisionId++) {
            ipfsHashes[revisionId] = itemRevisionIpfsHashes[itemId][revisionId];
        }
    }

    /**
     * @dev Get the timestamp for a specific item revision.
     * @param itemId itemId of the item.
     * @param revisionId Id of the revision.
     * @return timestamp Timestamp of the specified revision or 0 for unconfirmed.
     */
    function _getRevisionTimestamp(bytes32 itemId, uint revisionId) internal view returns (uint timestamp) {
        if (revisionId == 0) {
            timestamp = itemState[itemId].timestamp;
        }
        else {
            uint offset = revisionId - 1;
            timestamp = uint32(uint256(itemPackedTimestamps[itemId][offset / 8] >> ((offset % 8) * 32)));
        }
        // Check if the revision has been confirmed yet.
        if (timestamp == block.timestamp) {
            timestamp = 0;
        }
    }

    /**
     * @dev Get the timestamps for all of an item's revisions.
     * @param itemId itemId of the item.
     * @return timestamps Revision timestamps.
     */
    function _getAllRevisionTimestamps(bytes32 itemId) internal view returns (uint[] memory timestamps) {
        uint count = itemState[itemId].revisionCount;
        timestamps = new uint[](count);
        for (uint revisionId = 0; revisionId < count; revisionId++) {
            timestamps[revisionId] = _getRevisionTimestamp(itemId, revisionId);
        }
    }

    /**
     * @dev Get an item.
     * @param itemId itemId of the item.
     * @return flags Packed item settings.
     * @return owner Owner of the item.
     * @return revisionCount How many revisions the item has.
     * @return timestamps Timestamp of each revision.
     * @return ipfsHashes IPFS hash of each revision.
     */
    function getItem(bytes32 itemId) external view inUse(itemId) returns (byte flags, address owner, uint revisionCount, uint[] memory timestamps, bytes32[] memory ipfsHashes) {
        ItemState storage state = itemState[itemId];
        flags = state.flags;
        owner = state.owner;
        revisionCount = state.revisionCount;
        ipfsHashes = _getAllRevisionIpfsHashes(itemId);
        timestamps = _getAllRevisionTimestamps(itemId);
    }

    /**
     * @dev Get an item's flags.
     * @param itemId itemId of the item.
     * @return Packed item settings.
     */
    function getFlags(bytes32 itemId) external view inUse(itemId) returns (byte) {
        return itemState[itemId].flags;
    }

    /**
     * @dev Determine if an item is updatable.
     * @param itemId itemId of the item.
     * @return True if the item is updatable.
     */
    function getUpdatable(bytes32 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & UPDATABLE != 0;
    }

    /**
     * @dev Determine if an item enforces revisions.
     * @param itemId itemId of the item.
     * @return True if the item enforces revisions.
     */
    function getEnforceRevisions(bytes32 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & ENFORCE_REVISIONS != 0;
    }

    /**
     * @dev Determine if an item is retractable.
     * @param itemId itemId of the item.
     * @return True if the item is item retractable.
     */
    function getRetractable(bytes32 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & RETRACTABLE != 0;
    }

    /**
     * @dev Determine if an item is transferable.
     * @param itemId itemId of the item.
     * @return True if the item is transferable.
     */
    function getTransferable(bytes32 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & TRANSFERABLE != 0;
    }

    /**
     * @dev Get the owner of an item.
     * @param itemId itemId of the item.
     * @return Owner of the item.
     */
    function getOwner(bytes32 itemId) external view inUse(itemId) returns (address) {
        return itemState[itemId].owner;
    }

    /**
     * @dev Get the number of revisions an item has.
     * @param itemId itemId of the item.
     * @return How many revisions the item has.
     */
    function getRevisionCount(bytes32 itemId) external view inUse(itemId) returns (uint) {
        return itemState[itemId].revisionCount;
    }

    /**
     * @dev Get the timestamp for a specific item revision.
     * @param itemId itemId of the item.
     * @param revisionId Id of the revision.
     * @return Timestamp of the specified revision.
     */
    function getRevisionTimestamp(bytes32 itemId, uint revisionId) external view revisionExists(itemId, revisionId) returns (uint) {
        return _getRevisionTimestamp(itemId, revisionId);
    }

    /**
     * @dev Get the timestamps for all of an item's revisions.
     * @param itemId itemId of the item.
     * @return Timestamps of all revisions of the item.
     */
    function getAllRevisionTimestamps(bytes32 itemId) external view inUse(itemId) returns (uint[] memory) {
        return _getAllRevisionTimestamps(itemId);
    }

    /**
     * @dev Get the IPFS hash for a specific item revision.
     * @param itemId itemId of the item.
     * @param revisionId Id of the revision.
     * @return IPFS hash of the specified revision.
     */
    function getRevisionIpfsHash(bytes32 itemId, uint revisionId) external view revisionExists(itemId, revisionId) returns (bytes32) {
        return itemRevisionIpfsHashes[itemId][revisionId];
    }

    /**
     * @dev Get the IPFS hashes for all of an item's revisions.
     * @param itemId itemId of the item.
     * @return IPFS hashes of all revisions of the item.
     */
    function getAllRevisionIpfsHashes(bytes32 itemId) external view inUse(itemId) returns (bytes32[] memory) {
        return _getAllRevisionIpfsHashes(itemId);
    }

}

pragma solidity ^0.5.9;

import "./item_store_interface.sol";
import "./item_store_constants.sol";
import "./item_store_registry.sol";

/**
 * @title ItemStoreIpfsSha256
 * @author Jonathan Brown <jbrown@mix-blockchain.org>
 * @dev ItemStore implementation where each item revision is a SHA256 IPFS hash.
 */
contract ItemStoreIpfsSha256 is ItemStoreInterface, ItemStoreConstants {

    /**
     * @dev Single slot structure of item state.
     */
    struct ItemState {
        bool inUse;             // Has this itemId ever been used.
        byte flags;             // Packed item settings.
        uint32 revisionCount;   // Number of revisions including revision 0.
        uint32 timestamp;       // Timestamp of revision 0.
        address owner;          // Who owns this item.
    }

    /**
     * @dev Mapping of itemId to item state.
     */
    mapping (bytes32 => ItemState) itemState;

    /**
     * @dev Mapping of itemId to mapping of packed slots of eight 32-bit timestamps.
     */
    mapping (bytes32 => mapping (uint => bytes32)) itemPackedTimestamps;

    /**
     * @dev Mapping of itemId to mapping of revision number to IPFS hash.
     */
    mapping (bytes32 => mapping (uint => bytes32)) itemRevisionIpfsHashes;

    /**
     * @dev Mapping of itemId to mapping of transfer recipient addresses to enabled.
     */
    mapping (bytes32 => mapping (address => bool)) itemTransferEnabled;

    /**
     * @dev ItemStoreRegistry contract.
     */
    ItemStoreRegistry public itemStoreRegistry;

    /**
     * @dev Id of this instance of ItemStore. Stored as bytes32 instead of bytes8 to reduce gas usage.
     */
    bytes32 contractId;

    /**
     * @dev Revert if the itemId is not in use.
     * @param itemId itemId of the item.
     */
    modifier inUse(bytes32 itemId) {
        require (itemState[itemId].inUse);
        _;
    }

    /**
     * @dev Revert if the owner of the item is not the message sender.
     * @param itemId itemId of the item.
     */
    modifier isOwner(bytes32 itemId) {
        require (itemState[itemId].owner == msg.sender);
        _;
    }

    /**
     * @dev Revert if the item is not updatable.
     * @param itemId itemId of the item.
     */
    modifier isUpdatable(bytes32 itemId) {
        require (itemState[itemId].flags & UPDATABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not enforcing revisions.
     * @param itemId itemId of the item.
     */
    modifier isNotEnforceRevisions(bytes32 itemId) {
        require (itemState[itemId].flags & ENFORCE_REVISIONS == 0);
        _;
    }

    /**
     * @dev Revert if the item is not retractable.
     * @param itemId itemId of the item.
     */
    modifier isRetractable(bytes32 itemId) {
        require (itemState[itemId].flags & RETRACTABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not transferable.
     * @param itemId itemId of the item.
     */
    modifier isTransferable(bytes32 itemId) {
        require (itemState[itemId].flags & TRANSFERABLE != 0);
        _;
    }

    /**
     * @dev Revert if the item is not transferable to a specific user.
     * @param itemId itemId of the item.
     * @param recipient Address of the user.
     */
    modifier isTransferEnabled(bytes32 itemId, address recipient) {
        require (itemTransferEnabled[itemId][recipient]);
        _;
    }

    /**
     * @dev Revert if the item only has one revision.
     * @param itemId itemId of the item.
     */
    modifier hasAdditionalRevisions(bytes32 itemId) {
        require (itemState[itemId].revisionCount > 1);
        _;
    }

    /**
     * @dev Revert if a specific item revision does not exist.
     * @param itemId itemId of the item.
     * @param revisionId Id of the revision.
     */
    modifier revisionExists(bytes32 itemId, uint revisionId) {
        require (revisionId < itemState[itemId].revisionCount);
        _;
    }

    /**
     * @param _itemStoreRegistry Address of the ItemStoreRegistry contract.
     */
    constructor(ItemStoreRegistry _itemStoreRegistry) public {
        // Store the address of the ItemStoreRegistry contract.
        itemStoreRegistry = _itemStoreRegistry;
        // Register this contract.
        contractId = itemStoreRegistry.register();
    }

    /**
     * @dev Generates an itemId from owner and nonce and checks that it is unused.
     * @param owner Address that will own the item.
     * @param nonce Nonce that this owner has never used before.
     * @return itemId itemId of the item with this owner and nonce.
     */
    function getNewItemId(address owner, bytes32 nonce) public view returns (bytes32 itemId) {
        // Combine contractId with hash of sender and nonce.
        itemId = (keccak256(abi.encodePacked(address(this), owner, nonce)) & ITEM_ID_MASK) | contractId;
        // Make sure this itemId has not been used before.
        require (!itemState[itemId].inUse);
    }

    /**
     * @dev Creates an item with no parents. It is guaranteed that different users will never receive the same itemId, even before consensus has been reached. This prevents itemId sniping.
     * @param flagsNonce Nonce that this address has never passed before; first byte is creation flags.
     * @param ipfsHash Hash of the IPFS object where revision 0 is stored.
     * @return itemId itemId of the new item.
     */
    function create(bytes32 flagsNonce, bytes32 ipfsHash) external returns (bytes32 itemId) {
        // Determine the itemId.
        itemId = getNewItemId(msg.sender, flagsNonce);
        // Extract the flags.
        byte flags = byte(flagsNonce);
        // Determine the owner.
        address owner = (flags & DISOWN == 0) ? msg.sender : address(0);
        // Store item state.
        ItemState storage state = itemState[itemId];
        state.inUse = true;
        state.flags = flags;
        state.revisionCount = 1;
        state.timestamp = uint32(block.timestamp);
        state.owner = owner;
        // Store the IPFS hash.
        itemRevisionIpfsHashes[itemId][0] = ipfsHash;
        // Log item creation.
        emit Create(itemId, owner, flags);
        // Log the first revision.
        emit PublishRevision(itemId, owner, 0);
    }

    /**
     * @dev Store an item revision timestamp in a packed slot.
     * @param itemId itemId of the item.
     * @param offset The offset of the timestamp that should be stored.
     */
    function _setPackedTimestamp(bytes32 itemId, uint offset) internal {
        // Get the slot.
        bytes32 slot = itemPackedTimestamps[itemId][offset / 8];
        // Calculate the shift.
        uint shift = (offset % 8) * 32;
        // Wipe the previous timestamp.
        slot &= ~(bytes32(uint256(uint32(-1))) << shift);
        // Insert the current timestamp.
        slot |= bytes32(uint256(uint32(block.timestamp))) << shift;
        // Store the slot.
        itemPackedTimestamps[itemId][offset / 8] = slot;
    }

    /**
     * @dev Create a new item revision.
     * @param itemId itemId of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     * @return revisionId The revisionId of the new revision.
     */
    function createNewRevision(bytes32 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) returns (uint revisionId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Increment the number of revisions.
        revisionId = state.revisionCount++;
        // Store the IPFS hash.
        itemRevisionIpfsHashes[itemId][revisionId] = ipfsHash;
        // Store the timestamp.
        _setPackedTimestamp(itemId, revisionId - 1);
        // Log the revision.
        emit PublishRevision(itemId, state.owner, revisionId);
    }

    /**
     * @dev Update an item's latest revision.
     * @param itemId itemId of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     */
    function updateLatestRevision(bytes32 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Determine the revisionId.
        uint revisionId = state.revisionCount - 1;
        // Update the IPFS hash.
        itemRevisionIpfsHashes[itemId][revisionId] = ipfsHash;
        // Update the timestamp.
        if (revisionId == 0) {
            state.timestamp = uint32(block.timestamp);
        }
        else {
            _setPackedTimestamp(itemId, revisionId - 1);
        }
        // Log the revision.
        emit PublishRevision(itemId, state.owner, revisionId);
    }

    /**
     * @dev Retract an item's latest revision. Revision 0 cannot be retracted.
     * @param itemId itemId of the item.
     */
    function retractLatestRevision(bytes32 itemId) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) hasAdditionalRevisions(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Decrement the number of revisions.
        uint revisionId = --state.revisionCount;
        // Delete the IPFS hash.
        delete itemRevisionIpfsHashes[itemId][revisionId];
        // Delete the packed timestamp slot if it is no longer required.
        if (revisionId % 8 == 1) {
            delete itemPackedTimestamps[itemId][revisionId / 8];
        }
        // Log the revision retraction.
        emit RetractRevision(itemId, state.owner, revisionId);
    }

    /**
     * @dev Delete all of an item's packed revision timestamps.
     * @param itemId itemId of the item.
     */
    function _deleteAllPackedRevisionTimestamps(bytes32 itemId) internal {
        // Determine how many slots should be deleted.
        // Timestamp of the first revision is stored in the item state, so the first slot only needs to be deleted if there are at least 2 revisions.
        uint slotCount = (itemState[itemId].revisionCount + 6) / 8;
        // Delete the slots.
        for (uint i = 0; i < slotCount; i++) {
            delete itemPackedTimestamps[itemId][i];
        }
    }

    /**
     * @dev Delete all an item's revisions and replace it with a new item.
     * @param itemId itemId of the item.
     * @param ipfsHash Hash of the IPFS object where the item revision is stored.
     */
    function restart(bytes32 itemId, bytes32 ipfsHash) external isOwner(itemId) isUpdatable(itemId) isNotEnforceRevisions(itemId) {
        // Get item state and IPFS hashes.
        ItemState storage state = itemState[itemId];
        mapping (uint => bytes32) storage ipfsHashes = itemRevisionIpfsHashes[itemId];
        // Log and delete all the IPFS hashes except the first one.
        for (uint revisionId = state.revisionCount - 1; revisionId > 0; revisionId--) {
            delete ipfsHashes[revisionId];
            emit RetractRevision(itemId, state.owner, revisionId);
        }
        // Delete all the packed revision timestamps.
        _deleteAllPackedRevisionTimestamps(itemId);
        // Update the item state.
        state.revisionCount = 1;
        state.timestamp = uint32(block.timestamp);
        // Update the first IPFS hash.
        ipfsHashes[0] = ipfsHash;
        // Log the revision.
        emit PublishRevision(itemId, state.owner, 0);
    }

    /**
     * @dev Retract an item.
     * @param itemId itemId of the item. This itemId can never be used again.
     */
    function retract(bytes32 itemId) external isOwner(itemId) isRetractable(itemId) {
        // Get item state and IPFS hashes.
        ItemState storage state = itemState[itemId];
        mapping (uint => bytes32) storage ipfsHashes = itemRevisionIpfsHashes[itemId];
        // Log and delete all the IPFS hashes.
        for (uint revisionId = state.revisionCount - 1; revisionId < state.revisionCount; revisionId--) {
            delete ipfsHashes[revisionId];
            emit RetractRevision(itemId, state.owner, revisionId);
        }
        // Delete all the packed revision timestamps.
        _deleteAllPackedRevisionTimestamps(itemId);
        // Mark this item as retracted.
        state.inUse = true;
        state.flags = 0;
        state.revisionCount = 0;
        state.timestamp = 0;
        state.owner = address(0);
        // Log the item retraction.
        emit Retract(itemId, state.owner);
    }

    /**
     * @dev Enable transfer of an item to the current user.
     * @param itemId itemId of the item.
     */
    function transferEnable(bytes32 itemId) external isTransferable(itemId) {
        // Record in state that the current user will accept this item.
        itemTransferEnabled[itemId][msg.sender] = true;
        // Log that transfer to this user is enabled.
        emit EnableTransfer(itemId, itemState[itemId].owner, msg.sender);
    }

    /**
     * @dev Disable transfer of an item to the current user.
     * @param itemId itemId of the item.
     */
    function transferDisable(bytes32 itemId) external isTransferEnabled(itemId, msg.sender) {
        // Record in state that the current user will not accept this item.
        itemTransferEnabled[itemId][msg.sender] = false;
        // Log that transfer to this user is disabled.
        emit DisableTransfer(itemId, itemState[itemId].owner, msg.sender);
    }

    /**
     * @dev Transfer an item to a new user.
     * @param itemId itemId of the item.
     * @param recipient Address of the user to transfer to item to.
     */
    function transfer(bytes32 itemId, address recipient) external isOwner(itemId) isTransferable(itemId) isTransferEnabled(itemId, recipient) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Log the transfer.
        emit Transfer(itemId, state.owner, recipient);
        // Update ownership of the item.
        state.owner = recipient;
        // Disable this transfer in future and free up the slot.
        itemTransferEnabled[itemId][recipient] = false;
    }

    /**
     * @dev Disown an item.
     * @param itemId itemId of the item.
     */
    function disown(bytes32 itemId) external isOwner(itemId) isTransferable(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Log that the item has been disowned.
        emit Disown(itemId, state.owner);
        // Remove the owner from the item's state.
        delete state.owner;
    }

    /**
     * @dev Set an item as not updatable.
     * @param itemId itemId of the item.
     */
    function setNotUpdatable(bytes32 itemId) external isOwner(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Record in state that the item is not updatable.
        state.flags &= ~UPDATABLE;
        // Log that the item is not updatable.
        emit SetNotUpdatable(itemId, state.owner);
    }

    /**
     * @dev Set an item to enforce revisions.
     * @param itemId itemId of the item.
     */
    function setEnforceRevisions(bytes32 itemId) external isOwner(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Record in state that all changes to this item must be new revisions.
        state.flags |= ENFORCE_REVISIONS;
        // Log that the item now enforces new revisions.
        emit SetEnforceRevisions(itemId, state.owner);
    }

    /**
     * @dev Set an item to not be retractable.
     * @param itemId itemId of the item.
     */
    function setNotRetractable(bytes32 itemId) external isOwner(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Record in state that the item is not retractable.
        state.flags &= ~RETRACTABLE;
        // Log that the item is not retractable.
        emit SetNotRetractable(itemId, state.owner);
    }

    /**
     * @dev Set an item to not be transferable.
     * @param itemId itemId of the item.
     */
    function setNotTransferable(bytes32 itemId) external isOwner(itemId) {
        // Get item state.
        ItemState storage state = itemState[itemId];
        // Record in state that the item is not transferable.
        state.flags &= ~TRANSFERABLE;
        // Log that the item is not transferable.
        emit SetNotTransferable(itemId, state.owner);
    }

    /**
     * @dev Get the ABI version for this ItemStore contract.
     * @return ABI version.
     */
    function getAbiVersion() external view returns (uint) {
        return ABI_VERSION;
    }

    /**
     * @dev Get the id for this ItemStore contract.
     * @return Id of the contract.
     */
    function getContractId() external view returns (bytes8) {
        return bytes8(contractId << 192);
    }

    /**
     * @dev Check if an itemId is in use.
     * @param itemId itemId of the item.
     * @return True if the itemId is in use.
     */
    function getInUse(bytes32 itemId) external view returns (bool) {
        return itemState[itemId].inUse;
    }

    /**
     * @dev Get the IPFS hashes for all of an item's revisions.
     * @param itemId itemId of the item.
     * @return ipfsHashes Revision IPFS hashes.
     */
    function _getAllRevisionIpfsHashes(bytes32 itemId) internal view returns (bytes32[] memory ipfsHashes) {
        uint revisionCount = itemState[itemId].revisionCount;
        ipfsHashes = new bytes32[](revisionCount);
        for (uint revisionId = 0; revisionId < revisionCount; revisionId++) {
            ipfsHashes[revisionId] = itemRevisionIpfsHashes[itemId][revisionId];
        }
    }

    /**
     * @dev Get the timestamp for a specific item revision.
     * @param itemId itemId of the item.
     * @param revisionId Id of the revision.
     * @return timestamp Timestamp of the specified revision or 0 for unconfirmed.
     */
    function _getRevisionTimestamp(bytes32 itemId, uint revisionId) internal view returns (uint timestamp) {
        if (revisionId == 0) {
            timestamp = itemState[itemId].timestamp;
        }
        else {
            uint offset = revisionId - 1;
            timestamp = uint32(uint256(itemPackedTimestamps[itemId][offset / 8] >> ((offset % 8) * 32)));
        }
        // Check if the revision has been confirmed yet.
        if (timestamp == block.timestamp) {
            timestamp = 0;
        }
    }

    /**
     * @dev Get the timestamps for all of an item's revisions.
     * @param itemId itemId of the item.
     * @return timestamps Revision timestamps.
     */
    function _getAllRevisionTimestamps(bytes32 itemId) internal view returns (uint[] memory timestamps) {
        uint count = itemState[itemId].revisionCount;
        timestamps = new uint[](count);
        for (uint revisionId = 0; revisionId < count; revisionId++) {
            timestamps[revisionId] = _getRevisionTimestamp(itemId, revisionId);
        }
    }

    /**
     * @dev Get an item.
     * @param itemId itemId of the item.
     * @return flags Packed item settings.
     * @return owner Owner of the item.
     * @return revisionCount How many revisions the item has.
     * @return ipfsHashes IPFS hash of each revision.
     * @return timestamps Timestamp of each revision.
     * @return parentIds itemIds of all parents.
     * @return childIds itemIds of all children.
     */
    function getItem(bytes32 itemId) external view inUse(itemId) returns (byte flags, address owner, uint revisionCount, uint[] memory timestamps, bytes32[] memory ipfsHashes) {
        ItemState storage state = itemState[itemId];
        flags = state.flags;
        owner = state.owner;
        revisionCount = state.revisionCount;
        ipfsHashes = _getAllRevisionIpfsHashes(itemId);
        timestamps = _getAllRevisionTimestamps(itemId);
    }

    /**
     * @dev Get an item's flags.
     * @param itemId itemId of the item.
     * @return Packed item settings.
     */
    function getFlags(bytes32 itemId) external view inUse(itemId) returns (byte) {
        return itemState[itemId].flags;
    }

    /**
     * @dev Determine if an item is updatable.
     * @param itemId itemId of the item.
     * @return True if the item is updatable.
     */
    function getUpdatable(bytes32 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & UPDATABLE != 0;
    }

    /**
     * @dev Determine if an item enforces revisions.
     * @param itemId itemId of the item.
     * @return True if the item enforces revisions.
     */
    function getEnforceRevisions(bytes32 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & ENFORCE_REVISIONS != 0;
    }

    /**
     * @dev Determine if an item is retractable.
     * @param itemId itemId of the item.
     * @return True if the item is item retractable.
     */
    function getRetractable(bytes32 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & RETRACTABLE != 0;
    }

    /**
     * @dev Determine if an item is transferable.
     * @param itemId itemId of the item.
     * @return True if the item is transferable.
     */
    function getTransferable(bytes32 itemId) external view inUse(itemId) returns (bool) {
        return itemState[itemId].flags & TRANSFERABLE != 0;
    }

    /**
     * @dev Get the owner of an item.
     * @param itemId itemId of the item.
     * @return Owner of the item.
     */
    function getOwner(bytes32 itemId) external view inUse(itemId) returns (address) {
        return itemState[itemId].owner;
    }

    /**
     * @dev Get the number of revisions an item has.
     * @param itemId itemId of the item.
     * @return How many revisions the item has.
     */
    function getRevisionCount(bytes32 itemId) external view inUse(itemId) returns (uint) {
        return itemState[itemId].revisionCount;
    }

    /**
     * @dev Get the timestamp for a specific item revision.
     * @param itemId itemId of the item.
     * @param revisionId Id of the revision.
     * @return Timestamp of the specified revision.
     */
    function getRevisionTimestamp(bytes32 itemId, uint revisionId) external view revisionExists(itemId, revisionId) returns (uint) {
        return _getRevisionTimestamp(itemId, revisionId);
    }

    /**
     * @dev Get the timestamps for all of an item's revisions.
     * @param itemId itemId of the item.
     * @return Timestamps of all revisions of the item.
     */
    function getAllRevisionTimestamps(bytes32 itemId) external view inUse(itemId) returns (uint[] memory) {
        return _getAllRevisionTimestamps(itemId);
    }

    /**
     * @dev Get the IPFS hash for a specific item revision.
     * @param itemId itemId of the item.
     * @param revisionId Id of the revision.
     * @return IPFS hash of the specified revision.
     */
    function getRevisionIpfsHash(bytes32 itemId, uint revisionId) external view revisionExists(itemId, revisionId) returns (bytes32) {
        return itemRevisionIpfsHashes[itemId][revisionId];
    }

    /**
     * @dev Get the IPFS hashes for all of an item's revisions.
     * @param itemId itemId of the item.
     * @return IPFS hashes of all revisions of the item.
     */
    function getAllRevisionIpfsHashes(bytes32 itemId) external view inUse(itemId) returns (bytes32[] memory) {
        return _getAllRevisionIpfsHashes(itemId);
    }

}


Rename function to decline from external reasons

/**
 * FlightDelay with Oraclized Underwriting and Payout
 *
 * @description	Underwrite contract
 * @copyright (c) 2017 etherisc GmbH
 * @author Christoph Mussenbrock
 */

pragma solidity ^0.4.11;

import "./FlightDelayControlledContract.sol";
import "./FlightDelayConstants.sol";
import "./FlightDelayDatabaseInterface.sol";
import "./FlightDelayAccessControllerInterface.sol";
import "./FlightDelayLedgerInterface.sol";
import "./FlightDelayUnderwriteInterface.sol";
import "./FlightDelayPayoutInterface.sol";
import "./FlightDelayOraclizeInterface.sol";
import "./convertLib.sol";
import "./../vendors/strings.sol";

contract FlightDelayUnderwrite is FlightDelayControlledContract, FlightDelayConstants, FlightDelayOraclizeInterface, ConvertLib {

    using strings for *;

    FlightDelayDatabaseInterface FD_DB;
    FlightDelayLedgerInterface FD_LG;
    FlightDelayPayoutInterface FD_PY;
    FlightDelayAccessControllerInterface FD_AC;

    function FlightDelayUnderwrite(address _controller) {
        setController(_controller);
    }

    function setContracts() onlyController {
        FD_AC = FlightDelayAccessControllerInterface(getContract("FD.AccessController"));
        FD_DB = FlightDelayDatabaseInterface(getContract("FD.Database"));
        FD_LG = FlightDelayLedgerInterface(getContract("FD.Ledger"));
        FD_PY = FlightDelayPayoutInterface(getContract("FD.Payout"));

        FD_AC.setPermissionById(101, "FD.NewPolicy");
        FD_AC.setPermissionById(102, "FD.Funder");
    }

    /*
     * @dev Fund contract
     */
    function fund() payable {
        require(FD_AC.checkPermission(102, msg.sender));

        // todo: bookkeeping
        // todo: fire funding event
    }

    function scheduleUnderwriteOraclizeCall(uint _policyId, bytes32 _carrierFlightNumber) {
        require(FD_AC.checkPermission(101, msg.sender));

        string memory oraclizeUrl = strConcat(
            ORACLIZE_RATINGS_BASE_URL,
            b32toString(_carrierFlightNumber),
            ORACLIZE_RATINGS_QUERY
        );

// --> debug-mode
//            LogUint("_policyId", _policyId);
//            LogBytes32Str("_carrierFlightNumber",_carrierFlightNumber);
//            LogString("oraclizeUrl", oraclizeUrl);
// <-- debug-mode

        bytes32 queryId = oraclize_query("nested", oraclizeUrl, ORACLIZE_GAS);

        // call oraclize to get Flight Stats; this will also call underwrite()
        FD_DB.createOraclizeCallback(
            queryId,
            _policyId,
            oraclizeState.ForUnderwriting,
            0
        );

        LogOraclizeCall(_policyId, queryId, oraclizeUrl);
    }

    function __callback(bytes32 _queryId, string _result, bytes _proof) onlyOraclize {
// --> debug-mode
//            LogString("_result", _result);
// <-- debug-mode

        var (policyId,) = FD_DB.getOraclizeCallback(_queryId);

        var slResult = _result.toSlice();

        // we expect result to contain 6 values, something like
        // "[61, 10, 4, 3, 0, 0, \"CUN\"]" ->
        // ['observations','late15','late30','late45','cancelled','diverted','arrivalAirportFsCode']
        if (bytes(_result).length == 0) {
            decline(policyId, "Declined (empty result)", _proof);
        } else {
            // now slice the string using
            // https://github.com/Arachnid/solidity-stringutils
            if (slResult.count(", ".toSlice()) != 6) {
                // check if result contains 7 values
                decline(policyId, "Declined (invalid result)", _proof);
            } else {
                slResult.beyond("[".toSlice()).until("]".toSlice());

                uint observations = parseInt(slResult.split(", ".toSlice()).toString());

                // decline on < minObservations observations,
                // can't calculate reasonable probabibilities
                if (observations <= MIN_OBSERVATIONS) {
                    decline(policyId, "Declined (too few observations)", _proof);
                } else {
                    uint[6] memory statistics;
                    // calculate statistics (scaled by 10000; 1% => 100)
                    statistics[0] = observations;
                    for (uint i = 1; i <= 5; i++) {
                        statistics[i] = parseInt(slResult.split(", ".toSlice()).toString()) * 10000/observations;
                    }

                    var destination  = slResult.split(", ".toSlice());

                    if (
// --> test-mode
//                            '"JFK"'.toSlice().equals(destination) ||
// <-- test-mode
                        '"CUN"'.toSlice().equals(destination) ||
                        '"CZM"'.toSlice().equals(destination) ||
                        '"MID"'.toSlice().equals(destination))
                    {
                        // underwrite policy
                        underwrite(policyId, statistics, _proof);
                    } else {
                        decline(policyId, "Not acceptable destination", _proof);
                    }
                }
            }
        }
    } // __callback

    function externalDecline(uint _policyId, bytes32 _reason) external {
        require(msg.sender == FD_CI.getContract("FD.CustomersAdmin"));

        LogPolicyDeclined(_policyId, _reason);

        FD_DB.setState(
            _policyId,
            policyState.Declined,
            now,
            _reason
        );

        FD_DB.setWeight(_policyId, 0, "");

        var (customer, premium) = FD_DB.getCustomerPremium(_policyId);

        if (!FD_LG.sendFunds(customer, Acc.Premium, premium)) {
            FD_DB.setState(
                _policyId,
                policyState.SendFailed,
                now,
                "decline: Send failed."
            );
        }
    }

    function decline(uint _policyId, bytes32 _reason, bytes _proof)	internal {
        LogPolicyDeclined(_policyId, _reason);

        FD_DB.setState(
            _policyId,
            policyState.Declined,
            now,
            _reason
        );

        FD_DB.setWeight(_policyId, 0, _proof);

        var (customer, premium) = FD_DB.getCustomerPremium(_policyId);

        // TODO: LOG
        if (!FD_LG.sendFunds(customer, Acc.Premium, premium)) {
            FD_DB.setState(
                _policyId,
                policyState.SendFailed,
                now,
                "decline: Send failed."
            );
        }
    }

    function underwrite(uint _policyId, uint[6] _statistics, bytes _proof) internal {
        var (, premium) = FD_DB.getCustomerPremium(_policyId); // throws if _policyId invalid
        bytes32 riskId = FD_DB.getRiskId(_policyId);

        var (, premiumMultiplier) = FD_DB.getPremiumFactors(riskId);

        uint weight;
        for (uint8 i = 1; i <= 5; i++ ) {
            weight += WEIGHT_PATTERN[i] * _statistics[i];
            // 1% = 100 / 100% = 10,000
        }
        // to avoid div0 in the payout section,
        // we have to make a minimal assumption on p.weight.
        if (weight == 0) {
            weight = 100000 / _statistics[0];
        }

        // we calculate the factors to limit cluster risks.
        if (premiumMultiplier == 0) {
            // it's the first call, we accept any premium
            FD_DB.setPremiumFactors(riskId, premium * 100000 / weight, 100000 / weight);
        }

        FD_DB.setWeight(_policyId, weight, _proof);

        FD_DB.setState(
            _policyId,
            policyState.Accepted,
            now,
            "Policy underwritten by oracle"
        );

        LogPolicyAccepted(
            _policyId,
            _statistics[0],
            _statistics[1],
            _statistics[2],
            _statistics[3],
            _statistics[4],
            _statistics[5]
        );

        // schedule payout Oracle
        FD_PY.schedulePayoutOraclizeCall(_policyId, riskId, CHECK_PAYOUT_OFFSET);
    }
}

/**
 * FlightDelay with Oraclized Underwriting and Payout
 *
 * @description	Underwrite contract
 * @copyright (c) 2017 etherisc GmbH
 * @author Christoph Mussenbrock
 */

pragma solidity ^0.4.11;

import "./FlightDelayControlledContract.sol";
import "./FlightDelayConstants.sol";
import "./FlightDelayDatabaseInterface.sol";
import "./FlightDelayAccessControllerInterface.sol";
import "./FlightDelayLedgerInterface.sol";
import "./FlightDelayUnderwriteInterface.sol";
import "./FlightDelayPayoutInterface.sol";
import "./FlightDelayOraclizeInterface.sol";
import "./convertLib.sol";
import "./../vendors/strings.sol";

contract FlightDelayUnderwrite is FlightDelayControlledContract, FlightDelayConstants, FlightDelayOraclizeInterface, ConvertLib {

    using strings for *;

    FlightDelayDatabaseInterface FD_DB;
    FlightDelayLedgerInterface FD_LG;
    FlightDelayPayoutInterface FD_PY;
    FlightDelayAccessControllerInterface FD_AC;

    function FlightDelayUnderwrite(address _controller) {
        setController(_controller);
    }

    function setContracts() onlyController {
        FD_AC = FlightDelayAccessControllerInterface(getContract("FD.AccessController"));
        FD_DB = FlightDelayDatabaseInterface(getContract("FD.Database"));
        FD_LG = FlightDelayLedgerInterface(getContract("FD.Ledger"));
        FD_PY = FlightDelayPayoutInterface(getContract("FD.Payout"));

        FD_AC.setPermissionById(101, "FD.NewPolicy");
        FD_AC.setPermissionById(102, "FD.Funder");
    }

    /*
     * @dev Fund contract
     */
    function fund() payable {
        require(FD_AC.checkPermission(102, msg.sender));

        // todo: bookkeeping
        // todo: fire funding event
    }

    function scheduleUnderwriteOraclizeCall(uint _policyId, bytes32 _carrierFlightNumber) {
        require(FD_AC.checkPermission(101, msg.sender));

        string memory oraclizeUrl = strConcat(
            ORACLIZE_RATINGS_BASE_URL,
            b32toString(_carrierFlightNumber),
            ORACLIZE_RATINGS_QUERY
        );

// --> debug-mode
//            LogUint("_policyId", _policyId);
//            LogBytes32Str("_carrierFlightNumber",_carrierFlightNumber);
//            LogString("oraclizeUrl", oraclizeUrl);
// <-- debug-mode

        bytes32 queryId = oraclize_query("nested", oraclizeUrl, ORACLIZE_GAS);

        // call oraclize to get Flight Stats; this will also call underwrite()
        FD_DB.createOraclizeCallback(
            queryId,
            _policyId,
            oraclizeState.ForUnderwriting,
            0
        );

        LogOraclizeCall(_policyId, queryId, oraclizeUrl);
    }

    function __callback(bytes32 _queryId, string _result, bytes _proof) onlyOraclize {
// --> debug-mode
//            LogString("_result", _result);
// <-- debug-mode

        var (policyId,) = FD_DB.getOraclizeCallback(_queryId);

        var slResult = _result.toSlice();

        // we expect result to contain 6 values, something like
        // "[61, 10, 4, 3, 0, 0, \"CUN\"]" ->
        // ['observations','late15','late30','late45','cancelled','diverted','arrivalAirportFsCode']
        if (bytes(_result).length == 0) {
            decline(policyId, "Declined (empty result)", _proof);
        } else {
            // now slice the string using
            // https://github.com/Arachnid/solidity-stringutils
            if (slResult.count(", ".toSlice()) != 6) {
                // check if result contains 7 values
                decline(policyId, "Declined (invalid result)", _proof);
            } else {
                slResult.beyond("[".toSlice()).until("]".toSlice());

                uint observations = parseInt(slResult.split(", ".toSlice()).toString());

                // decline on < minObservations observations,
                // can't calculate reasonable probabibilities
                if (observations <= MIN_OBSERVATIONS) {
                    decline(policyId, "Declined (too few observations)", _proof);
                } else {
                    uint[6] memory statistics;
                    // calculate statistics (scaled by 10000; 1% => 100)
                    statistics[0] = observations;
                    for (uint i = 1; i <= 5; i++) {
                        statistics[i] = parseInt(slResult.split(", ".toSlice()).toString()) * 10000/observations;
                    }

                    var destination  = slResult.split(", ".toSlice());

                    if (
// --> test-mode
//                            '"JFK"'.toSlice().equals(destination) ||
// <-- test-mode
                        '"CUN"'.toSlice().equals(destination) ||
                        '"CZM"'.toSlice().equals(destination) ||
                        '"MID"'.toSlice().equals(destination))
                    {
                        // underwrite policy
                        underwrite(policyId, statistics, _proof);
                    } else {
                        decline(policyId, "Not acceptable destination", _proof);
                    }
                }
            }
        }
    } // __callback

    function decline(uint _policyId, bytes32 _reason) external {
        require(msg.sender == FD_CI.getContract("FD.CustomersAdmin"));

        LogPolicyDeclined(_policyId, _reason);

        FD_DB.setState(
            _policyId,
            policyState.Declined,
            now,
            _reason
        );

        FD_DB.setWeight(_policyId, 0, "");

        var (customer, premium) = FD_DB.getCustomerPremium(_policyId);

        if (!FD_LG.sendFunds(customer, Acc.Premium, premium)) {
            FD_DB.setState(
                _policyId,
                policyState.SendFailed,
                now,
                "decline: Send failed."
            );
        }
    }

    function decline(uint _policyId, bytes32 _reason, bytes _proof)	internal {
        LogPolicyDeclined(_policyId, _reason);

        FD_DB.setState(
            _policyId,
            policyState.Declined,
            now,
            _reason
        );

        FD_DB.setWeight(_policyId, 0, _proof);

        var (customer, premium) = FD_DB.getCustomerPremium(_policyId);

        // TODO: LOG
        if (!FD_LG.sendFunds(customer, Acc.Premium, premium)) {
            FD_DB.setState(
                _policyId,
                policyState.SendFailed,
                now,
                "decline: Send failed."
            );
        }
    }

    function underwrite(uint _policyId, uint[6] _statistics, bytes _proof) internal {
        var (, premium) = FD_DB.getCustomerPremium(_policyId); // throws if _policyId invalid
        bytes32 riskId = FD_DB.getRiskId(_policyId);

        var (, premiumMultiplier) = FD_DB.getPremiumFactors(riskId);

        uint weight;
        for (uint8 i = 1; i <= 5; i++ ) {
            weight += WEIGHT_PATTERN[i] * _statistics[i];
            // 1% = 100 / 100% = 10,000
        }
        // to avoid div0 in the payout section,
        // we have to make a minimal assumption on p.weight.
        if (weight == 0) {
            weight = 100000 / _statistics[0];
        }

        // we calculate the factors to limit cluster risks.
        if (premiumMultiplier == 0) {
            // it's the first call, we accept any premium
            FD_DB.setPremiumFactors(riskId, premium * 100000 / weight, 100000 / weight);
        }

        FD_DB.setWeight(_policyId, weight, _proof);

        FD_DB.setState(
            _policyId,
            policyState.Accepted,
            now,
            "Policy underwritten by oracle"
        );

        LogPolicyAccepted(
            _policyId,
            _statistics[0],
            _statistics[1],
            _statistics[2],
            _statistics[3],
            _statistics[4],
            _statistics[5]
        );

        // schedule payout Oracle
        FD_PY.schedulePayoutOraclizeCall(_policyId, riskId, CHECK_PAYOUT_OFFSET);
    }
}