<?php
/**
 * YANA library
 *
 * @package yana
 * @licence http://creativecommons.org/licenses/by-nc-sa/2.5/
 */

/**
 * Manipulate a directory
 *
 * This class represents a directory.
 * You may use this to get a list of contents, or remove,
 * or create a directory.
 *
 * @access      public
 * @package     yana
 * @subpackage  io
 */
class DirStream extends InputStream
{

    /**#@+
     * @ignore
     * @access  protected
     */
    /** @var array  */ var $content = array();
    /** @var array  */ var $options = array();
    /** @var string */ var $filter  = "";
    /**#@-*/

    /**
     * read contents and put results in cache (filter settings will be applied)
     *
     * @uses $dirStream->read()
     * @access public
     * @return boolean
     */
    function read()
    {
        if (!$this->exists()) {
            return false;
        } else {
            $this->content = dirlist($this->getFilename(), $this->filter);
            sort($this->content);
            $this->options = $this->attributes;
            return true;
        }
    }


    /**
     * return list of files within the directory
     *
     * NOTE: will only return filenames with the path stripped
     *
     * @uses    $dirStream->get()
     * @access  public
     * @return  array
     */
    function get()
    {
        if (!$this->isEmpty()) {
            return $this->content;
        } else {
            return array();
        }
    }

    /**
     * create this directory
     *
     * Tries to create the directory.
     * Check the developer's cookbook for an example
     * to this function.
     *
     * @uses $dirStream->create(660)
     *
     * @access  public
     * @return  bool
     * @name    dirstream::create()
     * @param   int $mode access mode
     */
    function create($mode = 777)
    {
        assert('is_int($mode);');
        if (!is_int($mode) || strlen($mode) != 3 || $this->exists() || !isset($this->filename)) {
            return false;
        } else {
            return @mkdir($this->filename,"0$mode");
        }
    }

    /**
     * remove this directory
     *
     * By option you may choose to also recursivly remove all files and subdirectories inside.
     * Otherwise the directory will only be removed if it is empty.
     *
     * @uses    $dirStream->delete(false)
     *
     * @access  public
     * @param   boolean  $is_recursive  triggers wether to remove directories even if they are not empty, default = false
     * @return  boolean
     */
    function delete($is_recursive=false)
    {
        if ($is_recursive === true) {
            $content = dirlist($this->filename, '');
            foreach ($content as $a => $b) {
                $b = '/'.$b;
                if (is_file($this->filename.$b)) {
                    $file = new secureFileStream($this->filename.$b);
                    $file->delete();
                } elseif (is_dir($this->filename.$b)) {
                    $dir = new dirStream($this->filename.$b);
                    $dir->delete(true);
                } else {
                    /* intentionally left blank */
                }
            }
        }
        return @rmdir($this->getFilename());
    }

    /**
     * toString
     *
     * @uses    $dirStream->toString()
     *
     * @access  public
     * @return  string
     */
    function toString()
    {
        if (!$this->exists()) {
            return "Directory ".$this->filename." does not exist\n";
        } else if ($this->isEmpty()) {
            return "Directory ".$this->filename." is not loaded\n";
        } else {
            return implode("\n", $this->get());
        }
    }

    /**
     * check wether the directory has no contents
     *
     * Returns bool(true) if there are no files that
     * match the current filter and bool(true) if there
     * is at least 1 file that matches.
     *
     * @uses    $dirStream->isEmpty()
     *
     * @access  public
     * @return  boolean
     */
    function isEmpty()
    {
        return empty($this->content);
    }

    /**
     * length
     *
     * @uses $dirStream->length()
     *
     * @access public
     * @return int
     */
    function length()
    {
        return count($this->content);
    }
    
    /**
     * list contents of a directory
     *
     * The argument $filter may contain multiple file extension,
     * use a pipe '|' sign to seperate them.
     * Example: "*.xml|*.html" will find all xml- and html-files
     *
     * @uses $dirStream->dirlist('*.cfg')
     *
     * @access  public
     * @param   string  $filter
     * @return  array
     */
    function dirlist($filter)
    {
        assert('is_string($filter);');
        settype($filter, "string");
        $this->filter = $filter;
        $this->read();
        return $this->content;
    }
    
    /**
    * getContent
    *
    * @uses $dirStream->getContent()
    *
    * @access public
    * @return array
    * @ignore
    */
    function getContent()
    {
         if ($this->isEmpty()) { 
             $this->read(); 
         }
         $REF = array();
         for ($i=0; $i<count($this->content); $i++)
         {
             $REF[$i]['VALUE'] = $this->content[$i];
             $REF[$i]['NAME']  = substr($this->content[$i], 0, strrpos($this->content[$i], "."));
         }
         return $REF;
    }

    /**
     * reset statistic data
     *
     * @uses $dirStream->resetStats()
     *
     * @access protected
     * @ignore
     */
    function resetStats()
    {
        if (!preg_match('/.*\/$/', $this->filename)) {
            $this->filename .= '/';
        }
        if ($this->exists()) {
            $this->attributes['MTIME']       = date("d.m.Y",filemtime($this->filename));
            $this->attributes['ATIME']       = date("d.m.Y H:i:s",fileatime($this->filename));
            $this->attributes['CTIME']       = date("d.m.Y",filectime($this->filename));
            $this->attributes['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
            clearstatcache();
        }
    }

    /**
     * check if directory exists and is readable
     *
     * @access public
     * @return boolean
     */
    function exists()
    {
        return is_dir($this->filename) && file_exists($this->filename) && is_readable($this->filename);
    }

}

?>