<?php

use dokuwiki\Extension\ActionPlugin;
use dokuwiki\Extension\EventHandler;
use dokuwiki\Extension\Event;

/**
 * DokuWiki Plugin networkgraph (Action Component)
 *
 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
 * @author Feralheart <dokuwiki@feralheart.dev>
 */
class action_plugin_networkgraph_grapher extends ActionPlugin
{
    /** @inheritDoc */
    public function register(EventHandler $controller)
    {
        $controller->register_hook('INDEXER_PAGE_ADD', 'AFTER', $this, 'rebuildGraphData');
    }

    /**
     * Event handler for INDEXER_TASKS_RUN
     *
     * @see https://www.dokuwiki.org/devel:events:INDEXER_TASKS_RUN
     * @param Event $event Event object
     * @param mixed $param optional parameter passed when event was registered
     * @return void
     */
    public function rebuildGraphData(Event $event, $param)
    {
        global $conf;

        $namespaces = [''];
        $depth = 0;
        $incmedia = 'ns';
        $pages = [];
        $media = [];
        $nodes = [];
        $links = [];
        foreach($namespaces as $ns) {
            // find media
            if($incmedia == 'ns') {
                $data = [];
                search(
                    $data,
                    $conf['mediadir'],
                    'search_universal',
                    [
                        'depth' => $depth,
                        'listfiles' => true,
                        'listdirs' => false,
                        'pagesonly' => false,
                        'skipacl' => true,
                        'keeptxt' => true,
                        'meta' => true,
                    ],
                    str_replace(':', '/', $ns)
                );

                // go through all those media files
                while($item = array_shift($data)) {
                    $media[$item['id']] = [
                        'title' => noNS($item['id']),
                        'size' => $item['size'],
                        'ns' => getNS($item['id']),
                        'time' => $item['mtime'],
                    ];
                }
            }

            // find pages
            $data = [];
            search(
                $data,
                $conf['datadir'],
                'search_universal',
                [
                    'depth' => $depth,
                    'listfiles' => true,
                    'listdirs' => false,
                    'pagesonly' => true,
                    'skipacl' => true,
                    'firsthead' => true,
                    'meta' => true,
                ],
                str_replace(':', '/', $ns)
            );

            // ns start page
            if($ns && page_exists($ns)) {
                $data[] = [
                    'id' => $ns,
                    'ns' => getNS($ns),
                    'title' => p_get_first_heading($ns, false),
                    'size' => filesize(wikiFN($ns)),
                    'mtime' => filemtime(wikiFN($ns)),
                    'perm' => 16,
                    'type' => 'f',
                    'level' => 0,
                    'open' => 1,
                ];
            }

            // go through all those pages
            while($item = array_shift($data)) {
                $time = (int) p_get_metadata($item['id'], 'date created', false);
                if(!$time) $time = $item['mtime'];

                $pages[$item['id']] = [
                    'title' => $item['title'],
                    'ns' => $item['ns'],
                    'size' => $item['size'],
                    'time' => $time,
                    'links' => [],
                    'media' => [],
                ];
            }
        }

        // now get links and media
        foreach($pages as $pid => $item) {
            // get instructions
            $ins = p_cached_instructions(wikiFN($pid), false, $pid);
            // find links and media usage
            foreach($ins as $i) {
                $mid = null;

                if($i[0] == 'internallink') {
                    $id = $i[1][0];
                    $exists = true;
                    resolve_pageid($item['ns'], $id, $exists);
                    list($id) = explode('#', $id, 2);
                    if($id == $pid) continue; // skip self references
                    if($exists && isset($pages[$id])) {
                        $pages[$pid]['links'][] = $id;
                    }
                    if(is_array($i[1][1]) && $i[1][1]['type'] == 'internalmedia') {
                        $mid = $i[1][1]['src']; // image link
                    } else {
                        continue; // we're done here
                    }
                }

                if($i[0] == 'internalmedia') {
                    $mid = $i[1][0];
                }

                if(is_null($mid)) continue;
                if($incmedia == 'none') continue; // no media wanted

                $exists = true;
                resolve_mediaid($item['ns'], $mid, $exists);
                list($mid) = explode('#', $mid, 2);
                $mid = cleanID($mid);

                if($exists) {
                    if($incmedia == 'all') {
                        if(!isset($media[$mid])) { //add node
                            $media[$mid] = [
                                'size' => filesize(mediaFN($mid)),
                                'time' => filemtime(mediaFN($mid)),
                                'ns' => getNS($mid),
                                'title' => noNS($mid),
                            ];
                        }
                        $pages[$pid]['media'][] = $mid;
                    } elseif(isset($media[$mid])) {
                        $pages[$pid]['media'][] = $mid;
                    }
                }
            }

	        $backlinks = ft_backlinks($pid, true);
            foreach($backlinks as $backlink) {
                $pages[$backlink]['links'][] = $pid;   
            }
        }
        
        // clean up duplicates then create nodes
        foreach($pages as $pid => $item) {
            $pages[$pid]['links'] = array_unique($pages[$pid]['links']);
            $pages[$pid]['media'] = array_unique($pages[$pid]['media']);

            //create nodes
            $nodes[] = [
                'id' => $pid,
                'group' => 'page',
                'label' => $pid."\n".$item['title']
            ];

            //create links
            foreach($pages[$pid]['links'] as $link) {
                $links[] = [
                    'source' => $pid,
                    'target' => $link
                ];
            }

            foreach($pages[$pid]['media'] as $mediaLink) {
                $links[] = [
                    'source' => $pid,
                    'target' => $mediaLink
                ];
            }
        }

        foreach($media as $mid => $item) {
            $nodes[] = [
                'id' => $mid,
                'group' => 'media',
                'label' => $mid."\n".$item['title']
            ];
        }

        $graphData = json_encode(['nodes' => $nodes, 'links' => $links]);
        $saveFile = metaFN('networkgraph_data', '.json');
        io_saveFile($saveFile, json_encode([
            'nodes' => $nodes,
            'links' => $links
        ]));

    }
}
