<?
function simulate($regionId) {
    include("serverConnect.php");
    
    $set = 0;
    $req = $bdd->prepare('SELECT id FROM cSets WHERE region = ?');
    $req->execute(array($regionId));
    if ($data = $req->fetch()) {
        $set = $data["id"];
    }
    
    if ($set == 0) {
        return simulateRegion($regionId, time());
    }
    else {
        $now = time();
        
        $regions = [];
        
        $req = $bdd->prepare('SELECT cSets.region FROM cSets WHERE cSets.id = ?');
        $req->execute(array($set));
        while ($data = $req->fetch()) {
            $regions[] = $data['region'];
        }
        
        do {
            $transport = true;
            
            $req = $bdd->prepare('SELECT MIN(cTransports.timeArrived) AS T FROM cSets JOIN cTransports ON cTransports.regionStart = cSets.region WHERE cSets.id = ?');
            $req->execute(array($set));
            $data = $req->fetch();
            
            $t = nullIsZero($data['T']);
            
            if ($t == 0 || $t > $now) {
                $t = $now;
                $transport = false;
            }
            
            foreach($regions as $region) {
                $tmp = simulateRegion($region, $t);
                
                if ($region == $regionId) {
                    $result = $tmp;
                }
            }
            
            if ($transport) {
                $req = $bdd->prepare('SELECT * FROM cTransports WHERE cTransports.timeArrived = ?');
                $req->execute(array($t));
                while ($data = $req->fetch()) {
                    if (in_array($data['regionStart'], $regions)) { // not transports for other sets
                        
                        if ($data['way'] == 0) { // debut du retour
                            addResourcesInRegion($data['regionEnd'], $data['resource'], $data['amount']);
                            
                            $req2 = $bdd->prepare('UPDATE cTransports SET timeArrived = ?, way = ? WHERE id = ?');
                            $req2->execute(array($data['timeArrived'] + $data['time'], 1, $data['id']));
                        }
                        else { // debut de l'aller
                        
                            if (resourcesInRegion($data['regionStart'], $data['resource']) < $data['amount']) { // if not enough resources
                                breakTrade($data['id']);
                            }
                            else {
                                removeResourcesInRegion($data['regionStart'], $data['resource'], $data['amount']);
                            
                                $req2 = $bdd->prepare('UPDATE cTransports SET timeArrived = ?, way = ? WHERE id = ?');
                                $req2->execute(array($data['timeArrived'] + $data['time'], 0, $data['id']));
                            }
                        }
                    }
                }
            }
            
        } while ($t < $now);
        
        return $result;
    }
}

