contract AssetHashToken is ownable, verifiable{
    using SafeMath for uint;

    //Asset Struct
    struct data {
        // link URL of the original information for storing data; null means undisclosed
        string link;
        // The hash type of the original data, such as SHA-256
        string hashType;
        // Hash value of the agreed content.
        string hashValue;
    }

    data public assetFile;
    data public legalFile;

    //The token id
    uint id;

    //The validity of the contract
    bool public isValid;

    //The splitting status of the asset
    //Set to true if the asset has been splitted to small tokens
    bool public isSplitted;

    // The tradeable status of asset
    // Leave (together with assetPrice) for auto buy and sell functionality (with Ether).
    bool public isTradable;

    /**
     * The price of asset
     * if the contract is valid and tradeable,
     * others can get asset by transfer assetPrice ETH to contract
     */
    uint public assetPrice;

    //Some addtional notes
    string public remark1;
    string public remark2;

    mapping (address => uint) pendingWithdrawals;

    /**
     * The asset update events
     */
    event TokenUpdateEvent (
        uint id,
        bool isValid,
        bool isTradable,
        address owner,
        uint assetPrice,
        string assetFileLink,
        string legalFileLink
    );

    modifier onlyUnsplitted {
        require(isSplitted == false, "This function can be called only under unsplitted status");
        _;
    }

    modifier onlyValid {
        require(isValid == true, "Contract is invaild!");
        _;
    }

    /**
     * constructor
     * @param _id Token id
     * @param _owner initial owner
     * @param _assetPrice The price of asset
     * @param _assetFileUrl The url of asset file
     * @param _assetFileHashType The hash type of asset file
     * @param _assetFileHashValue The hash value of asset file
     * @param _legalFileUrl The url of legal file
     * @param _legalFileHashType The hash type of legal file
     * @param _legalFileHashValue The hash value of legal file
     */
    constructor(
        uint _id,
        address _owner,
        uint _assetPrice,
        string _assetFileUrl,
        string _assetFileHashType,
        string _assetFileHashValue,
        string _legalFileUrl,
        string _legalFileHashType,
        string _legalFileHashValue
        ) public {

        id = _id;
        owner = _owner;

        assetPrice = _assetPrice;

        initAssetFile(
            _assetFileUrl, _assetFileHashType, _assetFileHashValue, _legalFileUrl, _legalFileHashType, _legalFileHashValue);

        isValid = true;
        isSplitted = false;
        isTradable = false;
    }

    /**
     * Initialize asset file and legal file
     * @param _assetFileUrl The url of asset file
     * @param _assetFileHashType The hash type of asset file
     * @param _assetFileHashValue The hash value of asset file
     * @param _legalFileUrl The url of legal file
     * @param _legalFileHashType The hash type of legal file
     * @param _legalFileHashValue The hash value of legal file
     */
    function initAssetFile(
        string _assetFileUrl,
        string _assetFileHashType,
        string _assetFileHashValue,
        string _legalFileUrl,
        string _legalFileHashType,
        string _legalFileHashValue
        ) internal {
        assetFile = data(
            _assetFileUrl, _assetFileHashType, _assetFileHashValue);
        legalFile = data(
            _legalFileUrl, _legalFileHashType, _legalFileHashValue);
    }

     /**
     * Get base asset info
     */
    function getAssetBaseInfo() public view onlyValid
        returns (
            uint _id,
            uint _assetPrice,
            bool _isTradable,
            string _remark1,
            string _remark2
        )
    {
        _id = id;
        _assetPrice = assetPrice;
        _isTradable = isTradable;

        _remark1 = remark1;
        _remark2 = remark2;
    }

    /**
     * set the price of asset
     * @param newAssetPrice new price of asset
     * Only can be called by owner
     */
    function setassetPrice(uint newAssetPrice)
        public
        onlyOwner
        onlyValid
        onlyUnsplitted
    {
        assetPrice = newAssetPrice;
        emit TokenUpdateEvent (
            id,
            isValid,
            isTradable,
            owner,
            assetPrice,
            assetFile.link,
            legalFile.link
        );
    }

    /**
     * set the tradeable status of asset
     * @param status status of isTradable
     * Only can be called by owner
     */
    function setTradeable(bool status) public onlyOwner onlyValid onlyUnsplitted {
        isTradable = status;
        emit TokenUpdateEvent (
            id,
            isValid,
            isTradable,
            owner,
            assetPrice,
            assetFile.link,
            legalFile.link
        );
    }

    /**
     * set the remark1
     * @param content new content of remark1
     * Only can be called by owner
     */
    function setRemark1(string content) public onlyOwner onlyValid onlyUnsplitted {
        remark1 = content;
    }

    /**
     * set the remark2
     * @param content new content of remark2
     * Only can be called by owner
     */
    function setRemark2(string content) public onlyOwner onlyValid onlyUnsplitted {
        remark2 = content;
    }

    /**
     * Modify the link of the asset file
     * @param url new link
     * Only can be called by owner
     */
    function setAssetFileLink(string url) public
        onlyOwner
        onlyValid
        onlyUnsplitted
    {
        assetFile.link = url;
        emit TokenUpdateEvent (
            id,
            isValid,
            isTradable,
            owner,
            assetPrice,
            assetFile.link,
            legalFile.link
        );
    }

    /**
     * Modify the link of the legal file
     * @param url new link
     * Only can be called by owner
     */
    function setLegalFileLink(string url)
        public
        onlyOwner
        onlyValid
        onlyUnsplitted
    {
        legalFile.link = url;
        emit TokenUpdateEvent (
            id,
            isValid,
            isTradable,
            owner,
            assetPrice,
            assetFile.link,
            legalFile.link
        );
    }

    /**
     * cancel contract
     * Only can be called by owner
     */
    function cancelContract() public onlyOwner onlyValid onlyUnsplitted {
        isValid = false;
        emit TokenUpdateEvent (
            id,
            isValid,
            isTradable,
            owner,
            assetPrice,
            assetFile.link,
            legalFile.link
        );
    }

    /**
     * overwrite the transferOwnership interface in ownable.
     * Only can transfer when the token is not splitted into small keys.
     * After transfer, the token should be set in "no trading" status.
     */
    function transferOwnership(address newowner) public onlyOwner onlyValid onlyUnsplitted {
        owner = newowner;
        isTradable = false;  // set to false for new owner

        emit TokenUpdateEvent (
            id,
            isValid,
            isTradable,
            owner,
            assetPrice,
            assetFile.link,
            legalFile.link
        );
    }


    /**
     * Buy asset
     */
    function buy() public payable onlyValid onlyUnsplitted {
        require(isTradable == true, "contract is tradeable");
        require(msg.value >= assetPrice, "assetPrice not match");
        address origin_owner = owner;

        owner = msg.sender;
        isTradable = false;  // set to false for new owner

        emit TokenUpdateEvent (
            id,
            isValid,
            isTradable,
            owner,
            assetPrice,
            assetFile.link,
            legalFile.link
        );

        uint priviousBalance = pendingWithdrawals[origin_owner];
        pendingWithdrawals[origin_owner] = priviousBalance.add(assetPrice);
    }

    function withdraw() public {
        uint amount = pendingWithdrawals[msg.sender];

        // Remember to zero the pending refund before sending to prevent re-entrancy attacks
        pendingWithdrawals[msg.sender] = 0;
        msg.sender.transfer(amount);
    }
}
function setLegalFileLink(string url)
    public
    onlyOwner
    onlyValid
    onlyUnsplitted
{
    legalFile.link = url;
    emit TokenUpdateEvent (
        id,
        isValid,
        isTradable,
        owner,
        assetPrice,
        assetFile.link,
        legalFile.link
    );
}

/**
 * Modify the link of the legal file
 * @param url new link
 * Only can be called by owner
 */