<?php

/**
 * Sniff for detecting PHP4 constructors.
 */

/**
 * Warns about classes with PHP4 constructors that don't have PHP5 constructors.
 */
class JDGrimes_Sniffs_PHP7_PHP4ConstructorSniff extends JDGrimes_Sniff {

	public function register() {
		return array( T_FUNCTION );
	}

	public function process( PHP_CodeSniffer_File $phpcsFile, $stackPtr ) {

		$tokens = $phpcsFile->getTokens();

		if ( ! isset( $tokens[ $stackPtr ]['scope_closer'] ) ) {
			return;
		}

		$parent = end( $tokens[ $stackPtr ]['conditions'] );

		if ( ! $parent || T_CLASS !== $parent ) {
			return;
		}

		$class_ptr = key( $tokens[ $stackPtr ]['conditions'] );

		$method_ptr = $phpcsFile->findNext( T_STRING, $stackPtr + 1 );
		$method_name = $tokens[ $method_ptr ]['content'];

		if ( '__construct' === $method_name ) {
			return $tokens[ $class_ptr ]['scope_closer'];
		}

		$class_name = $phpcsFile->getDeclarationName( $class_ptr );

		if ( strtolower( $method_name ) === strtolower( $class_name ) ) {

			if (  isset( $phpcsFile->fixer ) ) {

				$fix = $phpcsFile->addFixableError(
					'Found PHP4 constructor not proceeded by a PHP5 constructor.'
					, $stackPtr
					, 'NoPHP5Constructor'
				);

				if ( $fix ) {

					$method_end_ptr = $tokens[ $stackPtr ]['scope_closer'];

					// Get the list of arguments accepted by the function.
					$args_def = $phpcsFile->getTokensAsString(
						$tokens[ $stackPtr ]['parenthesis_opener'] + 1
						, $tokens[ $stackPtr ]['parenthesis_closer'] - $tokens[ $stackPtr ]['parenthesis_opener'] - 1
					);

					if ( ! empty( $args_def ) ) {
						$args_def = ' ' . trim( $args_def ) . ' ';
						$args_only = preg_replace( '/\s?=[^,]*(,)?/', '\1', $args_def );
						$args_only .= ' ';
					} else {
						$args_only = '';
					}

					$phpcsFile->fixer->beginChangeset();

					// Change the name of the method to __construct().
					$phpcsFile->fixer->replaceToken( $method_ptr, '__construct' );

					$new_method = "\n\n\t/**";
					$new_method .= "\n\t * PHP4 constructor.";
					$new_method .= "\n\t */";
					$new_method .= "\n\tpublic function {$method_name}({$args_def}) {";
					$new_method .= "\n\t\tself::__construct({$args_only});";
					$new_method .= "\n\t}";

					$phpcsFile->fixer->addContent(
						$method_end_ptr
						, $new_method
					);
/*
					// Add a the PHP4 constructor back, right after the PHP5 one.
					$phpcsFile->fixer->addNewline( $method_end_ptr );
					$phpcsFile->fixer->addNewline( $method_end_ptr );
					$phpcsFile->fixer->addContent(
						$method_end_ptr
						, "\tpublic function {$method_name} ({$args}) {"
					);
					$phpcsFile->fixer->addNewline( $method_end_ptr );
					$phpcsFile->fixer->addContent(
						$method_end_ptr
						, "\t\tself::__construct({$args});"
					);
					$phpcsFile->fixer->addNewline( $method_end_ptr );
					$phpcsFile->fixer->addContent(
						$method_end_ptr
						, "\t}"
					);
*/
					$phpcsFile->fixer->endChangeset();
				}

			} else {

				$phpcsFile->addError(
					'Found PHP4 constructor not proceeded by a PHP5 constructor.'
					, $stackPtr
					, 'NoPHP5Constructor'
				);
			}

			return $tokens[ $class_ptr ]['scope_closer'];
		}
	}
}

// EOF
