<?php

namespace Modules;

class FilesInFolders {

    private $folder;
    public $content = array();
    public $extras = array();
    private $domains = array('default'=>'default');
    private $keyfiles = array();
    public $structs = array();
    private $EXT=array(
            'txt'=>array( 'txt', 'text', 'md' ),
            'pic'=>array( 'jpg', 'jpeg', 'png', 'svg' ),
            'tpl'=>array( 'html', 'htm', 'tpl' ),
            'csv'=>array( 'csv' )
        );
    public $config = array();
    private $state=array();

    function __construct($folder,$conf=array()) {
        $f3 = \Base::instance();
        
        if(is_dir($folder)) {                    // are we given a valid path?
            $this->folder = $folder;
        } else {                                 // and if not?
            $this->folder = $f3->get('CONTENT')."./";
        }
        if(is_array($conf)) {
            foreach($conf as $key=>$value) {
                switch($key) {
                case 'content':
                    if(is_array($value)) {
                        foreach($value as $k=>$v) {
                            $this->domains[$k] = $v;
                        }
                    }
                    break;
                case 'keyfiles':
                    if(is_array($value)) {
                        foreach($value as $k=>$v) {
                            $this->keyfiles[$k] = $v;
                        }
                    }
                    break;
                }
            }
        }
        foreach($this->domains as $domain) {
            $this->content[$domain] = array();
        }
        foreach($this->keyfiles as $keys=>$d) {
            $this->extras[$keys] = "";
        }
    }


    /////////////////////////////
    // read folder into struct //
    /////////////////////////////
    function prepare_files() {

        foreach ($this->domains as $k=>$v) {
            foreach($this->EXT as $cat=>$endings) {
                $this->structs[$k][$cat]=array();
            }
        }
        
        $ls = scandir($this->folder);
        foreach ($ls as $k=>$f) {
            if (!strncmp($f,'.',1)) continue; // ignore hidden files
            
            $ex=explode(".", $f);
            $ext=strtolower(end($ex));
            if (array_key_exists($ex[0],$this->domains)) {
                $domain_key=$ex[0];
                $sort_key=1;
            } elseif (array_key_exists($ex[0], $this->keyfiles)) {
                if(in_array($ext,$this->EXT[$this->keyfiles[$ex[0]]['type']])) {
                    $this->extras[$ex[0]]=$this->folder.$f;
                    continue;
                }
                $domain_key='default';
                $sort_key=0;
            } else {
                $domain_key='default';
                $sort_key=0;
            }
            foreach ($this->EXT as $cat=>$endings) {
                if (in_array($ext, $endings)) {
                    $this->structs[$domain_key][$cat][$ex[$sort_key]] = $this->folder.$f;
                    break;
                }
            }
        }

        foreach($this->keyfiles as $key=>$param) {
            if(!$this->extras[$key]) {
                $this->extras[$key] = self::search_up(
                    $key,
                    array($this->folder,$param['until']),
                    $this->EXT[$param['type']]
                );
            }
        }
    }

    
    ///////////////////////////////////////
    // prepare content as per the struct //
    ///////////////////////////////////////
    function fill_content() {
        $md = new \Parsedown();
        foreach($this->domains as $domain_key=>$domain) {
            $this->state['current_domain'] = $domain_key;
            
            foreach($this->structs[$domain_key]['txt'] as $key=>$file) {
                $str = $this->read_textfile($file);
                $str = self::content_element_dispatcher($str);
                $str = $md->text($str);    
                $str = sprintf("<div class='post'>%s</div>", $str);
                $this->content[$domain][$key] = sprintf(
                    "<div class=\"item %s %s\">%s</div>",
                    $page,
                    $key,
                    $str
                );
            }
            foreach($this->structs[$domain_key]['tpl'] as $key=>$file) {
                $str = file_get_contents($file);
                $str = \Template::instance()->render($file);
                $str = self::linkify($str);
                $this->content[$domain][$key] = sprintf(
                    "<div class=\"item %s %s\">%s</div>",
                    $page,
                    $key,
                    $str
                );
            }
            if (false) { // TODO: make this configurable in main.cfg
                foreach($this->structs[$domain_key]['pic'] as $key=>$file) {
                    $this->content[$domain][$key] = sprintf(
                        "<img class=\"direct\" src=\"/$file\" />"
                    );
                }
            }
            foreach($this->structs[$domain_key]['csv'] as $key=>$file) {
                $csv = new \Modules\Ography($file,TRUE);
                $str="<table>";
                foreach($csv->entries as $entry) {
                    $tmp="";
                    foreach($entry as $key=>$value) {
                        $tmp .= sprintf("<td class=\"%s\">%s</td>", $key, $value);
                    }
                    $str .= sprintf("<tr>%s</tr>",$tmp);
                }
                $str.="</table>";
                $this->content[$domain][$key] = $str;
            }
        }
    }

