library BdpCalculator {

	using SafeMath for uint256;

	function calculateArea(address[16] _contracts, uint256 _regionId) view public returns (uint256 _area, uint256 _width, uint256 _height) {
		var (x1, y1, x2, y2) = BdpDataStorage(BdpContracts.getBdpDataStorage(_contracts)).getRegionCoordinates(_regionId);
		_width = x2 - x1 + 1;
		_height = y2 - y1 + 1;
		_area = _width * _height;
	}

	function countPurchasedPixels(address[16] _contracts) view public returns (uint256 _count) {
		var lastRegionId = BdpDataStorage(BdpContracts.getBdpDataStorage(_contracts)).getLastRegionId();
		for (uint256 i = 0; i <= lastRegionId; i++) {
			if(BdpDataStorage(BdpContracts.getBdpDataStorage(_contracts)).getRegionPurchasedAt(i) > 0) { // region is purchased
				var (area,,) = calculateArea(_contracts, i);
				_count += area;
			}
		}
	}

	function calculateCurrentMarketPixelPrice(address[16] _contracts) view public returns(uint) {
		return calculateMarketPixelPrice(_contracts, countPurchasedPixels(_contracts));
	}

	function calculateMarketPixelPrice(address[16] _contracts, uint _pixelsSold) view public returns(uint) {
		var pricePointsLength = BdpPriceStorage(BdpContracts.getBdpPriceStorage(_contracts)).getPricePointsLength();
		uint mod = _pixelsSold % (1000000 / (pricePointsLength - 1));
		uint div = _pixelsSold * (pricePointsLength - 1) / 1000000;
		var divPoint = BdpPriceStorage(BdpContracts.getBdpPriceStorage(_contracts)).getPricePoint(div);
		if(mod == 0) return divPoint;
		return divPoint + mod * (BdpPriceStorage(BdpContracts.getBdpPriceStorage(_contracts)).getPricePoint(div+1) - divPoint) * (pricePointsLength - 1) / 1000000;
	}

	function calculateAveragePixelPrice(address[16] _contracts, uint _a, uint _b) view public returns (uint _price) {
		_price = (calculateMarketPixelPrice(_contracts, _a) + calculateMarketPixelPrice(_contracts, _b)) / 2;
	}

	/** Current market price per pixel for this region if it is the first sale of this region
	  */
	function calculateRegionInitialSalePixelPrice(address[16] _contracts, uint256 _regionId) view public returns (uint256) {
		require(BdpDataStorage(BdpContracts.getBdpDataStorage(_contracts)).getRegionUpdatedAt(_regionId) > 0); // region exists
		var purchasedPixels = countPurchasedPixels(_contracts);
		var (area,,) = calculateArea(_contracts, _regionId);
		return calculateAveragePixelPrice(_contracts, purchasedPixels, purchasedPixels + area);
	}

	/** Current market price or (Current market price)*3 if the region was sold
	  */
	function calculateRegionSalePixelPrice(address[16] _contracts, uint256 _regionId) view public returns (uint256) {
		var pixelPrice = BdpDataStorage(BdpContracts.getBdpDataStorage(_contracts)).getRegionCurrentPixelPrice(_regionId);
		if(pixelPrice > 0) {
			return pixelPrice * 3;
		} else {
			return calculateRegionInitialSalePixelPrice(_contracts, _regionId);
		}
	}

	/** Setup is allowed one whithin one day after purchase
	  */
	function calculateSetupAllowedUntil(address[16] _contracts, uint256 _regionId) view public returns (uint256) {
		var (updatedAt, purchasedAt) = BdpDataStorage(BdpContracts.getBdpDataStorage(_contracts)).getRegionUpdatedAtPurchasedAt(_regionId);
		if(updatedAt != purchasedAt) {
			return 0;
		} else {
			return purchasedAt + 1 days;
		}
	}

}
function calculateRegionInitialSalePixelPrice(address[16] _contracts, uint256 _regionId) view public returns (uint256) {
	require(BdpDataStorage(BdpContracts.getBdpDataStorage(_contracts)).getRegionUpdatedAt(_regionId) > 0); // region exists
	var purchasedPixels = countPurchasedPixels(_contracts);
	var (area,,) = calculateArea(_contracts, _regionId);
	return calculateAveragePixelPrice(_contracts, purchasedPixels, purchasedPixels + area);
}

/** Current market price per pixel for this region if it is the first sale of this region
 	  */