contract Validator is Owned {

    mapping (bytes32 => mapping (address => bool)) public hashAttestations;
    mapping (address => bool) public isValidator;
    mapping (address => uint8) public validatorNum;
    address[] public validators;
    address public metToken;
    address public tokenPorter;

    mapping (bytes32 => bool) public hashClaimed;

    uint8 public threshold = 2;

    event LogAttestation(bytes32 indexed hash, address indexed who, bool isValid);

    /// @param _validator1 first validator  
    /// @param _validator2 second validator
    /// @param _validator3 third validator
    function initValidator(address _validator1, address _validator2, address _validator3) public onlyOwner {
        // Clear old validators. Validators can be updated multiple times
        for (uint8 i = 0; i < validators.length; i++) {
            delete isValidator[validators[i]];
            delete validatorNum[validators[i]];
        }
        delete validators;
        validators.push(_validator1);
        validators.push(_validator2);
        validators.push(_validator3);
        // TODO: This will be NA, Bloq and a third party (escrow or company) at launch, 
        // and should be scripted into deploy

        isValidator[_validator1] = true;
        isValidator[_validator2] = true;
        isValidator[_validator3] = true;

        validatorNum[_validator1] = 0;
        validatorNum[_validator2] = 1;
        validatorNum[_validator3] = 2;

    }

    /// @notice set address of token porter
    /// @param _tokenPorter address of token porter
    function setTokenPorter(address _tokenPorter) public onlyOwner returns (bool) {
        require(_tokenPorter != 0x0);
        tokenPorter = _tokenPorter;
        return true;
    }

    function validateHash(bytes32 hash) public {
        require(isValidator[msg.sender]);
        hashAttestations[hash][msg.sender] = true;
        emit LogAttestation(hash, msg.sender, true);
    }

    function invalidateHash(bytes32 hash) public {
        require(isValidator[msg.sender]);
        hashAttestations[hash][msg.sender] = false;
        emit LogAttestation(hash, msg.sender, false);
    }

    function hashClaimable(bytes32 hash) public view returns(bool) {
        if (hashClaimed[hash]) { return false; }

        uint8 count = 0;

        for (uint8 i = 0; i < validators.length; i++) {
            if (hashAttestations[hash][validators[i]]) { count++;} 
        }

        if (count >= threshold) { return true; }
        return false;
    }

    function claimHash(bytes32 hash) public {
        require(msg.sender == tokenPorter);
        require(hashClaimable(hash));
        hashClaimed[hash] = true;
    }

    function isReceiptClaimable(bytes8 _originChain, bytes8 _destinationChain, address[] _addresses, bytes _extraData, 
        bytes32[] _burnHashes, uint[] _supplyOnAllChain, uint[] _importData, bytes _proof) public view returns(bool) {
        // We want to validate that these hash to the provided hash as a safety check, 
        // then we want to know if the hash is Claimable. 

        // Due to stack too deep error and limitation in using number of local 
        // variables we have to use uint array here. 
        // _importData[0] is _blockTimestamp, _importData[1] is _amount, _importData[2] is _fee,
        // _importData[3] is _burnedAtTick, _importData[4] is _genesisTime,
        // _importData[5] is _dailyMintable, _importData[6] is _burnSequence,
        // _addresses[0] is _destMetronomeAddr and _addresses[1] is _recipAddr

        require(_burnHashes[1] == keccak256(_importData[0], _originChain, _destinationChain, _addresses[0], 
            _addresses[1], _importData[1], _importData[3], _importData[4], _importData[5], _supplyOnAllChain[0], 
            _extraData, _burnHashes[0]));

        if (hashClaimable(_burnHashes[1])) {
            return true;
        } 
        
        return false;

    }
}
function initValidator(address _validator1, address _validator2, address _validator3) public onlyOwner {
    // Clear old validators. Validators can be updated multiple times
    for (uint8 i = 0; i < validators.length; i++) {
        delete isValidator[validators[i]];
        delete validatorNum[validators[i]];
    }
    delete validators;
    validators.push(_validator1);
    validators.push(_validator2);
    validators.push(_validator3);
    // TODO: This will be NA, Bloq and a third party (escrow or company) at launch, 
    // and should be scripted into deploy

    isValidator[_validator1] = true;
    isValidator[_validator2] = true;
    isValidator[_validator3] = true;

    validatorNum[_validator1] = 0;
    validatorNum[_validator2] = 1;
    validatorNum[_validator3] = 2;

}

/// @param _validator1 first validator  
/// @param _validator2 second validator
/// @param _validator3 third validator