<?php

namespace Aowow;

if (!defined('AOWOW_REVISION'))
    die('illegal access');

if (!CLI)
    die('not in cli mode');


CLISetup::registerSetup("sql", new class extends SetupScript
{
    protected $info = array(
        'taxi' => [[], CLISetup::ARGV_PARAM, 'Compiles supplemental data for type: NPC from dbc and world db.']
    );

    protected $dbcSourceFiles  = ['taxipath', 'taxinodes', 'worldmaparea', 'worldmaptransforms', 'factiontemplate'];
    protected $worldDependency = ['creature', 'creature_template'];
    protected $setupAfter      = [['dungeonmap', 'worldmaparea'], []]; // accessed by WorldPosition::toZonePos

    public function generate() : bool
    {
        DB::Aowow()->qry('TRUNCATE ::taxipath');
        DB::Aowow()->qry('TRUNCATE ::taxinodes');

        /*********/
        /* paths */
        /*********/

        DB::Aowow()->qry('INSERT INTO ::taxipath SELECT tp.id, tp.startNodeId, tp.endNodeId FROM dbc_taxipath tp WHERE tp.startNodeId > 0 AND tp.EndNodeId > 0');

        // paths are monodirectional and thus exist twice for regular flight travel (which is bidirectional)
        $paths = DB::Aowow()->selectAssoc('SELECT id AS ARRAY_KEY, tp.* FROM ::taxipath tp');
        foreach ($paths as $i => $p)
        {
            foreach ($paths as $j => $_)
            {
                if ($_['startNodeId'] != $p['endNodeId'] || $_['endNodeId'] != $p['startNodeId'])
                    continue;

                DB::Aowow()->qry('DELETE FROM ::taxipath WHERE id = %i', $j);
                unset($paths[$j]);
                unset($paths[$i]);
                break;
            }
        }


        /*********/
        /* nodes */
        /*********/

        // all sensible nodes
        $fNodes  = DB::Aowow()->selectAssoc(
           'SELECT tn.`id`,
                   tn.`mapId`,
                   100 - ROUND((tn.`posY` - wma.`right`)  * 100 / (wma.`left` - wma.`right`), 1) AS "mapX",
                   100 - ROUND((tn.`posX` - wma.`bottom`) * 100 / (wma.`top` - wma.`bottom`), 1) AS "mapY",
                   0 AS "areaId",
                   0 AS "areaX",
                   0 AS "areaY",
                   1 AS `type`, 0 AS `typeId`, 1 AS "reactA", 1 AS "reactH",
                   tn.`name_loc0`, tn.`name_loc2`, tn.`name_loc3`, tn.`name_loc4`, tn.`name_loc6`, tn.`name_loc8`,
                   tn.`mapId` AS "_mapId", tn.`posX` AS "_posX", tn.`posY` AS "_posY",
                   IF (tn.`id` NOT IN (15, 148, 225, 235) AND (
                          tn.`id` IN (64, 250) OR (
                              tn.`name_loc0` NOT LIKE "%Transport%" AND tn.`name_loc0` NOT LIKE "%Quest%" AND
                              tn.`name_loc0` NOT LIKE "%Start%"     AND tn.`name_loc0` NOT LIKE "%End%"
                          )
                      ), 0, 1) AS "_scripted"
            FROM   dbc_taxinodes tn
            JOIN   dbc_worldmaparea wma ON ( tn.`mapId` = wma.`mapId` AND tn.`posX` BETWEEN wma.`bottom` AND wma.`top` AND tn.`posY` BETWEEN wma.`right` AND wma.`left`)
            WHERE  wma.`areaId` = 0 AND wma.`mapId` = tn.`mapId`
            UNION
            SELECT tn.`id`,
                   wmt.`targetMapId`,
                   100 - ROUND((tn.`posY` + wmt.`offsetY` - wma.`right`)  * 100 / (wma.`left` - wma.`right`), 1) AS "mapX",
                   100 - ROUND((tn.`posX` + wmt.`offsetX` - wma.`bottom`) * 100 / (wma.`top` - wma.`bottom`), 1) AS "mapY",
                   0 AS "areaId",
                   0 AS "areaX",
                   0 AS "areaY",
                   1 AS `type`, 0 AS `typeId`, 1 AS "reactA", 1 AS "reactH",
                   tn.`name_loc0`, tn.`name_loc2`, tn.`name_loc3`, tn.`name_loc4`, tn.`name_loc6`, tn.`name_loc8`,
                   tn.`mapId` AS "_mapId", tn.`posX` AS "_posX", tn.`posY` AS "_posY",
                   IF (tn.name_loc0 NOT LIKE "%Transport%" AND tn.name_loc0 NOT LIKE "%Quest%" AND tn.name_loc0 NOT LIKE "%Start%" AND tn.name_loc0 NOT LIKE "%End%",
                       0, 1 ) AS "_scripted"
            FROM   dbc_taxinodes tn
            JOIN   dbc_worldmaptransforms wmt ON ( tn.`mapId` = wmt.`sourceMapId`  AND tn.`posX`                 BETWEEN wmt.`minX`   AND wmt.`maxX` AND tn.`posY`                 BETWEEN wmt.`minY`  AND wmt.`maxY`)
            JOIN   dbc_worldmaparea wma       ON ( wmt.`targetMapId` = wma.`mapId` AND tn.`posX` + wmt.`offsetX` BETWEEN wma.`bottom` AND wma.`top`  AND tn.`posY` + wmt.`offsetY` BETWEEN wma.`right` AND wma.`left`)
            WHERE  wma.`areaId` = 0 AND wmt.`sourcemapId` = tn.`mapId`'
        );

        // all available flightmaster
        $fMaster = DB::World()->selectAssoc(
           'SELECT ct.`entry`, ct.`faction`, c.`map`, c.`position_x` AS "posX", c.`position_y` AS "posY" FROM creature_template ct JOIN creature c ON c.`id` = ct.`entry` WHERE ct.`npcflag` & %i OR c.`npcflag` & %i',
            NPC_FLAG_FLIGHT_MASTER, NPC_FLAG_FLIGHT_MASTER
        );

        // fetch reactions per faction
        $factions = DB::Aowow()->selectAssoc(
           'SELECT `id` AS ARRAY_KEY,
                   IF(`enemyFactionId1` = 1 OR `enemyFactionId2` = 1 OR `enemyFactionId3` = 1 OR `enemyFactionId4` = 1 OR `hostileMask` & 0x3, -1, 1) AS "reactA",
                   IF(`enemyFactionId1` = 2 OR `enemyFactionId2` = 2 OR `enemyFactionId3` = 2 OR `enemyFactionId4` = 2 OR `hostileMask` & 0x5, -1, 1) AS "reactH"
            FROM   dbc_factiontemplate
            WHERE  `id` IN %in',
        array_column($fMaster, 'faction'));

        foreach ($fNodes as $n)
        {
            // assign nearest flightmaster and its reaction to node
            if ($n['_scripted'])
                $n['type'] = $n['typeId'] = 0;
            else
            {
                foreach ($fMaster as &$c)
                {
                    if ($c['map'] != $n['_mapId'])
                        continue;

                    $dist = pow($c['posX'] - $n['_posX'], 2) + pow($c['posY'] - $n['_posY'], 2);
                    if ($dist > 1000)
                        continue;

                    if (!isset($n['_dist']) || $n['_dist'] < $dist)
                    {
                        $n['_dist']  = $dist;
                        $n['typeId'] = $c['entry'];
                        $n['reactA'] = $factions[$c['faction']]['reactA'] ?? 0;
                        $n['reactH'] = $factions[$c['faction']]['reactH'] ?? 0;
                    }
                }
            }

            // calculate zone pos
            if ($points = WorldPosition::toZonePos($n['_mapId'], $n['_posX'], $n['_posY']))
            {
                $n['areaId'] = $points[0]['areaId'];
                $n['areaX']  = $points[0]['posX'];
                $n['areaY']  = $points[0]['posY'];
            }

            unset($n['_mapId'], $n['_posX'], $n['_posY'], $n['_dist'], $n['_scripted']);

            DB::Aowow()->qry('INSERT INTO ::taxinodes VALUES %l', $n);
        }

        return true;
    }
});

?>
