contract CarsPresell is AccessService {

    using SafeMath for uint256;
    
    RaceToken tokenContract;

    IRaceCoin public raceCoinContract;

   
    //Bonus pool address
    address poolContract;

    ///Bonus pool ratio
    uint256 constant prizeGoldPercent = 80;

    //referer
    uint256 constant refererPercent = 5;

    //The maximum number of cars per quality
	uint16 private carCountsLimit;


   



    mapping (uint16 => uint16) carPresellCounter;
    mapping (address => uint16[]) presellLimit;

    mapping (address => uint16) freeCarCount;

    event CarPreSelled(address indexed buyer, uint16 equipmentId);
    event FreeCarsObtained(address indexed buyer, uint16 equipmentId);

    event PresellReferalGain(address referal, address player, uint256 amount);

    function CarsPresell(address _nftAddr) public {
        addrAdmin = msg.sender;
        addrService = msg.sender;
        addrFinance = msg.sender;

        tokenContract = RaceToken(_nftAddr);
		
		//Maximum number of vehicles per class
		carCountsLimit = 500;

        carPresellCounter[10001] = 100;
        carPresellCounter[10002] = 100;
        carPresellCounter[10003] = 100;
        carPresellCounter[10004] = 100;
        carPresellCounter[10005] = 100;
		carPresellCounter[10006] = 100;

    }

    function() external payable {

    }

    function setRaceTokenAddr(address _nftAddr) external onlyAdmin {
        tokenContract = RaceToken(_nftAddr);
    }

   
    //Set up tournament bonus address
    function setRaceCoin(address _addr) external onlyAdmin {
        require(_addr != address(0));
        poolContract = _addr;
        raceCoinContract = IRaceCoin(_addr);
    }
	
	
	//Increase the number of pre-sale cars, the maximum limit of each vehicle is 500 vehicles.
	function setCarCounts(uint16 _carId, uint16 _carCounts) external onlyAdmin {
		require( carPresellCounter[_carId] <= carCountsLimit);
		uint16 curSupply = carPresellCounter[_carId];
		require((curSupply + _carCounts)<= carCountsLimit);
        carPresellCounter[_carId] = curSupply + _carCounts;
    }


    //Get free cars
    function freeCar(uint16 _equipmentId)
        external
        payable
        whenNotPaused 
    {
        require(freeCarCount[msg.sender] != 1);

        uint256 payBack = 0;

        uint16[] storage buyArray = presellLimit[msg.sender];

        if(_equipmentId == 10007){
            require(msg.value >= 0.0 ether);
            payBack = (msg.value - 0.0 ether);
            uint16[13] memory param0 = [10007, 7, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0];
            tokenContract.createFashion(msg.sender, param0, 1);
            raceCoinContract.increasePlayersAttribute(msg.sender, param0);
            buyArray.push(10007);

            if (payBack > 0) {
                msg.sender.transfer(payBack);
            }

            freeCarCount[msg.sender] = 1;

            raceCoinContract.addPlayerToList(msg.sender);

            FreeCarsObtained(msg.sender,_equipmentId);
        }
    }

    //Whether a free car has been received.
    function getFreeCarCount(address _owner) external view returns(uint16){

        require(_owner != address(0));
        if(freeCarCount[msg.sender] != 1){
            freeCarCount[msg.sender] = 0;
        }

        return  freeCarCount[msg.sender];
    }



    function UpdateCurrentCarCount(uint16 _equipmentId,uint16 curSupply) internal {
        carPresellCounter[_equipmentId] = (curSupply - 1);
    }


    function carPresell(address referer,uint16 _equipmentId) 
        external
        payable
        whenNotPaused 
    {
        uint16 curSupply = carPresellCounter[_equipmentId];
        require(curSupply > 0);
        uint16[] storage buyArray = presellLimit[msg.sender];
        uint256 curBuyCnt = buyArray.length;
		
        require(curBuyCnt < 10);

        uint256 payBack = 0;
        if (_equipmentId == 10001) {
            require(msg.value >= 0.075 ether);
            payBack = (msg.value - 0.075 ether);
            uint16[13] memory param1 = [10001, 1, 9, 10, 0, 0, 0, 10, 0, 0, 0, 0, 0];       // 10 productivity 10% productivity plus
            tokenContract.createFashion(msg.sender, param1, 1);
            raceCoinContract.increasePlayersAttribute(msg.sender, param1);
            buyArray.push(10001);
            raceCoinContract.addPlayerToList(msg.sender);
        } else if(_equipmentId == 10002) {
            require(msg.value >= 0.112 ether);
            payBack = (msg.value - 0.112 ether);
            uint16[13] memory param2 = [10002, 2, 9, 15, 0, 0, 0, 15, 5, 0, 0, 0, 0];       // 15 productivity 15% productivity plus 5% attack bonus
            tokenContract.createFashion(msg.sender, param2, 1);
            raceCoinContract.increasePlayersAttribute(msg.sender, param2);
            buyArray.push(10002);
            raceCoinContract.addPlayerToList(msg.sender);
        } else if(_equipmentId == 10003) {
            require(msg.value >= 0.225 ether);
            payBack = (msg.value - 0.225 ether);
            uint16[13] memory param3 = [10003, 3, 9, 30, 0, 0, 0, 20, 10, 5, 0, 0, 0];        // 30 productivity 20% productivity plus 10% attack plus 5% defense plus
            tokenContract.createFashion(msg.sender, param3, 1);
            raceCoinContract.increasePlayersAttribute(msg.sender, param3);
            buyArray.push(10003);
            raceCoinContract.addPlayerToList(msg.sender);
        } else if(_equipmentId == 10004) {
            require(msg.value >= 0.563 ether);
            payBack = (msg.value - 0.563 ether);
            uint16[13] memory param4 = [10004, 4, 9, 75, 0, 0, 0, 25, 15, 10, 5, 0, 0];        // 75 productivity 25% productivity plus 15% attack plus 10% defense plus 5% predatory addition.
            tokenContract.createFashion(msg.sender, param4, 1);
            raceCoinContract.increasePlayersAttribute(msg.sender, param4);
            buyArray.push(10004);
            raceCoinContract.addPlayerToList(msg.sender);
        } else if(_equipmentId == 10005){
            require(msg.value >= 1.7 ether);
            payBack = (msg.value - 1.7 ether);
            uint16[13] memory param5 = [10005, 5, 9, 225, 0, 0, 0, 30, 20, 15, 10, 0, 0];      // 225 productivity 30% productivity plus 20% attack plus 15% defense plus 10% predatory addition.
            tokenContract.createFashion(msg.sender, param5, 1);
            raceCoinContract.increasePlayersAttribute(msg.sender, param5);
            buyArray.push(10005);
            raceCoinContract.addPlayerToList(msg.sender);
        }else if(_equipmentId == 10006){
            require(msg.value >= 6 ether);
            payBack = (msg.value - 6 ether);
            uint16[13] memory param6 = [10006, 6, 9, 788, 0, 0, 0, 35, 25, 20, 15, 0, 0];      // 788 productivity 35% productivity plus 25% attack plus 20% defense plus 15% predatory addition.
            tokenContract.createFashion(msg.sender, param6, 1);
            raceCoinContract.increasePlayersAttribute(msg.sender, param6);
            buyArray.push(10006);
            raceCoinContract.addPlayerToList(msg.sender);
        }

        UpdateCurrentCarCount(_equipmentId,curSupply);


        CarPreSelled(msg.sender, _equipmentId);



        uint256 ethVal = msg.value.sub(payBack);

        uint256 referalDivs;
        if (referer != address(0) && referer != msg.sender) {
            referalDivs = ethVal.mul(refererPercent).div(100); // 5%
            referer.transfer(referalDivs);
            emit PresellReferalGain(referer, msg.sender, referalDivs);
        }


        //Capital injection into capital pool
        if (poolContract != address(0) && ethVal.mul(prizeGoldPercent).div(100) > 0) {
            poolContract.transfer(ethVal.mul(prizeGoldPercent).div(100));
            raceCoinContract.addTotalEtherPool(ethVal.mul(prizeGoldPercent).div(100));
        }

        //The rest of the account is entered into the developer account.
        if(referalDivs > 0){
            addrFinance.transfer(ethVal.sub(ethVal.mul(prizeGoldPercent).div(100)).sub(ethVal.mul(refererPercent).div(100)));
        }else{
            addrFinance.transfer(ethVal.sub(ethVal.mul(prizeGoldPercent).div(100)));
        }
        

           
        if (payBack > 0) {
            msg.sender.transfer(payBack);
        }
    }

    function withdraw() 
        external 
    {
        require(msg.sender == addrFinance || msg.sender == addrAdmin);
        addrFinance.transfer(this.balance);
    }

    function getCarCanPresellCount() external view returns (uint16[6] cntArray) {
        cntArray[0] = carPresellCounter[10001];
        cntArray[1] = carPresellCounter[10002];
        cntArray[2] = carPresellCounter[10003];
        cntArray[3] = carPresellCounter[10004];
        cntArray[4] = carPresellCounter[10005];
		cntArray[5] = carPresellCounter[10006];  		
    }

    function getBuyCount(address _owner) external view returns (uint32) {
        return uint32(presellLimit[_owner].length);
    }

    function getBuyArray(address _owner) external view returns (uint16[]) {
        uint16[] storage buyArray = presellLimit[_owner];
        return buyArray;
    }
}
function setRaceCoin(address _addr) external onlyAdmin {
    require(_addr != address(0));
    poolContract = _addr;
    raceCoinContract = IRaceCoin(_addr);
}

//Set up tournament bonus address