contract AlchemyPatent is AlchemyBase {

    // patent struct
    struct Patent {
        // current patent owner
        address patentOwner;
        // the time when owner get the patent
        uint256 beginTime;
        // whether this patent is on sale
        bool onSale; 
        // the sale price
        uint256 price;
        // last deal price
        uint256 lastPrice;
        // the time when this sale is put on
        uint256 sellTime;
    }

    // Creator of each kind of asset
    mapping (uint16 => Patent) public patents;

    // patent fee ratio
    // Values 0-10,000 map to 0%-100%
    uint256 public feeRatio = 9705;

    uint256 public patentValidTime = 2 days;
    uint256 public patentSaleTimeDelay = 2 hours;

    // Event
    event RegisterCreator(address account, uint16 kind);
    event SellPatent(uint16 assetId, uint256 sellPrice);
    event ChangePatentSale(uint16 assetId, uint256 newPrice);
    event BuyPatent(uint16 assetId, address buyer);

    // set the patent fee ratio
    function setPatentFee(uint256 newFeeRatio) external onlyCOO {
        require(newFeeRatio <= 10000);
        feeRatio = newFeeRatio;
    }

    // sell the patent
    function sellPatent(uint16 assetId, uint256 sellPrice) public whenNotPaused {
        Patent memory patent = patents[assetId];
        require(patent.patentOwner == msg.sender);
        if (patent.lastPrice > 0) {
            require(sellPrice <= 2 * patent.lastPrice);
        } else {
            require(sellPrice <= 1 ether);
        }
        
        require(!patent.onSale);

        patent.onSale = true;
        patent.price = sellPrice;
        patent.sellTime = now;

        patents[assetId] = patent;

        // Emit the event
        emit SellPatent(assetId, sellPrice);
    }

    function publicSell(uint16 assetId) public whenNotPaused {
        Patent memory patent = patents[assetId];
        require(patent.patentOwner != address(0));  // this is a valid patent
        require(!patent.onSale);
        require(patent.beginTime + patentValidTime < now);

        patent.onSale = true;
        patent.price = patent.lastPrice;
        patent.sellTime = now;

        patents[assetId] = patent;

        // Emit the event
        emit SellPatent(assetId, patent.lastPrice);
    }

    // change sell price
    function changePatentSale(uint16 assetId, uint256 newPrice) external whenNotPaused {
        Patent memory patent = patents[assetId];
        require(patent.patentOwner == msg.sender);
        if (patent.lastPrice > 0) {
            require(newPrice <= 2 * patent.lastPrice);
        } else {
            require(newPrice <= 1 ether);
        }
        require(patent.onSale == true);

        patent.price = newPrice;

        patents[assetId] = patent;

        // Emit the event
        emit ChangePatentSale(assetId, newPrice);
    }

    // buy patent
    function buyPatent(uint16 assetId) external payable whenNotPaused {
        Patent memory patent = patents[assetId];
        require(patent.patentOwner != address(0));  // this is a valid patent
        require(patent.patentOwner != msg.sender);
        require(patent.onSale);
        require(msg.value >= patent.price);
        require(now >= patent.sellTime + patentSaleTimeDelay);

        patent.patentOwner.transfer(patent.price / 10000 * feeRatio);
        patent.patentOwner = msg.sender;
        patent.beginTime = now;
        patent.onSale = false;
        patent.lastPrice = patent.price;

        patents[assetId] = patent;

        //Emit the event
        emit BuyPatent(assetId, msg.sender);
    }
}
function changePatentSale(uint16 assetId, uint256 newPrice) external whenNotPaused {
    Patent memory patent = patents[assetId];
    require(patent.patentOwner == msg.sender);
    if (patent.lastPrice > 0) {
        require(newPrice <= 2 * patent.lastPrice);
    } else {
        require(newPrice <= 1 ether);
    }
    require(patent.onSale == true);

    patent.price = newPrice;

    patents[assetId] = patent;

    // Emit the event
    emit ChangePatentSale(assetId, newPrice);
}

// change sell price