<?
function simulateRegionUntilConstruction($regionId, $until) {
	include("serverConnect.php");

	$buildings = getBuildingsList();

	do {
		$construction = true;

	    $req = $bdd->prepare('SELECT MIN(cBuildingConstructions.timeFinished) AS T FROM cBuildingConstructions WHERE territory >= ? AND territory <= ? ');
		$req->execute(array(getMinTerritoryId($regionId), getMaxTerritoryId($regionId)));
		$data = $req->fetch();

		$t = nullIsZero($data['T']);

		if ($t == 0 || $t > $until) {
		    $t = $until;
		    $construction = false;
		}

		$result = simulateRegion($regionId, $t);

		if ($construction) {
			$req = $bdd->prepare('SELECT * FROM cBuildingConstructions WHERE territory >= ? AND territory <= ? AND timeFinished = ?');
	        $req->execute(array(getMinTerritoryId($regionId), getMaxTerritoryId($regionId), $t));
	        
	        while ($data = $req->fetch()) {
	            $production = 0;
	            
	            if (array_key_exists("production", $buildings[$data['type']])) {
	                foreach ($buildings[$data['type']]["production"] as $key => $prod) {
	                    $production = getResourceId($key);
	                }
	            }
	            
	            $req2 = $bdd->prepare('INSERT INTO cBuildings (territory, type, production) VALUES(?, ?, ?)');
	            $req2->execute(array($data['territory'], $data['type'], $production));
	            
	            $req2 = $bdd->prepare('DELETE FROM cBuildingConstructions WHERE territory = ?');
	            $req2->execute(array($data['territory']));
	        }

		}
		
	} while ($t < $until);

	return $result;
}