function simulateRegion($regionId, $until) {
    include("serverConnect.php");
    
    $regionResources = [
        "current" => [],
        "gained" => [],
        "populationConsumption" => [],
        "owner" => 0,
        "currentInfluences" => [],
        "gainedInfluences" => [],
        "agricultureEfficiency" => [],
        "mineralEfficiency" => [],
        "buildingsEfficiency" => [],
        "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'];

    $regionResources["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)) {
                $regionResources["agricultureEfficiency"][$key] = $ratio;
            }
            else if (array_key_exists("mineralSolidity", $r)) {
                $regionResources["mineralEfficiency"][$key] = $ratio;
            }
        }
    }

    if ($data['OWNER'] == 0) {
        return simulateInfluence($regionId, $until, $data['TIME'], $regionResources);
    }
    
    if ($deltaTime > 0) {
        $theoreticalHappiness = 30;
        
        $theoreticalPopulation = 10;
        $buildings = getBuildingsList();
        
        //Construction
        
        $buildingTimes = [];
        
        $req = $bdd->prepare('SELECT * FROM cBuildingConstructions WHERE territory >= ? AND territory <= ? AND timeFinished <= ?');
        $req->execute(array(getMinTerritoryId($regionId), getMaxTerritoryId($regionId), $until));
        
        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));
            
            $buildingTimes[$data['territory']] = $data['timeFinished'];
            
            $req2 = $bdd->prepare('DELETE FROM cBuildingConstructions WHERE territory = ?');
            $req2->execute(array($data['territory']));
            
            
        }
        //Production/Population/Happiness
        
        $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()) {
            $ownDeltaTime = $deltaTime;
            
            if (array_key_exists($data['TERR'], $buildingTimes)) { // if building was constructed during this simulation
                $ownDeltaTime = $until - $buildingTimes[$data['TERR']];
            }
            
            $regionResources["buildingsEfficiency"][$data['TERR']] = 1;
            
            $building = $buildings[$data['BTYPE']];
            $resourceName = $resources[$data['PROD']]["shortName"];
            
            //Adjacent buildings
            $adjacentRatioProduction = 1;
            $nei = getNeighbourgs($data['TERR']);
            
            foreach ($nei as $idNei) { //OPTI : cache all buildings (/!\ out of region buildings)
                $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"];
                    $theoreticalHappiness += $bonusMalus["happiness"];
                }
            }

            if (array_key_exists("population", $building)) { //population buildings
                $theoreticalPopulation += $building["population"];
            }
            else if (array_key_exists("happiness", $building)) { //happiness buildings
                $theoreticalHappiness += $building["happiness"];
            }
            else if (array_key_exists("production", $building)) { //Production
                if (empty($building["production"][$resourceName]["resourcesNeeded"])) { // mines or farms
                    $amount = prodPerSec($building["production"][$resourceName]["amount"]) * $ownDeltaTime;
                    
                    $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;
                        }
                    }
                    
                    $amount *= $efficiencies[$data['PROD']] * $depositRatio * $adjacentRatioProduction;
                    $regionResources["buildingsEfficiency"][$data['TERR']] = $efficiencies[$data['PROD']] * $depositRatio * $adjacentRatioProduction;
                
                    addResourcesInRegion($regionId, $data['PROD'], $amount);
                    
                    $regionResources["gained"][$data['PROD']] += $amount / $ownDeltaTime;
                }
                else { //plants
                    $minRatio = 1;
                    
                    foreach($building["production"][$resourceName]["resourcesNeeded"] as $key => $resourceNeeded) {
                        $currentAmount = resourcesInRegion($regionId, getResourceId($key));
                        $neededAmount = prodPerSec($resourceNeeded) * $ownDeltaTime * $adjacentRatioProduction;
                        
                        $minRatio = min($minRatio, $currentAmount / $neededAmount);
                    }
                    
                    if ($minRatio > 0) { // no need to update if no changes
                        foreach($building["production"][$resourceName]["resourcesNeeded"] as $key => $resourceNeeded) {
                            $usedAmount = $minRatio * prodPerSec($resourceNeeded) * $ownDeltaTime * $adjacentRatioProduction;
                            
                            removeResourcesInRegion($regionId, getResourceId($key), $usedAmount);
                            $regionResources["gained"][getResourceId($key)] -= $usedAmount / $ownDeltaTime;
                        }
                        $amount = prodPerSec($building["production"][$resourceName]["amount"]) * $ownDeltaTime * $minRatio * $adjacentRatioProduction;
                        
                        addResourcesInRegion($regionId, $data['PROD'], $amount);
                        $regionResources["gained"][$data['PROD']] += $amount / $ownDeltaTime;
                    }
                }
            }
            
        }
        
        $consumption = getConsumption(2); // TODO : maybe lvl will change during simulation
        $consumptionResources = [];
        
        $req = $bdd->prepare('SELECT * FROM cRegionResources WHERE region = ?');
        $req->execute(array($regionId));
        while ($data = $req->fetch()) {
            $type = $resources[$data['resource']]['type'];
            
            if (!array_key_exists($type, $consumptionResources)) {
                $consumptionResources[$type] = [];
            }
            
            $consumptionResources[$type][$data['resource']] = $data['amount'];
        }
        
        $step = 60;
        $t = $time;
        
        $done = false;
        while (!$done) {
            if ($until - $t > $step) {
                $dt = $step;
                $t += $step;
            }
            else {
                $dt = $until - $t;
                $done = true;
            }
            
            //------------------------------------------------------------------------
            //Population consumption
            //------------------------------------------------------------------------
            
            $consumptionHappiness = 0;
            
            foreach($consumption as $type => $tab) {
                $sum = 0;
                
                if (array_key_exists($type, $consumptionResources)) {
                    foreach($consumptionResources[$type] as $r => $q) {
                        $sum += $q / $resources[$r]["consumptionValue"];
                    }
                }
                
                $needed = intval($population) * prodPerSec($tab["amount"]) * $dt;
                
                if ($sum == 0) {
                    //TODO : maybe display message ?
                }
                else if ($needed > $sum) {
                    $ratio = $needed / $sum;
                    
                    foreach($consumptionResources[$type] as $r => $q) {
                        $consumptionResources[$type][$r] = 0;
                        
                        $regionResources["populationConsumption"][$r] = - $ratio * $q * $resources[$r]["consumptionValue"] / $dt;
                    }
                    
                    $consumptionHappiness -= $tab["malus"];
                }
                else {
                    $ratio = $needed / $sum;
                    
                    foreach($consumptionResources[$type] as $r => $q) {
                        $consumptionResources[$type][$r] -= $ratio * $q * $resources[$r]["consumptionValue"];
                        $regionResources["populationConsumption"][$r] = - $ratio * $q * $resources[$r]["consumptionValue"] / $dt;
                    }
                }
            }
            
            //------------------------------------------------------------------------
            //Happiness
            //------------------------------------------------------------------------

            
            $newHappiness = $theoreticalHappiness + $consumptionHappiness;
            
            if (abs($happiness - $newHappiness) < 0.000001) {
                $happiness = $newHappiness;
                $regionResources["happinessGrowth"] = 0;
            }
            else if ($newHappiness > $happiness) {
                $happiness += $dt * getHappinessGrowth();
                $regionResources["happinessGrowth"] = prodPerHour(getHappinessGrowth());
                $happiness = min($happiness, $newHappiness);
            }
            else if ($newHappiness < $happiness) {
                $happiness -= $dt * getHappinessGrowth();
                $regionResources["happinessGrowth"] = -prodPerHour(getHappinessGrowth());
                $happiness = max($happiness, $newHappiness);
            }
            
            $happiness = max(min($happiness, 100), 0);
            
            
            //------------------------------------------------------------------------
            //Population
            //------------------------------------------------------------------------
            
            $newPopulation = $theoreticalPopulation * (1 + max(($happiness - 80), 0) / 50);
            
            if (abs($population - $newPopulation) < 0.000001) {
                $population = $newPopulation;
                $regionResources["populationGrowth"] = 0;
            }
            else if ($newPopulation > $population) {
                $population += $deltaTime * getPopulationGrowth() * max(($happiness - 60), 0);
                $regionResources["populationGrowth"] = prodPerHour(getPopulationGrowth() * max(($happiness - 60), 0));
                $population = min($population, $newPopulation);
            }
            else if ($newPopulation < $population) {
                $population -= $deltaTime * getPopulationGrowth();
                $regionResources["populationGrowth"] = -prodPerHour(getPopulationGrowth());
                $population = max($population, $newPopulation);
            }
            $population = max($population, 1);
        }
        
        foreach($consumption as $type => $amount) {
            if (array_key_exists($type, $consumptionResources)) {
                foreach($consumptionResources[$type] as $r => $q) {
                    setResourcesInRegion($regionId, $r, $q);
                }
            }
        }
        
        $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));
    }
    
    $req = $bdd->prepare('SELECT * FROM cRegionResources WHERE region = ?');
    $req->execute(array($regionId));
    while ($data = $req->fetch()) {
        $regionResources["current"][$data['resource']] = $data['amount'];
    }
    
    return $regionResources;
}

