// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// A representation of an empty/uninitialized UID.
bytes32 constant EMPTY_UID = 0;

// A zero expiration represents an non-expiring attestation.
uint64 constant NO_EXPIRATION_TIME = 0;

error AccessDenied();
error InvalidEAS();
error InvalidLength();
error InvalidSignature();
error NotFound();

/**
 * @dev A struct representing EIP712 signature data.
 */
struct EIP712Signature {
    uint8 v; // The recovery ID.
    bytes32 r; // The x-coordinate of the nonce R.
    bytes32 s; // The signature data.
}

/**
 * @dev A struct representing a single attestation.
 */
struct Attestation {
    bytes32 uid; // A unique identifier of the attestation.
    bytes32 schema; // The unique identifier of the schema.
    uint64 time; // The time when the attestation was created (Unix timestamp).
    uint64 expirationTime; // The time when the attestation expires (Unix timestamp).
    uint64 revocationTime; // The time when the attestation was revoked (Unix timestamp).
    bytes32 refUID; // The UID of the related attestation.
    address recipient; // The recipient of the attestation.
    address attester; // The attester/sender of the attestation.
    bool revocable; // Whether the attestation is revocable.
    bytes data; // Custom attestation data.
}

// Maximum upgrade forward-compatibility storage gap.
uint32 constant MAX_GAP = 50;

/**
 * @dev A helper function to work with unchecked iterators in loops.
 *
 * @param i The index to increment.
 *
 * @return j The incremented index.
 */
function uncheckedInc(uint256 i) pure returns (uint256 j) {
    unchecked {
        j = i + 1;
    }
}

/**
 * @dev A helper function that converts a string to a bytes32.
 *
 * @param str The string to convert.
 *
 * @return The converted bytes32.
 */
function stringToBytes32(string memory str) pure returns (bytes32) {
    bytes32 result;

    assembly {
        result := mload(add(str, 32))
    }

    return result;
}

/**
 * @dev A helper function that converts a bytes32 to a string.
 *
 * @param data The bytes32 data to convert.
 *
 * @return The converted string.
 */
function bytes32ToString(bytes32 data) pure returns (string memory) {
    bytes memory byteArray = new bytes(32);

    uint256 length = 0;
    for (uint256 i = 0; i < 32; i = uncheckedInc(i)) {
        bytes1 char = data[i];
        if (char == 0x00) {
            break;
        }

        byteArray[length] = char;
        length = uncheckedInc(length);
    }

    bytes memory terminatedBytes = new bytes(length);
    for (uint256 j = 0; j < length; j = uncheckedInc(j)) {
        terminatedBytes[j] = byteArray[j];
    }

    return string(terminatedBytes);
}
