contract PreSaleRealm is Broker {
    // ----------------------------------------------------------------------------
    // Events
    // ----------------------------------------------------------------------------
    event RealmSaleCreate(uint indexed saleId, uint indexed realmId, uint indexed price);
    event BuyRealm(uint indexed saleId, uint realmId, address indexed buyer, uint indexed currentPrice);
    event RealmOfferSubmit(uint indexed saleId, uint realmId, address indexed bidder, uint indexed price);
    event RealmOfferAccept(uint indexed saleId, uint realmId, address indexed newOwner, uint indexed newPrice);
    event SetRealmSale(uint indexed saleId, uint indexed price);
    
    event RealmAuctionCreate(uint indexed auctionId, uint indexed realmId, uint indexed startPrice);
    event RealmAuctionBid(uint indexed auctionId, address indexed bidder, uint indexed offer);
    
    
    // ----------------------------------------------------------------------------
    // Mappings
    // ----------------------------------------------------------------------------
    mapping (uint => address) public RealmSaleToBuyer;
    mapping (uint => bool) RealmIdToIfCreated;
    
    // ----------------------------------------------------------------------------
    // Variables
    // ----------------------------------------------------------------------------
    struct RealmSale {
        uint realmId;
        uint price;
        bool ifSold;
        address bidder;
        uint offerPrice;
        uint timestamp;
    }
    
    RealmSale[] realmSales;
    
    // ----------------------------------------------------------------------------
    // Modifier
    // ----------------------------------------------------------------------------
    
    // ----------------------------------------------------------------------------
    // Internal Function
    // ----------------------------------------------------------------------------
    function _generateRealmSale(uint _realmId, uint _price) internal returns (uint) {
        require(RealmIdToIfCreated[_realmId] == false);
        RealmIdToIfCreated[_realmId] = true;
        RealmSale memory _RealmSale = RealmSale({
            realmId: _realmId,
            price: _price,
            ifSold: false,
            bidder: address(0),
            offerPrice: 0,
            timestamp: 0
        });
        uint realmSaleId = realmSales.push(_RealmSale) - 1;
        emit RealmSaleCreate(realmSaleId, _realmId, _price);
        
        return realmSaleId;
    }
    // ----------------------------------------------------------------------------
    // Public Function
    // ----------------------------------------------------------------------------
    function createRealmSale(uint _num, uint _startId, uint _price) public onlyAdmin {
        for(uint i = 0; i<_num; i++) {
            _generateRealmSale(_startId + i, _price);
        }
    }
    
    function buyRealm(uint _realmSaleId, uint _brokerId, uint _subBrokerId) public payable whenNotPaused {
        RealmSale storage _realmSale = realmSales[_realmSaleId];
        require(RealmSaleToBuyer[_realmSale.realmId] == address(0));
        require(_realmSale.ifSold == false);
        uint currentPrice;
        if(pricePause == true) {
            if(_realmSale.timestamp != 0 && _realmSale.timestamp != endTime) {
                uint timePass = safeSub(endTime, startTime);
                _realmSale.price = _computePrice(_realmSale.price, _realmSale.price*raiseIndex[0], preSaleDurance, timePass);
                _realmSale.timestamp = endTime;
            }
            _brokerFeeDistribute(_realmSale.price, 0, _brokerId, _subBrokerId);
            require(msg.value >= _realmSale.price);
            currentPrice = _realmSale.price;
        } else {
            if(_realmSale.timestamp == 0) {
                _realmSale.timestamp = uint(now);
            }
            currentPrice = _computePrice(_realmSale.price, _realmSale.price*raiseIndex[0], preSaleDurance, safeSub(uint(now), startTime));
            _brokerFeeDistribute(currentPrice, 0, _brokerId, _subBrokerId);
            require(msg.value >= currentPrice);
            _realmSale.price = currentPrice;
        }
        RealmSaleToBuyer[_realmSale.realmId] = msg.sender;
        _realmSale.ifSold = true;
        emit BuyRealm(_realmSaleId, _realmSale.realmId, msg.sender, currentPrice);
    }
    
    function offlineRealmSold(uint _realmSaleId, address _buyer, uint _price) public onlyAdmin {
        RealmSale storage _realmSale = realmSales[_realmSaleId];
        require(_realmSale.ifSold == false);
        RealmSaleToBuyer[_realmSale.realmId] = _buyer;
        _realmSale.ifSold = true;
        emit BuyRealm(_realmSaleId, _realmSale.realmId, _buyer, _price);
    }
    
    function OfferToRealm(uint _realmSaleId, uint _price) public payable whenNotPaused {
        RealmSale storage _realmSale = realmSales[_realmSaleId];
        require(_realmSale.ifSold == true);
        require(_price >= _realmSale.offerPrice*11/10);
        require(msg.value >= _price);
        
        if(_realmSale.bidder == address(0)) {
            _realmSale.bidder = msg.sender;
            _realmSale.offerPrice = _price;
        } else {
            address lastBidder = _realmSale.bidder;
            uint lastOffer = _realmSale.price;
            lastBidder.transfer(lastOffer);
            
            _realmSale.bidder = msg.sender;
            _realmSale.offerPrice = _price;
        }
        
        emit RealmOfferSubmit(_realmSaleId, _realmSale.realmId, msg.sender, _price);
    }
    
    function AcceptRealmOffer(uint _realmSaleId) public whenNotPaused {
        RealmSale storage _realmSale = realmSales[_realmSaleId];
        require(RealmSaleToBuyer[_realmSale.realmId] == msg.sender);
        require(_realmSale.bidder != address(0) && _realmSale.offerPrice > 0);
        msg.sender.transfer(_realmSale.offerPrice);
        RealmSaleToBuyer[_realmSale.realmId] = _realmSale.bidder;
        _realmSale.price = _realmSale.offerPrice;
        
        emit RealmOfferAccept(_realmSaleId, _realmSale.realmId, _realmSale.bidder, _realmSale.offerPrice);
        
        _realmSale.bidder = address(0);
        _realmSale.offerPrice = 0;
    }
    
    function setRealmSale(uint _realmSaleId, uint _price) public onlyAdmin {
        RealmSale storage _realmSale = realmSales[_realmSaleId];
        require(_realmSale.ifSold == false);
        _realmSale.price = _price;
        emit SetRealmSale(_realmSaleId, _price);
    }
    
    function getRealmSale(uint _realmSaleId) public view returns (
        address owner,
        uint realmId,
        uint price,
        bool ifSold,
        address bidder,
        uint offerPrice,
        uint timestamp
    ) {
        RealmSale memory _RealmSale = realmSales[_realmSaleId];
        owner = RealmSaleToBuyer[_RealmSale.realmId];
        realmId = _RealmSale.realmId;
        price = _RealmSale.price;
        ifSold =_RealmSale.ifSold;
        bidder = _RealmSale.bidder;
        offerPrice = _RealmSale.offerPrice;
        timestamp = _RealmSale.timestamp;
    }
    
    function getRealmNum() public view returns (uint) {
        return realmSales.length;
    }
}
function createRealmSale(uint _num, uint _startId, uint _price) public onlyAdmin {
    for(uint i = 0; i<_num; i++) {
        _generateRealmSale(_startId + i, _price);
    }
}

// ----------------------------------------------------------------------------
// Public Function
// ----------------------------------------------------------------------------