function simulateRegion($regionId, $until) {
	include("serverConnect.php");
    
    $regionInfo = [
        "current" => [],
        "gained" => [],
        "populationConsumption" => [],
        "owner" => 0,
        "currentInfluences" => [],
        "gainedInfluences" => [],
        "agricultureEfficiency" => [],
        "mineralEfficiency" => [],
        "buildingsProductionAmount" => [],
        "buildingsProductionResource" => [],
        "buildingsEfficiency" => [],
        "buildingsResourcesNeeded" => [],
        "buildingsHappiness" => [],
        "buildingsAdjacentHappiness" => [],
        "buildingsPopulation" => [],
        "happiness" => 0,
        "happinessGrowth" => 0,
        "happinessBonus" => 0,
        "population" => 0,
        "populationGrowth" => 0
    ];
    
    $req = $bdd->prepare('SELECT cRegions.time AS TIME, cRegions.owner AS OWNER, cRegions.happiness AS HAP, cRegions.population AS POP, cRegions.temperature AS TEMP, cRegions.precipitation AS PREC, cRegions.mineralSolidity AS SOLI, cRegions.mineralValue AS VALU FROM cRegions WHERE cRegions.id = ?');
    $req->execute(array($regionId));
    $data = $req->fetch();
    
    $happiness = $data['HAP'];
    $population = $data['POP'];
    
    $temperature = $data['TEMP'];
    $precipitation = $data['PREC'];
    
    $mineralSolidity = $data['SOLI'];
    $mineralValue = $data['VALU'];

    $regionInfo["owner"] = $data['OWNER'];

    $deltaTime = $until - $data['TIME'];
    $time = $data['TIME'];
    
    //------------------------------------------------------------------------------------
    //Efficiency of agriculture and minerals
    //------------------------------------------------------------------------------------

    $efficiencies = [];
    $resources = getResourcesList();
    foreach ($resources as $key => $r) {
        
        if (is_int($key) && $key != 0) {
            $dTemperature = 0;
            if (array_key_exists("temperature", $r)) {
                $dTemperature = abs($temperature - $r["temperature"]) / 100;
            }
            $dPrecipitation = 0;
            if (array_key_exists("precipitation", $r)) {
                $dPrecipitation = abs($precipitation - $r["precipitation"]) / 100;
            }
            
            $dMineralSolidity = 0;
            if (array_key_exists("mineralSolidity", $r)) {
                $dMineralSolidity = abs($mineralSolidity - $r["mineralSolidity"]) / 100;
            }
            $dMineralValue = 0;
            if (array_key_exists("mineralValue", $r)) {
                $dMineralValue = abs($mineralValue - $r["mineralValue"]) / 100;
            }
            
            $dTot = $dTemperature*$dTemperature + $dPrecipitation*$dPrecipitation + $dMineralSolidity*$dMineralSolidity + $dMineralValue*$dMineralValue;
            $dTot = min($dTot, 1);
            
            $ratio = 1;
            if (array_key_exists("adaptability", $r) && array_key_exists("limitUp", $r) && array_key_exists("limitDown", $r)) {
                $ratio = pow((1-$dTot), $r["adaptability"]);
                
                if ($ratio > $r["limitUp"]) {
                    $ratio = 1;
                }
                else if ($ratio < $r["limitDown"]) {
                    $ratio = 0;
                }
            }
            
            $efficiencies[$key] = $ratio;
            
            if (array_key_exists("temperature", $r)) {
                $regionInfo["agricultureEfficiency"][$key] = $ratio;
            }
            else if (array_key_exists("mineralSolidity", $r)) {
                $regionInfo["mineralEfficiency"][$key] = $ratio;
            }
        }
    }

    if ($data['OWNER'] == 0) {
        return simulateInfluence($regionId, $until, $data['TIME'], $regionInfo);
    }

    //------------------------------------------------------------------------------------
    //Buildings
    //------------------------------------------------------------------------------------

    $localBuildings = [];
	$buildings = getBuildingsList();
	
    $req = $bdd->prepare('SELECT cBuildings.territory AS TERR, cBuildings.type AS BTYPE, cBuildings.production AS PROD, cDeposits.resource AS DEPR, cDeposits.concentration AS DEPC FROM cTerritories JOIN cBuildings on cTerritories.id = cBuildings.territory LEFT JOIN cDeposits ON cTerritories.id = cDeposits.territory WHERE cTerritories.id >= ? AND cTerritories.id <= ?');
    $req->execute(array(getMinTerritoryId($regionId), getMaxTerritoryId($regionId)));
    while ($data = $req->fetch()) {
    	$localBuildings[] = $data['TERR'];
        
        $regionInfo["buildingsEfficiency"][$data['TERR']] = 1;
        $regionInfo["buildingsProductionResource"][$data['TERR']] = $data['PROD'];
        
        $building = $buildings[$data['BTYPE']];
        $resourceName = $resources[$data['PROD']]["shortName"];
        
        //Adjacent buildings
        $adjacentRatioProduction = 1;
        $nei = getNeighbourgs($data['TERR']);
        
        foreach ($nei as $idNei) {
            $req2 = $bdd->prepare('SELECT cBuildings.type AS BTYPE FROM cBuildings WHERE cBuildings.territory = ?');
            $req2->execute(array($idNei));

            if ($data2 = $req2->fetch()) {
                $bonusMalus = buildingBonuses($buildings[$data2['BTYPE']]["color"], $building["color"]);

                $adjacentRatioProduction += $bonusMalus["production"];
                $regionInfo["buildingsAdjacentHappiness"][$data['TERR']] += $bonusMalus["happiness"];
            }
        }

        if (array_key_exists("population", $building)) { //population buildings
            $regionInfo["buildingsPopulation"][$data['TERR']] += $building["population"];
        }
        else if (array_key_exists("happiness", $building)) { //happiness buildings
            $regionInfo["buildingsHappiness"][$data['TERR']] += $building["happiness"];
        }
        else if (array_key_exists("production", $building)) { //Production
        	
        	$regionInfo["buildingsProductionAmount"][$data['TERR']] = prodPerSec($building["production"][$resourceName]["amount"]);

            if (empty($building["production"][$resourceName]["resourcesNeeded"])) { // mines or farms
                
                $depositRatio = 1;
                if (array_key_exists("deposit", $resources[$data['PROD']]) && $resources[$data['PROD']]["deposit"]) {
                    $r = nullIsZero($data['DEPR']);
                    if ($r != $data['PROD']) { //deposits does not exist or not the right type
                        $depositRatio = 0;
                    }
                    else {
                        $depositRatio = $data['DEPC'] / 100;
                    }
                }
                $regionInfo["buildingsEfficiency"][$data['TERR']] = $efficiencies[$data['PROD']] * $depositRatio * $adjacentRatioProduction;
            }
            else { //plants

            	$regionInfo["buildingsResourcesNeeded"][$data['TERR']] = [];
                
                foreach($building["production"][$resourceName]["resourcesNeeded"] as $key => $resourceNeeded) {
                    $regionInfo["buildingsResourcesNeeded"][$data['TERR']][getResourceId($key)] = prodPerSec($resourceNeeded);
                }
                
                $regionInfo["buildingsEfficiency"][$data['TERR']] = $adjacentRatioProduction;
            }
        }
    }

    //------------------------------------------------------------------------------------
    //Current resources
    //------------------------------------------------------------------------------------


    $req = $bdd->prepare('SELECT * FROM cRegionResources WHERE region = ?');
    $req->execute(array($regionId));
    while ($data = $req->fetch()) {
        $regionInfo["current"][$data['resource']] = $data['amount'];
    }

    //------------------------------------------------------------------------------------
    //Actual simulation
    //------------------------------------------------------------------------------------

    do {
    	//calculate derivatives
    	$regionInfo["gained"] = [];
    	$theoreticalHappiness = 30;
        $theoreticalPopulation = 10;

        //Buildings
    	foreach ($localBuildings as $building) {
    		
    		$theoreticalHappiness += $regionInfo["buildingsAdjacentHappiness"][$building];
    		

    		$resource = $regionInfo["buildingsProductionResource"][$building];
    		$amount = $regionInfo["buildingsProductionAmount"][$building];
    		$efficiency = $regionInfo["buildingsEfficiency"][$building];

    		if ($resource == 0) {
				$theoreticalPopulation += $regionInfo["buildingsPopulation"][$building];
				$theoreticalHappiness += $regionInfo["buildingsHappiness"][$building];
    		}
    		else if (empty($regionInfo["buildingsResourcesNeeded"][$building])) { //mine or farm
    			$regionInfo["gained"][$resource] += $amount * $efficiency;
    		}
    		else {
    			$minRatio = $efficiency;
    			foreach ($regionInfo["buildingsResourcesNeeded"][$building] as $r => $a) {
    				if ($regionInfo["current"][$r] > 0) {
    					//do not decrease ratio
    				}
    				else {
    					$minRatio = min($minRatio, $regionInfo["gained"][$r] / $a);
    				}
    			}

    			foreach ($regionInfo["buildingsResourcesNeeded"][$building] as $r => $a) {
    				$regionInfo["gained"][$r] -= $a * $minRatio;
    			}
    			$regionInfo["gained"][$resource] += $amount * $minRatio;
    		}
    	}

    	//Consumption
    	$consumption = getConsumption();

    	$t = $time;

    	foreach ($consumption as $type => $data) {
    		$num = 0;
    		foreach ($resources as $key => $r) {
    			if (is_int($key) && $key > 0 && $r['type'] == $type && $regionInfo["current"][$key] > 0) {
    				$num++;
    			}
    		}

    		if ($num == 0) { //no reserves
    			$sumGained = 0;
				foreach ($resources as $key => $r) {
	    			if (is_int($key) && $key > 0 && $r['type'] == $type) {
	    				$sumGained += $regionInfo["gained"][$key]; //always positive
	    			}
	    		}

	    		if ($sumGained > 0) {
	    			$ratio = prodPerSec($data['amount']) / $sumGained;

	    			if ($ratio <= 1) { //enough production
		    			foreach ($resources as $key => $r) {
			    			if (is_int($key) && $key > 0 && $r['type'] == $type) {
			    				$regionInfo["gained"][$key] -= $ratio * $regionInfo["gained"][$key];
			    			}
			    		}
		    		}
		    		else { //production not enough
		    			foreach ($resources as $key => $r) {
			    			if (is_int($key) && $key > 0 && $r['type'] == $type) {
			    				$regionInfo["gained"][$key] = 0;
			    			}
			    		}

			    		$theoreticalHappiness -= $data['malus'] * ($ratio - 1) / $ratio; //stays between 0 and 1
		    		}
	    		}
	    		else { //no production
	    			$theoreticalHappiness -= $data['malus'];
	    		}
    		}
    		else { //reserves
    			foreach ($resources as $key => $r) {
	    			if (is_int($key) && $key > 0 && $r['type'] == $type && $regionInfo["current"][$key] > 0) {
	    				$regionInfo["gained"][$key] -= prodPerSec($data['amount']) / $num;
	    			}
	    		}
    		}
    	}

    	//get next t
    	$dt = $until - $t;

    	foreach ($regionInfo["current"] as $key => $amount) {
    		if ($amount > 0 && $regionInfo["gained"][$key] < 0) {
    			$dt = min($dt, -$amount / $regionInfo["gained"][$key]);
    		}
    	}

    	//Happiness
    	if (abs($happiness - $theoreticalHappiness) < 0.000001) {
            $regionInfo["happinessGrowth"] = 0;
        }
        else if ($theoreticalHappiness > $happiness) {
            $regionInfo["happinessGrowth"] = prodPerHour(getHappinessGrowth());
        }
        else if ($theoreticalHappiness < $happiness) {
            $regionInfo["happinessGrowth"] = -prodPerHour(getHappinessGrowth());
        }
        $dt = min($dt, timeToNextLevel($regionInfo["happinessGrowth"], $happiness, getHappinessLevelInferior($happiness), getHappinessLevelSuperior($happiness)));


        //Population
        $theoreticalPopulation  *= (1 + max(($happiness - 80), 0) / 50); 
        if (abs($population - $newPopulation) < 0.000001) {
            $regionInfo["populationGrowth"] = 0;
        }
        else if ($newPopulation > $population) {
            $regionInfo["populationGrowth"] = prodPerHour(getPopulationGrowth());
        }
        else if ($newPopulation < $population) {
            $regionInfo["populationGrowth"] = -prodPerHour(getPopulationGrowth());
        }
        $dt = min($dt, timeToNextLevel($regionInfo["populationGrowth"], $population, floor($population), ceil($population)));


    	//simulate

    	foreach ($regionInfo["gained"] as $key => $amount) {
    		$regionInfo["current"][$key] += amount * $dt;
    	}
    	$happiness += $regionInfo["happinessGrowth"] * $dt;
    	$population += $regionInfo["populationGrowth"] * $dt;

    	$t += $dt;

    } while ($t < $until);

    //------------------------------------------------------------------------------------
    //Update
    //------------------------------------------------------------------------------------

    $regionResources["happiness"] = $happiness;
    $regionResources["population"] = $population;        
    
    $req = $bdd->prepare('UPDATE cRegions SET time = ? WHERE cRegions.id = ?');
    $req->execute(array($until, $regionId));
    
    $req = $bdd->prepare('UPDATE cRegions SET happiness = ? WHERE cRegions.id = ?');
    $req->execute(array($happiness, $regionId));
    
    $req = $bdd->prepare('UPDATE cRegions SET population = ? WHERE cRegions.id = ?');
    $req->execute(array($population, $regionId));

    foreach ($regionInfo["current"] as $key => $amount) {
		setRegionResources($regionId, $key, $amount);
	}
}

?>