contract GGDAsset is CustomERC721Full, WhitelistAdminRole {
    using SafeMath for uint256;
    ERC621Basic eRC621Token;

    string public tokenBaseURI = "";

    event AesetMinted(
        uint256 indexed _tokenId,
        address indexed _to,
        uint256 assetAount
    );

    uint256 public totalAssets = 0;
    uint256 public tokenIdPointer = 0;

    struct Aesset {
        string assetName;
        string assetCoordinates;
        uint256 propertyArea;
        uint256 assetValue;
        address manager;
    }
    
    struct ManagerInfo{
        string managerName;
        string managerRegNo;
    }

    mapping(uint256 => Aesset) internal assets;
    mapping(uint256 => string) internal evaluationSummarys;
    mapping(uint256 => string) internal appraiserRegistrationNos;
    mapping(uint256 => string) internal lawyerOpinions;
    mapping(uint256 => string) internal registeredLawyerNos;
    mapping(uint256 => ManagerInfo) internal managerInfos;

    constructor (string memory _tokenBaseURI) public CustomERC721Full("Green Gold Asset", "GGDA") {
        tokenBaseURI = _tokenBaseURI;
    }

    function createAsset(
        string memory _assetName,
        string memory _assetCoordinates,
        uint256 _propertyArea,
        uint256 _assetValue,
        address _manager,
        uint256 _assetAmount
    )
    public onlyWhitelistAdmin returns (uint256 _tokenId) {
        uint256 tokenId = tokenIdPointer.add(1);

        // reset token pointer
        tokenIdPointer = tokenId;

        // create Assets
        assets[tokenId] = Aesset({
            assetName : _assetName,
            assetCoordinates : _assetCoordinates,
            propertyArea : _propertyArea,
            assetValue : _assetValue,
            manager : _manager
        });

        totalAssets = totalAssets.add(1);

        _issueToken(_manager,_assetAmount);
        // mint the actual token magic
        _mint(_manager, tokenId);

        emit AesetMinted(tokenId, _manager, _assetAmount);

        return tokenId;
    }
    
    function updateMangerInfo(uint256 _tokenId,string memory _managerName,string memory _managerRegNo) public onlyWhitelistAdmin{
        require(_exists(_tokenId));
        managerInfos[_tokenId] = ManagerInfo({
            managerName : _managerName,
            managerRegNo : _managerRegNo
        });
    }
    
    function managerInfoOf(uint256 _tokenId) public view returns(
        string memory _managerName,
        string memory _managerRegNo
    ){
       require(_exists(_tokenId), "Token ID not found");
       ManagerInfo storage info = managerInfos[_tokenId];
       return(
           info.managerName,
           info.managerRegNo
       );
    }
    
    // evaluationSummarys 
    function updateEvaluationSummary(uint256 _tokenId,string memory _evaluationSummary) public onlyWhitelistAdmin{
        require(_exists(_tokenId));
        // require(ownerOf(tokenId) == from);
         evaluationSummarys[_tokenId] = _evaluationSummary;
    }
    
    function evaluationSummaryOf(uint256 _tokenId) public view returns(
        string memory _evaluationSummary
    ){
       require(_exists(_tokenId), "Token ID not found");
       return evaluationSummarys[_tokenId];
    }
    
    // lawyerOpinions
    function updateLawyerOpinions(uint256 _tokenId,string memory _lawyerOpinion) public onlyWhitelistAdmin{
        require(_exists(_tokenId));
        lawyerOpinions[_tokenId] = _lawyerOpinion;
    }
    
    function lawyerOpinionOf(uint256 _tokenId) public view returns(
        string memory _lawyerOpinion
    ){
       require(_exists(_tokenId), "Token ID not found");
       return lawyerOpinions[_tokenId];
    }
    
    // appraiserRegistrationNos
    function updateAppraiserRegistrationNo(uint256 _tokenId,string memory _appraiserRegistrationNo) public onlyWhitelistAdmin{
        require(_exists(_tokenId));
        appraiserRegistrationNos[_tokenId] = _appraiserRegistrationNo;
    }
    
    function appraiserRegistrationNoOf(uint256 _tokenId) public view returns(
        string memory _appraiserRegistrationNo
    ){
       require(_exists(_tokenId), "Token ID not found");
       return appraiserRegistrationNos[_tokenId];
    }
    
    // registeredLawyerNos
    function updateRegisteredLawyerNo(uint256 _tokenId,string memory _registeredLawyerNo) public onlyWhitelistAdmin{
        require(_exists(_tokenId));
        registeredLawyerNos[_tokenId] = _registeredLawyerNo;
    }
    
    function registeredLawyerNoOf(uint256 _tokenId) public view returns(
        string memory _registeredLawyerNo
    ){
       require(_exists(_tokenId), "Token ID not found");
       return registeredLawyerNos[_tokenId];
    }
    
    
    function assetBaseInfo(uint256 _tokenId) public view returns (
        string memory _assetName,
        string memory _assetCoordinates,
        uint256 _propertyArea,
        uint256 _assetValue,
        address _manager
    
    ) {
        require(_exists(_tokenId), "Token ID not found");
        Aesset storage asset = assets[_tokenId];

        return (
            asset.assetName,
            asset.assetCoordinates,
            asset.propertyArea,
            asset.assetValue,
            asset.manager
        );
    }
    

    /**
     * @dev Returns an URI for a given token ID
     * Throws if the token ID does not exist. May return an empty string.
     * @param tokenId uint256 ID of the token to query
     */
    function tokenURI(uint256 tokenId) external view returns (string memory) {
        require(_exists(tokenId));
        return Strings.strConcat(tokenBaseURI, Strings.uint2str(tokenId));
    }

    
    function _issueToken(address _to,uint256 _amount) internal{
        require(eRC621Token != ERC621Basic(0));
        eRC621Token.increaseSupply(_to,_amount);
    }
    
    function updateIssueToken(ERC621Basic _token) public onlyWhitelistAdmin{
        eRC621Token = _token;
    }
    

    function tokensOfOwner(address owner) public view returns (uint256[] memory) {
        return _tokensOfOwner(owner);
    }

    function burn(uint256 _tokenId) public onlyWhitelistAdmin returns (bool) {
        _burn(_tokenId);

        delete assets[_tokenId];

        return true;
    }

    function updateTokenBaseURI(string memory _newBaseURI) public onlyWhitelistAdmin {
        require(bytes(_newBaseURI).length != 0, "Base URI invalid");
        tokenBaseURI = _newBaseURI;
    }
}
function updateEvaluationSummary(uint256 _tokenId,string memory _evaluationSummary) public onlyWhitelistAdmin{
    require(_exists(_tokenId));
    // require(ownerOf(tokenId) == from);
     evaluationSummarys[_tokenId] = _evaluationSummary;
}

// evaluationSummarys 