protected static function generateProxy($originalClassName, array $methods = null, array $properties = null,
                                            $proxyClassName = '', $callAutoload = false)
    {
        $templateDir = __DIR__ . DIRECTORY_SEPARATOR . 'Generator' . DIRECTORY_SEPARATOR;
        $classTemplate = self::createTemplateObject(
            $templateDir . 'proxied_class.tpl'
        );

        $proxyClassName = self::generateProxyClassName(
            $originalClassName, $proxyClassName
        );

        if (interface_exists($proxyClassName['fullClassName'], $callAutoload)) {
            throw new GeneratorException(sprintf(
                '"%s" is an interface.', $proxyClassName['fullClassName']
            ), GeneratorException::IS_INTERFACE);
        }

        if (!class_exists($proxyClassName['fullClassName'], $callAutoload)) {
            throw new GeneratorException(sprintf(
                'Class "%s" does not exists.', $proxyClassName['fullClassName']
            ), GeneratorException::CLASS_NOT_FOUND);
        }

        $class = new \ReflectionClass($proxyClassName['fullClassName']);

        if ($class->isFinal()) {
            throw new GeneratorException(sprintf(
                'Class "%s" is declared "final". Cannot create proxy.', $proxyClassName['fullClassName']
            ), GeneratorException::CLASS_IS_FINAL);
        }

        if (!empty($proxyClassName['namespaceName'])) {
            $prologue = 'namespace ' . $proxyClassName['namespaceName'] . ";\n\n";
        }

        $classTemplate->setVar(
            array(
                'prologue' => isset($prologue) ? $prologue : '',
                'class_declaration' => $proxyClassName['proxyClassName'] . ' extends ' . $originalClassName,
                'methods' => self::getProxiedMethods($proxyClassName['fullClassName'], $class, $methods),
                'properties' => self::getProxiedProperties($proxyClassName['fullClassName'], $class, $properties),
            )
        );

        return array(
            'code' => $classTemplate->render(),
            'proxyClassName' => $proxyClassName['proxyClassName'],
            'namespaceName' => $proxyClassName['namespaceName']
        );
    }