    //////////////////////
    // read config data //
    //////////////////////
    function read_config($domain=false) {
        foreach ($this->domains as $source=>$destination) {
            if (is_string($domain)) {
                if ($source != $domain) { continue; }
            } elseif (is_array($domain)) {
                if (!in_array($source,$domain)) { continue; }
            }
            foreach ($this->structs[$source]['txt'] as $key=>$file) {
                $this->read_textfile($file);
            }
        }
        return $this->config;
    }
    
    ////////////////
    // recursions //
    ////////////////
    function search_up($key,$paths,$ext) {
        $return = "";

        if(count($paths) == 2) {
            $current = $paths[0];
            $last_try = $paths[1];
            $ls=scandir($current);
            foreach($ls as $f) {
                if(!strncmp($f,'.',1)) continue; // ignore hidden files
                $ex=explode(".", $f);
                if(in_array(strtolower(end($ex)),$ext)) {
                    if($ex[0]==$key) {
                        $return = $current.$f;
                        break;
                    }
                }
            }
        }
        
        if ($return) {
            return $return;
        } elseif($current == $last_try) {
            return false;
        } else {
            $p = explode('/',$current);
            array_pop($p);
            array_pop($p);
            return self::search_up($key,array(implode("/",$p)."/",$last_try),$ext);
        }
    }
    
