<?php
/**
 * Zend Framework (http://framework.zend.com/)
 *
 * @link      http://github.com/zendframework/zf2 for the canonical source repository
 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
 * @license   http://framework.zend.com/license/new-bsd New BSD License
 */

namespace Zend\Code\Reflection;

use 
ReflectionMethod as PhpReflectionMethod;
use 
Zend\Code\Annotation\AnnotationCollection;
use 
Zend\Code\Annotation\AnnotationManager;
use 
Zend\Code\Scanner\AnnotationScanner;
use 
Zend\Code\Scanner\CachingFileScanner;

class 
MethodReflection extends PhpReflectionMethod implements ReflectionInterface
{
    
/**
     * @var AnnotationScanner
     */
    
protected $annotations = null;

    
/**
     * Retrieve method DocBlock reflection
     *
     * @return DocBlockReflection|false
     */
    
public function getDocBlock()
    {
        if (
'' == $this->getDocComment()) {
            return 
false;
        }

        
$instance = new DocBlockReflection($this);

        return 
$instance;
    }

    
/**
     * @param  AnnotationManager $annotationManager
     * @return AnnotationScanner
     */
    
public function getAnnotations(AnnotationManager $annotationManager)
    {
        if ((
$docComment = $this->getDocComment()) == '') {
            return 
false;
        }

        if (!
$this->annotations) {
            
$cachingFileScanner = new CachingFileScanner($this->getFileName());
            
$nameInformation    = $cachingFileScanner->getClassNameInformation($this->getDeclaringClass()->getName());

            
$this->annotations = new AnnotationScanner($annotationManager, $docComment, $nameInformation);
        }

        return 
$this->annotations;
    }

    
/**
     * Get start line (position) of method
     *
     * @param  bool $includeDocComment
     * @return int
     */
    
public function getStartLine($includeDocComment = false)
    {
        if (
$includeDocComment) {
            if (
$this->getDocComment() != '') {
                return 
$this->getDocBlock()->getStartLine();
            }
        }

        return 
parent::getStartLine();
    }

    
/**
     * Get reflection of declaring class
     *
     * @return ClassReflection
     */
    
public function getDeclaringClass()
    {
        
$phpReflection  = parent::getDeclaringClass();
        
$zendReflection = new ClassReflection($phpReflection->getName());
        unset(
$phpReflection);

        return 
$zendReflection;
    }

    
/**
     * Get all method parameter reflection objects
     *
     * @return ParameterReflection[]
     */
    
public function getParameters()
    {
        
$phpReflections  = parent::getParameters();
        
$zendReflections = array();
        while (
$phpReflections && ($phpReflection = array_shift($phpReflections))) {
            
$instance = new ParameterReflection(array(
                
$this->getDeclaringClass()->getName(),
                
$this->getName()),
                
$phpReflection->getName()
            );
            
$zendReflections[] = $instance;
            unset(
$phpReflection);
        }
        unset(
$phpReflections);

        return 
$zendReflections;
    }

    
/**
     * Get method contents
     *
     * @param  bool $includeDocBlock
     * @return string
     */
    
public function getContents($includeDocBlock = true)
    {
        
$fileContents = file($this->getFileName());
        
$startNum     = $this->getStartLine($includeDocBlock);
        
$endNum       = ($this->getEndLine() - $this->getStartLine());

        return 
implode("\n", array_splice($fileContents, $startNum, $endNum, true));
    }

    
/**
     * Get method body
     *
     * @return string
     */
    
public function getBody()
    {
        
$lines = array_slice(
            
file($this->getDeclaringClass()->getFileName(), FILE_IGNORE_NEW_LINES),
            
$this->getStartLine(),
            (
$this->getEndLine() - $this->getStartLine()),
            
true
        
);

        
$firstLine = array_shift($lines);

        if (
trim($firstLine) !== '{') {
            
array_unshift($lines, $firstLine);
        }

        
$lastLine = array_pop($lines);

        if (
trim($lastLine) !== '}') {
            
array_push($lines, $lastLine);
        }

        
// just in case we had code on the bracket lines
        
return rtrim(ltrim(implode("\n", $lines), '{'), '}');
    }

    public function 
toString()
    {
        return 
parent::__toString();
    }

    public function 
__toString()
    {
        return 
parent::__toString();
    }
}