<?php
/*
Copyright 2008 Josh Heidenreich
 
This file is part of Pelzini.
 
Pelzini is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
Pelzini is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with Pelzini.  If not, see <http://www.gnu.org/licenses/>.
*/
 
 
/**
 * Contains the {@link CodeParserItem} class
 *
 * @package Parser model
 * @author Josh Heidenreich
 * @since 0.1
 **/
 
/**
 * Stores information about parser items that are actual source code.
 * Typically these parser items have authors and versions, so all of that information
 * is stored in this class.
 *
 * @todo Add get/set methods instead of using public variables
 **/
abstract class CodeParserItem extends ParserItem {
    public $authors;
    public $since;
    public $tables;
    public $see;
    public $info_tags;
    public $deprecated;
    public $example;
    public $linenum = 0;
 
    protected $docblock_tags;
 
 
    /**
     * Processes the docblock tags for a specific item
     **/
    abstract protected function processSpecificDocblockTags($docblock_tags);
 
 
    /**
     * Executes a function for this ParserItem, and all of its children ParserItems
     *
     * The function will be called with a two arguments, the ParserItem that it should operate on, and the parent
     * of the parser item
     **/
    public function treeWalk($function_name, ParserItem $parent_item = null)
    {
    }
 
 
    /**
     * This constructor must be called by extending classes
     **/
    protected function __construct()
    {
        parent::__construct();
 
        $this->docblock_tags = array();         $this->authors = array();         $this->since = null;
        $this->example = array();         $this->info_tags = array();     }
 
 
    /**
     * This parses a comment for a specific item
     **/
    public function applyComment($comment)
    {
        $this->docblock_tags = parse_doc_comment ($comment);
    }
 
 
    /**
     * Processes the tags for a specific item
     **/
    public function processTags()
    {
        $this->processGenericDocblockTags($this->docblock_tags);
        $this->processSpecificDocblockTags($this->docblock_tags);
    }
 
 
    /**
     * Cascades parent Docblock tags into a child item
     * Only cascades the tags specified in the config
     *
     * @param ParserItem $child The child item to cascade the tags into
     **/
    public function cascadeTags($child)
    {
        $cascaseDocblockTags = array('@author', '@since');  
        $child_tags = $child->getDocblockTags();
 
        foreach ($cascaseDocblockTags as $cascade_tag) {
                $child_tags[$cascade_tag] = @$this->docblock_tags[$cascade_tag];
            }
        }
 
        $child->setDocblockTags($child_tags);
    }
 
 
    /**
     * Gets the Docblock tags of this item
     **/
    public function getDocblockTags()
    {
        return $this->docblock_tags;
    }
 
 
    /**
     * Sets the Docblock tags for this item
     *
     * @param array $tags The new docblock tags.
     **/
    public function setDocblockTags($tags)
    {
        $this->docblock_tags = $tags;
    }
 
 
    /**
     * Processes general DocBlock tags that should apply to everything
     **/
    protected function processGenericDocblockTags($docblock_tags)
    {
        // @author
        if (@count($docblock_tags['@author']) > 0) {             // This regex is for taking an author string, and getting the name (required),
            // email address (optional) and description (optional).
            // The format, simply put, is:
            //    {Name} (<{Email}>)? ({Description})?
            // There is also some extra cleverness, such as you can use a comma, colon or semi-colon
            // to seperate the name part and the description part
            //
            //               | name part  || email address part         || desc part         |
            $expression = '/^((?:[a-z] ?)+)(?:\s*<([-a-z._]+@[-a-z.]+)>)?(?:\s*[,:;]?\s*(.*))?$/si';
 
            foreach ($docblock_tags['@author'] as $author) {
                    $author = new ParserAuthor();
                    $author->name = $matches[1];
                    $author->email = $matches[2];
                    $author->description = $matches[3];
 
                    $this->authors[] = $author;
                }
            }
        }
 
        // @since
        if (@count($docblock_tags['@since']) > 0) {             $this->since = $docblock_tags['@since'][0];
        }
 
        // @table
        if (@count($docblock_tags['@table']) > 0) {             $valid_actions = array('select', 'insert', 'update', 'delete');  
            foreach ($docblock_tags['@table'] as $table_def) {
                if ($table_def == '') continue;
 
                $parts = explode(' ', $table_def, 3);  
                $found_action = false;
                foreach ($valid_actions as $action) {
                        $found_action = true;
                        break;
                    }
                }
 
 
                $table = new ParserTable();
 
                if ($found_action) {
                    $table->name = $parts[1];
                    $table->description = $parts[2];
 
                } else {
                    $table->name = $parts[0];
                    $table->description = $parts[1] . ' ' . $parts[2];
                }
 
                $this->tables[] = $table;
            }
        }
 
        // @see
        if (@count($docblock_tags['@see']) > 0) {             foreach ($docblock_tags['@see'] as $see) {
                $this->see[] = $see;
            }
        }
 
        // @tag
        if (@count($docblock_tags['@tag']) > 0) {             foreach ($docblock_tags['@tag'] as $info_tag) {
                $this->info_tags[] = $info_tag;
            }
        }
 
        // @example
        if (@count($docblock_tags['@example']) > 0) {             foreach ($docblock_tags['@example'] as $example) {
            	$example = trim($example, "\r\n");  
            	$lead = 1000;
            	foreach ($lines as $ln) {
            		if (!$ln) continue;
            	}
 
            	foreach ($lines as &$ln) {
            	}
 
                $this->example[] = implode("\n", $lines);             }
        }
 
        // @deprecated
        if (@count($docblock_tags['@deprecated']) > 0) {             $this->deprecated = $docblock_tags['@deprecated'][0];
        }
    }
 
 
    /**
     * Debugging use only
     **/
    protected function dump()
    {
        echo '<br>Authors: '; foreach ($this->authors as $a) $a->dump();
        echo '<br>Tables: '; foreach ($this->tables as $a) $a->dump();
        echo '<br>Since: ', $this->since;
 
        //parent::dump();
    }
 
 
}
 
 
?>