    ///////////////////////
    // Utility functions //
    ///////////////////////
    function read_textfile($file) {
        $str = file_get_contents($file);
        $str = self::linkify($str);
        $str = self::strip_comments($str);
        $str = self::get_config_from_content($str);
        return $str;
    }
    function strip_comments($str) {
        $single_line_comments = "/(^;.*\R)/m";
        $str = preg_replace($single_line_comments,"",$str);
        $multi_line_comments = "/\/\*.*?\*\//s";
        $str = preg_replace($multi_line_comments,"",$str);
        return $str;
    }
    function linkify($string) {
        $pattern = "/\s@(\w+)[=]([\w,]+)\s/";
        $count = 0;
        $new = preg_replace_callback
            ($pattern,
             function($m){
                 $f3 = \Base::instance();
                 return $f3->get('SITE_URL')
                     .$f3->alias($m[1],self::$keyword."=".$m[2])
                     ;},
             $string);
        return $new;
    }
    function get_config_from_content($string) {
        $f3 = \Base::instance();
        $f = 0;

        $pattern = "/#\+(\w+):\s?(.*)/";
        $f = preg_match_all($pattern, $string,$matches,PREG_PATTERN_ORDER);
        for ($i=0;$i<$f;$i++) {
            $string = str_replace($matches[0][$i],"",$string);
            $key = $matches[1][$i];
            $value = $matches[2][$i];

            if(strtolower($value) == "false") {
                $value = FALSE;
            }
            
            if(!strncmp(trim($value),'@',1)) {
                //var_dump($f3->get('DATA'));
                if (array_key_exists($key,$f3->get('DATA'))) {
                    $DATA = $f3->get('DATA.'.$key);
                    $conf = array($DATA['type'],$DATA['dir']);
                    $relation = new \Modules\TOC($conf,$f3->get('CONTENT'),substr($value,1));
                    $relation->dispatch();
                    $this->config[$key]=array_shift($relation->entries);
                } else {
                    $this->config[$key]=$value;
                }
            } else {
                $this->config[$key]=$value;
            }
        }

        $pattern = "/§>\s*(\w+):(.*?)\R[\011\040]*\R/s";
        $f = preg_match_all($pattern, $string,$matches,PREG_PATTERN_ORDER);
        for ($i=0;$i<$f;$i++) {
            $string = str_replace($matches[0][$i],"",$string);
            $key = $matches[1][$i];
            $value = trim($matches[2][$i]);

            if(strtolower($value) == "false") {
                $value = FALSE;
            }
            
            if (!strncmp($value,'@',1)) {
#                var_dump();
                if (array_key_exists($key,$f3->get('DATA'))) {
                    $entries = explode("@",$value);
                    array_shift($entries); // first entry is always empty
                    $DATA = $f3->get('DATA.'.$key);
                    $conf = array($DATA['type'],$DATA['dir']);
                    $relation = new \Modules\TOC($conf,$f3->get('CONTENT'),$entries);
                    $relation->dispatch();
                    
                    if(/*count($entries) >*/ 1) {
                        $this->config[$key]= new CMultiple($relation->entries);
                    } else {
                        $this->config[$key]=array_shift($relation->entries);
                    }
                } else {
                    $this->config[$key]=$value;
                }
            } else {
                $this->config[$key]=$value;
            }
        }
        return $string;
    }
    function content_element_dispatcher($string) {
        
        $md = new \Parsedown();
        $f0 = 0;
        // find occorances of {| keyword |}
        $pattern = "/\{\|(.+?)\|\}/s";

        $f = preg_match_all($pattern, $string,$matches,PREG_PATTERN_ORDER);
        for ($i=0;$i<$f;$i++) {
            $body = preg_split("/\R/",trim($matches[1][$i]));
            $request = explode(":", trim(array_shift($body)));
            $new="";
            switch($request[0]) {
            case 'test':
                $new="seems to work";
                break;
            case ';':
                $new="";
                break;
            case 'path':
                $new="/".$this->folder;
                break;
            case 'space':
                $new=sprintf("<div style=\"height:%s;\"></div>",
                             $request[1]
                );
                break;
            case 'small-text':
                if(count($body)) { 
                    $new=sprintf("<div class=\"f1\">%s</div>",
                                 implode("\n",$body)
                    );
                } else {
                    $new=sprintf("<span class=\"f1\">%s</span>",
                                 $request[1]
                    );
                }
                break;
                
            case 'TOC':
                // throw away TOC part of request, we don't need it
                array_shift($request); 
                $toc = new \Modules\TOC($request,$this->folder,$body);
                $toc->dispatch();
                $new=sprintf("<div class=\"TOC %s\">%s</div>",
                             array_shift($request),
                             $toc);
                break;
                
            case 'calendar':
                array_shift($request);
                $conf = array('path', $this->folder);
                $v = $this->read_config();
                $cal = new \Modules\CCalendar($v,$conf);
                //$cal->dispatch();
                
                
                //$conf = array('path', $this->folder);
                //$v = $this->read_config();
                
                $new=sprintf("<div class=\"calendar\">%s</div>",
                             $cal);
                break;

            case 'header':
                array_shift($request);
                $conf = array('path', $this->folder);
                $v = $this->read_config();
                switch (array_shift($request)) {
                case 'event':
                    $el = new CEvent($v,$conf);
                    $el->set_layout('archive');
                    $new = $el;
                    break;
                case 'concert':
                    $el = new CConcert($v,$conf);
                    $el->set_layout('header');
                    $new = $el;
                    break;
                }

                break;
                
            case 'image':
                $key=$request[1];
                $image="";
                if(!$key) {
                    $new=self::warn("Content Module \"Image\" needs name of a file (without extension)");
                    break;
                }
                
                foreach($this->structs as $domain=>$destination) {
                    if(array_key_exists($key, $this->structs[$domain]['pic'])) {
                        $image = $this->structs[$domain]['pic'][$key];
                        unset($this->structs[$domain]['pic'][$key]);
                        unset($this->content[$this->domains[$domain]][$key]);
                        break;
                    }
                }

                if ($image) {
                    if( in_array($request[2],array('left','right','full'))) {
                        $class = $request[2];
                    } else {
                        $class = 'left';
                    }
                    $img = new \Image($image);
                    $ratio = ($img->width() >= $img->height())
                           ? "landscape"
                           : "portrait"
                           ;

                    $cached = new CachedImage($image);
                    foreach ($body as $k=>$line) {
                        if (strpos($line,"©") !== FALSE
                            || strpos($line,"&copy;") !== FALSE) {
                            $body[$k] = sprintf("<span class=\"copyright\">%s</span>",$line);
                        }
                    }
                    
                    $new=sprintf("<div class='image-container %s'>"
                                 ."<div class=\"media %s\"><a href=\"/%s\" data-featherlight=\"image\"><img src=\"/%s\" alt=\"user supplied image\" /></a></div>"
                                 ."<img src=\"/%s\" style=\"display:none;\" alt=\"user supplied image\" />"
                                 ."<div class=\"caption\">%s</div>"
                                 ."</div>",
                                 $class,
                                 $ratio,
                                 $cached->get_src(1400),
                                 $cached->get_src(500),
                                 $cached->get_src(1400),
                                 $md->text(implode("\n",$body))
                    );
                } else {
                    $new=self::warn("image \"$key\" not found");
                }
                break;

                
            case 'youtube':
                if( in_array($request[2],array('left','right','full'))) {
                    $class = $request[2];
                } else {
                    $class = 'left';
                }
                $video=sprintf("<iframe width=\"700\" height=\"394\" class=\"ytvideo\" "
                               ."src=\"https://www.youtube.com/embed/%s\"></iframe>",
                               $request[1]);

                $thumbnail = sprintf("<div class=\"video-thumbnail\"><a href=\"%s\" data-featherlight=\"#%s\">"
                                     ."<img class=\"thumbnail\" src=\"https://img.youtube.com/vi/%s/mqdefault.jpg\" alt=\"video-preview\"/>"
                                     ."<img class=\"play-button\" src=\"%s\" alt=\"play-button\" />"
                                     ."</a></div><div class=\"lightbox\" id=\"%s\" >%s</div>",
                                     "https://www.youtube.com/watch?v=".$request[1],
                                     $request[1],
                                     $request[1],
                                     "/rsc/img/play-button.png",
                                     $request[1],
                                     $video
                );


                foreach ($body as $k=>$line) {
                    if (strpos($line,"©") !== FALSE
                        || strpos($line,"&copy;") !== FALSE) {
                        $body[$k] = sprintf("<span class=\"copyright\">%s</span>",$line);
                    }
                }
                $new=sprintf("<div class='video-container %s'>"
                             ."<div class=\"media\">%s</div>"
                             ."<div class=\"caption\">%s</div>"
                             ."</div>",
                             $class,
                             $thumbnail,
                             $md->text(implode("\n",$body)));
                break;
            default:
                $new=self::warn("Content Module \"".$request[0]."\" unknown");
                break;
            }

            $string = str_replace($matches[0][$i],$new,$string);
        }
        return $string;
    }
    
    function warn($message) {
        return sprintf("<div class=\"warning\">%s</div>",$message);
    }
}