function simulateInfluence($regionId, $until, $time, $regionResources) {
    include("serverConnect.php");

    $deltaTime = $until - $time;
    $dInfluences = [];

    $gains = [];
    $current = [];

    $x = getRegionX($regionId);
    $y = getRegionY($regionId);

    for ($i = -1; $i <= 1; $i++) {
        for ($j = -1; $j <= 1; $j++) {
            $req = $bdd->prepare('SELECT cRegions.owner FROM cRegions WHERE cRegions.id = ?');
            $req->execute(array(getRegionId($x + $i, $y + $j)));
            $data = $req->fetch();

            if ($data['owner'] != 0) {
                $dInfluences[$data['owner']] += 1;
            }
        }
    }

    $maxVal = 0;
    $max = 0;

    $secondMax = 0;
    $secondMaxVal = 0;
    foreach ($dInfluences as $user => $value) {
        $value *= getInfluenceGrowth();
        if ($value > $maxVal) {
            $secondMax = $max;
            $secondMaxVal = $maxVal;

            $maxVal = $value;
            $max = $user;
        }
        else if ($value > $secondMaxVal) {
            $secondMaxVal = $value;
            $secondMax = $user;
        }
    }

    $dMaxVal = $maxVal - $secondMaxVal;

    if ($max != 0) {
        addInfluenceInRegion($regionId, $max, $dMaxVal * $deltaTime);
        $gains[$max] = $dMaxVal;

        $influences = [];
        $sum = 0;
        $req = $bdd->prepare('SELECT cInfluences.user, cInfluences.value FROM cInfluences WHERE cInfluences.region = ?');
        $req->execute(array($regionId));
        while ($data = $req->fetch()) {
            if ($data['user'] != $max) {
                $influences[$data['user']] = $data['value'];
                $sum += $data['value'];
            }
        }

        if ($sum != 0) {
            foreach ($influences as $user => $value) {
                removeInfluenceInRegion($regionId, $user, $dMaxVal * $value * $deltaTime / $sum);
                $gains[$user] = -$dMaxVal * $value / $sum;
            }
        }
    }

    //Update gains and current influence

    foreach ($gains as $key => $value) {
        $req = $bdd->prepare('SELECT pseudo FROM cUsers WHERE cUsers.id = ?');
        $req->execute(array($key));
        $data = $req->fetch();

        $regionResources["gainedInfluences"][$data['pseudo']] = $value;
    }

    $req = $bdd->prepare('SELECT cUsers.pseudo, cInfluences.value FROM cInfluences JOIN cUsers ON cInfluences.user = cUsers.id WHERE cInfluences.region = ?');
    $req->execute(array($regionId));
    while ($data = $req->fetch()) {
        $regionResources["currentInfluences"][$data['pseudo']] = $data['value'];
    }

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

    return $regionResources;
}

?>