contract ArtCertificate is Ownable, CertificateStructures, ERC165 {
    using SafeMath for uint256;

    event CertificateTransferred(uint certificateId, address _from, address _to);

    /*--------------------------------------------------STORAGE---------------------------------------------------*/
    // available id for next certificate
    uint256 public nextCertificateId = 1; 

    /* Public Storage */
    string public site_web = "https://www.artcertificate.eu/";
    string public constant nom = "Artcertificate";
    string public constant symbole = "ART";

    // Certificates storage
    mapping(uint256 => Certificate) public certificates;
    // Artworks storage
    mapping(uint256 => Artwork) public artworks;
    // All Certificates
    uint[] private certificateIds;
    // Mapping certificate owner => certificateIds
    mapping(address => uint256[]) private ownedCertificates;


    /*--------------------------------------------------ACCESS RESTRICTIONS---------------------------------------------------*/
    modifier onlyCertificateOrContractOwner(uint _id) {
        require(
            isOwner()
            || proprietaireCertificat(_id) == msg.sender
        );
        _;
    }

    
    /*-------------------------------------------------SETTER FUNCTIONS----------------------------------------------------*/
    function print(
        uint date_oeuvre,
        string memory identifiant_unique_non_consecutif,          
        string memory deposant,
        string memory artiste,
        string memory oeuvre,
        string memory support,
        string memory dimension,
        string memory signature,
        string memory numero_serie,
        string memory url_image_externe,
        string memory url_certificat
    ) public onlyOwner returns (uint){

        Certificate memory certificate;
        Artwork memory artwork;

        // add all certificate's params
        certificate = Certificate(
            nextCertificateId,
            block.timestamp,
            proprietaire_contrat(),
            identifiant_unique_non_consecutif,
            url_image_externe,
            url_certificat
        );

        // add all artwork's params
        artwork = Artwork(
            date_oeuvre,      
            deposant,
            artiste,
            signature,
            numero_serie,
            oeuvre,
            support,
            dimension
        );
        
        // add new certificate to certificates
        certificates[nextCertificateId] = certificate; 
        
        // add new artwork to artworks
        artworks[nextCertificateId] = artwork;

        // store certificate id to certificateIds
        certificateIds.push(nextCertificateId);

        // add owner to ownedCertificates
        ownedCertificates[proprietaire_contrat()].push(nextCertificateId);
        
        // add 1 to next certificate available id    
        nextCertificateId = nextCertificateId.add(1);

        return nextCertificateId.sub(1);

    }

    /**
    * @dev Website url setter
    * @dev access restricted to contract owner only
    * @param _url the new url to set as the url of the website
    */
    function setWebsiteUrl(string memory _url) public onlyOwner {
        site_web = _url;
    }
    
    /**
    * @dev Transfer a certificate
    * @dev access restricted to certificate or contract owner only
    * @param _id the id of the certificate to transfer ownership of
    * @param _newOwner the ethereum public address of the new certificate owner (will be denied if _newOwner is a contract)
    */
    function transferer_certificat(uint _id, address _newOwner) public onlyCertificateOrContractOwner(_id) {
        require(_newOwner != ZERO_ADDRESS);
        require(!Address.isContract(_newOwner));

        // retrieve certificate
        Certificate memory certificate = certificates[_id];
        // retrieve old owner
        address oldOwner = certificate.eth_adresse_proprietaire;
        // give Certificate ownership 
        certificates[_id].eth_adresse_proprietaire = _newOwner;
        // add to certificate owners (ownedCertificates)
        ownedCertificates[_newOwner].push(_id);
        // take certificate owner off from ownedCertificates
        for (uint i = 0; i < ownedCertificates[oldOwner].length; i++) {
            if (ownedCertificates[oldOwner][i] == _id) {
                delete ownedCertificates[oldOwner][i];
            }
        }

        emit CertificateTransferred(_id, oldOwner, _newOwner);


        
    }


    /*-------------------------------------------------GETTER FUNCTIONS----------------------------------------------------*/
    
    /**
    * @dev Returns owner's certificates
    * @param _proprietaire ethereum public address of the certificate owner
    * @return certificats_proprietaire : the certificates of `_proprietaire`
    */
    function certificatsProprietaire(address _proprietaire) public view returns(uint[] memory) {
        return ownedCertificates[_proprietaire];
    }

    /**
    * @dev Returns caller's certificates
    * @return mes_certificats
    */
    function mesCertificats() public view returns(uint[] memory mes_certificats) {
        return certificatsProprietaire(msg.sender);
    }

    /**
    * @dev Returns certificate's owner by id
    * @param _id the id of the certificate to retrieve owner of
    * @return proprietaire_certificat : the owner of certificate with `_id`
    */
    function proprietaireCertificat(uint _id) public view returns(address proprietaire_certificat) {
        return certificates[_id].eth_adresse_proprietaire;
    }

    /**
    * @dev Returns an external url leading to certificate's image 
    * @param _id the id of the certificate to retrieve image of
    * @return lien_vers_image : url pointing to an image of the certificate with `_id`
    */
    function imageCertificat(uint _id) public view returns(string memory lien_vers_image) {
        return certificates[_id].url_image_externe;
    }

    function liste_certificats() public view returns(uint[] memory) {
        return certificateIds;
    }
}
/**
 * @title ArtCertificate NFT Assets
 * @dev NON-STANDARD contract
 * @dev Each certificate id MUST lead to :
 {
 identifiant_unique_non_consecutif,          
 deposant,
 artiste,
 oeuvre,
 date_oeuvre,
 support,
 dimension,
 signature,
 numero_serie,
 eth_adresse_proprietaire
 }
 */
function setWebsiteUrl(string memory _url) public onlyOwner {
    site_web = _url;
}

/**
 * @dev Website url setter
 * @dev access restricted to contract owner only
 * @param _url the new url to set as the url of the website
 */