contract PreSaleGuardian is PreSaleCastle {
    // ----------------------------------------------------------------------------
    // Events
    // ----------------------------------------------------------------------------
    event GuardianSaleCreate(uint indexed saleId, uint indexed guardianId, uint indexed price, uint race, uint level, uint starRate);
    event BuyGuardian(uint indexed saleId, uint guardianId, address indexed buyer, uint indexed currentPrice);
    event GuardianOfferSubmit(uint indexed saleId, uint guardianId, address indexed bidder, uint indexed price);
    event GuardianOfferAccept(uint indexed saleId, uint guardianId, address indexed newOwner, uint indexed newPrice);
    event SetGuardianSale(uint indexed saleId, uint indexed price);
    
    event GuardianAuctionCreate(uint indexed auctionId, uint indexed guardianId, uint indexed startPrice, uint race, uint level, uint starRate);
    event GuardianAuctionBid(uint indexed auctionId, address indexed bidder, uint indexed offer);
    
    event VendingGuardian(uint indexed vendingId, address indexed buyer);
    event GuardianVendOffer(uint indexed vendingId, address indexed bidder, uint indexed offer);
    event GuardianVendAccept(uint indexed vendingId, address indexed newOwner, uint indexed newPrice);
    event SetGuardianVend(uint indexed priceId, uint indexed price);
    
    // ----------------------------------------------------------------------------
    // Mappings
    // ----------------------------------------------------------------------------
    mapping (uint => address) public GuardianSaleToBuyer;
    
    mapping (uint => uint) public GuardianVendToOffer;
    mapping (uint => address) public GuardianVendToBidder;
    mapping (uint => uint) public GuardianVendToTime;
    
    // ----------------------------------------------------------------------------
    // Variables
    // ----------------------------------------------------------------------------
    struct GuardianSale {
        uint guardianId;
        uint race;
        uint starRate;
        uint level;
        uint price;
        bool ifSold;
        address bidder;
        uint offerPrice;
        uint timestamp;
    }
    
    GuardianSale[] guardianSales;

    uint[5] GuardianVending = [
        0.5 ether,
        0.35 ether,
        0.20 ether,
        0.15 ether,
        0.1 ether
    ];
    
    // ----------------------------------------------------------------------------
    // Modifier
    // ----------------------------------------------------------------------------
    
    // ----------------------------------------------------------------------------
    // Internal Function
    // ----------------------------------------------------------------------------
    function _generateGuardianSale(uint _guardianId, uint _race, uint _starRate, uint _level, uint _price) internal returns (uint) {
        GuardianSale memory _GuardianSale = GuardianSale({
            guardianId: _guardianId,
            race: _race,
            starRate: _starRate,
            level: _level,
            price: _price,
            ifSold: false,
            bidder: address(0),
            offerPrice: 0,
            timestamp: 0
        });
        uint guardianSaleId = guardianSales.push(_GuardianSale) - 1;
        emit GuardianSaleCreate(guardianSaleId, _guardianId, _price, _race, _level, _starRate);
        
        return guardianSaleId;
    }
    
    function _guardianVendPrice(uint _guardianId , uint _level) internal returns (uint) {
        if(pricePause == true) {
            if(GuardianVendToTime[_guardianId] != 0 && GuardianVendToTime[_guardianId] != endTime) {
                uint timePass = safeSub(endTime, startTime);
                GuardianVending[_level] = _computePrice(GuardianVending[_level], GuardianVending[_level]*raiseIndex[1], preSaleDurance, timePass);
                GuardianVendToTime[_guardianId] = endTime;
            }
            return GuardianVending[_level];
        } else {
            if(GuardianVendToTime[_guardianId] == 0) {
                GuardianVendToTime[_guardianId] = uint(now);
            }
            uint currentPrice = _computePrice(GuardianVending[_level], GuardianVending[_level]*raiseIndex[1], preSaleDurance, safeSub(uint(now), startTime));
            return currentPrice;
        }
    }
    
    // ----------------------------------------------------------------------------
    // Public Function
    // ----------------------------------------------------------------------------
    function createGuardianSale(uint _num, uint _startId, uint _race, uint _starRate, uint _level, uint _price) public onlyAdmin {
        for(uint i = 0; i<_num; i++) {
            _generateGuardianSale(_startId + i, _race, _starRate, _level, _price);
        }
    }
    
    function buyGuardian(uint _guardianSaleId, uint _brokerId, uint _subBrokerId) public payable whenNotPaused {
        GuardianSale storage _guardianSale = guardianSales[_guardianSaleId];
        require(GuardianSaleToBuyer[_guardianSale.guardianId] == address(0));
        require(_guardianSale.ifSold == false);
        uint currentPrice;
        if(pricePause == true) {
            if(_guardianSale.timestamp != 0 && _guardianSale.timestamp != endTime) {
                uint timePass = safeSub(endTime, startTime);
                _guardianSale.price = _computePrice(_guardianSale.price, _guardianSale.price*raiseIndex[1], preSaleDurance, timePass);
                _guardianSale.timestamp = endTime;
            }
            _brokerFeeDistribute(_guardianSale.price, 1, _brokerId, _subBrokerId);
            require(msg.value >= _guardianSale.price);
            currentPrice = _guardianSale.price;
        } else {
            if(_guardianSale.timestamp == 0) {
                _guardianSale.timestamp = uint(now);
            }
            currentPrice = _computePrice(_guardianSale.price, _guardianSale.price*raiseIndex[1], preSaleDurance, safeSub(uint(now), startTime));
            _brokerFeeDistribute(currentPrice, 1, _brokerId, _subBrokerId);
            require(msg.value >= currentPrice);
            _guardianSale.price = currentPrice;
        }
        GuardianSaleToBuyer[_guardianSale.guardianId] = msg.sender;
        _guardianSale.ifSold = true;
        emit BuyGuardian(_guardianSaleId, _guardianSale.guardianId, msg.sender, currentPrice);
    }
    
    function offlineGuardianSold(uint _guardianSaleId, address _buyer, uint _price) public onlyAdmin {
        GuardianSale storage _guardianSale = guardianSales[_guardianSaleId];
        require(_guardianSale.ifSold == false);
        GuardianSaleToBuyer[_guardianSale.guardianId] = _buyer;
        _guardianSale.ifSold = true;
        emit BuyGuardian(_guardianSaleId, _guardianSale.guardianId, _buyer, _price);
    }
    
    function OfferToGuardian(uint _guardianSaleId, uint _price) public payable whenNotPaused {
        GuardianSale storage _guardianSale = guardianSales[_guardianSaleId];
        require(_guardianSale.ifSold == true);
        require(_price > _guardianSale.offerPrice*11/10);
        require(msg.value >= _price);
        
        if(_guardianSale.bidder == address(0)) {
            _guardianSale.bidder = msg.sender;
            _guardianSale.offerPrice = _price;
        } else {
            address lastBidder = _guardianSale.bidder;
            uint lastOffer = _guardianSale.price;
            lastBidder.transfer(lastOffer);
            
            _guardianSale.bidder = msg.sender;
            _guardianSale.offerPrice = _price;
        }
        
        emit GuardianOfferSubmit(_guardianSaleId, _guardianSale.guardianId, msg.sender, _price);
    }
    
    function AcceptGuardianOffer(uint _guardianSaleId) public whenNotPaused {
        GuardianSale storage _guardianSale = guardianSales[_guardianSaleId];
        require(GuardianSaleToBuyer[_guardianSale.guardianId] == msg.sender);
        require(_guardianSale.bidder != address(0) && _guardianSale.offerPrice > 0);
        msg.sender.transfer(_guardianSale.offerPrice);
        GuardianSaleToBuyer[_guardianSale.guardianId] = _guardianSale.bidder;
        _guardianSale.price = _guardianSale.offerPrice;
        
        emit GuardianOfferAccept(_guardianSaleId, _guardianSale.guardianId, _guardianSale.bidder, _guardianSale.price);
        
        _guardianSale.bidder = address(0);
        _guardianSale.offerPrice = 0;
    }
    
    function setGuardianSale(uint _guardianSaleId, uint _price) public onlyAdmin {
        GuardianSale storage _guardianSale = guardianSales[_guardianSaleId];
        require(_guardianSale.ifSold == false);
        _guardianSale.price = _price;
        emit SetGuardianSale(_guardianSaleId, _price);
    }
    
    function getGuardianSale(uint _guardianSaleId) public view returns (
        address owner,
        uint guardianId,
        uint race,
        uint starRate,
        uint level,
        uint price,
        bool ifSold,
        address bidder,
        uint offerPrice,
        uint timestamp
    ) {
        GuardianSale memory _GuardianSale = guardianSales[_guardianSaleId];
        owner = GuardianSaleToBuyer[_GuardianSale.guardianId];
        guardianId = _GuardianSale.guardianId;
        race = _GuardianSale.race;
        starRate = _GuardianSale.starRate;
        level = _GuardianSale.level;
        price = _GuardianSale.price;
        ifSold =_GuardianSale.ifSold;
        bidder = _GuardianSale.bidder;
        offerPrice = _GuardianSale.offerPrice;
        timestamp = _GuardianSale.timestamp;
    }
    
    function getGuardianNum() public view returns (uint) {
        return guardianSales.length;
    }

    function vendGuardian(uint _guardianId) public payable whenNotPaused {
        require(_guardianId > 1000 && _guardianId <= 6000);
        if(_guardianId > 1000 && _guardianId <= 2000) {
            require(GuardianSaleToBuyer[_guardianId] == address(0));
            require(msg.value >= _guardianVendPrice(_guardianId, 0));
            GuardianSaleToBuyer[_guardianId] = msg.sender;
            GuardianVendToOffer[_guardianId] = GuardianVending[0];
        } else if (_guardianId > 2000 && _guardianId <= 3000) {
            require(GuardianSaleToBuyer[_guardianId] == address(0));
            require(msg.value >= _guardianVendPrice(_guardianId, 1));
            GuardianSaleToBuyer[_guardianId] = msg.sender;
            GuardianVendToOffer[_guardianId] = GuardianVending[1];
        } else if (_guardianId > 3000 && _guardianId <= 4000) {
            require(GuardianSaleToBuyer[_guardianId] == address(0));
            require(msg.value >= _guardianVendPrice(_guardianId, 2));
            GuardianSaleToBuyer[_guardianId] = msg.sender;
            GuardianVendToOffer[_guardianId] = GuardianVending[2];
        } else if (_guardianId > 4000 && _guardianId <= 5000) {
            require(GuardianSaleToBuyer[_guardianId] == address(0));
            require(msg.value >= _guardianVendPrice(_guardianId, 3));
            GuardianSaleToBuyer[_guardianId] = msg.sender;
            GuardianVendToOffer[_guardianId] = GuardianVending[3];
        } else if (_guardianId > 5000 && _guardianId <= 6000) {
            require(GuardianSaleToBuyer[_guardianId] == address(0));
            require(msg.value >= _guardianVendPrice(_guardianId, 4));
            GuardianSaleToBuyer[_guardianId] = msg.sender;
            GuardianVendToOffer[_guardianId] = GuardianVending[4];
        }
        emit VendingGuardian(_guardianId, msg.sender);
    }
    
    function offerGuardianVend(uint _guardianId, uint _offer) public payable whenNotPaused {
        require(GuardianSaleToBuyer[_guardianId] != address(0));
        require(_offer >= GuardianVendToOffer[_guardianId]*11/10);
        require(msg.value >= _offer);
        address lastBidder = GuardianVendToBidder[_guardianId];
        if(lastBidder != address(0)){
            lastBidder.transfer(GuardianVendToOffer[_guardianId]);
        }
        GuardianVendToBidder[_guardianId] = msg.sender;
        GuardianVendToOffer[_guardianId] = _offer;
        emit GuardianVendOffer(_guardianId, msg.sender, _offer);
    }
    
    function acceptGuardianVend(uint _guardianId) public whenNotPaused {
        require(GuardianSaleToBuyer[_guardianId] == msg.sender);
        address bidder = GuardianVendToBidder[_guardianId];
        uint offer = GuardianVendToOffer[_guardianId];
        require(bidder != address(0) && offer > 0);
        msg.sender.transfer(offer);
        GuardianSaleToBuyer[_guardianId] = bidder;
        GuardianVendToBidder[_guardianId] = address(0);
        GuardianVendToOffer[_guardianId] = 0;
        emit GuardianVendAccept(_guardianId, bidder, offer);
    }
    
    function setGuardianVend(uint _num, uint _price) public onlyAdmin {
        GuardianVending[_num] = _price;
        emit SetGuardianVend(_num, _price);
    }
    
    function getGuardianVend(uint _guardianId) public view returns (
        address owner,
        address bidder,
        uint offer
    ) {
        owner = GuardianSaleToBuyer[_guardianId];
        bidder = GuardianVendToBidder[_guardianId];
        offer = GuardianVendToOffer[_guardianId];
    }
}
function _generateGuardianSale(uint _guardianId, uint _race, uint _starRate, uint _level, uint _price) internal returns (uint) {
    GuardianSale memory _GuardianSale = GuardianSale({
        guardianId: _guardianId,
        race: _race,
        starRate: _starRate,
        level: _level,
        price: _price,
        ifSold: false,
        bidder: address(0),
        offerPrice: 0,
        timestamp: 0
    });
    uint guardianSaleId = guardianSales.push(_GuardianSale) - 1;
    emit GuardianSaleCreate(guardianSaleId, _guardianId, _price, _race, _level, _starRate);
        
    return guardianSaleId;
}

// ----------------------------------------------------------------------------
// Modifier
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Internal Function
// ----------------------------------------------------------------------------