#!/bin/bash

N="\033[0m"
R="\033[1;31m"
G="\033[0;32m"
B="\033[1;34m"
Y="\033[1;33m"

fmt='s#&[ \t]*\$#\&\$#g;s#=# = #g;s#,#, #g;s#(#& #g;s#)# &#g;s#[ \t]\+# #g2;s#( )#()#g'

flist=()
while (( "$#" )); do case "$1" in
	-x|--debug) debug=1;                                                    shift 1;;
	--no-save)  nosave=1;                                                   shift 1;;
	-f|--file)  flist+=("$2");                                              shift 2;;
	--)                                                              shift 1; break;;
	-*|--*=)    echo "Error: Unsupported flag $1" >&2;                       exit 1;;
	*) flist+=("$1");                                                       shift 1;;
esac; done

function run_construct_check() {
	echo -ne "${Y}";
	fname="$1"
	if [[ ! -f "${fname}" ]]; then echo "file ${fname} not found"; return; fi

	while read line; do
		class=$(php -r '
			$buf = explode( " ", trim( preg_replace( array( "/\t/", "/ +/", "/[\n\r{]*/" ), array( " ", " ", "" ), $argv[1] ) ) );
			if ( ( !isset( $buf[2] ) ) || $buf[2] == "extends" || $buf[2] == "implements" ) echo $buf[1].PHP_EOL;
		' "${line}")
		if [[ -z "${class}" ]]; then continue; fi

		range=$(cat -n "${fname}" | sed -n '/^[ ]*[0-9]\+[ \t]*class[ \t]\+'"${class}"'\r\?$/,/^[ ]*[0-9]\+[ \t]*class[ \t]/ {s#^[ \t]*##g;s#[ \t]#:&#1; p;}' |sed -n '1{s#:.*##g;p;};${s#:.*##g;p;};'|paste -d, -s)
		if [[ -z "${range}" ]]; then range=$(cat -n "${fname}" | sed -n '/^[ ]*[0-9]\+[ \t]*class[ \t]\+'"${class}"'[ \t{]/,/^[ ]*[0-9]\+[ \t]*class[ \t]/ {s#^[ \t]*##g;s#[ \t]#:&#1; p;}' |sed -n '1{s#:.*##g;p;};${s#:.*##g;p;};'|paste -d, -s); fi
	
		constr=$(cat -n "${fname}" | sed -n "${range}p" | grep -P '^[ ]*[0-9]+[ \t]*[\w ]*function[ \t]+__construct[ \t]*\('|sed 's#//.*##g')
		funct=$(cat -n "${fname}" | sed -n "${range}p" |grep -P '^[ ]*[0-9]+[ \t]*[\w ]*function[ \t]+'"${class}"'[ \t]*\('|sed 's#//.*##g')
		if [[ $(echo "${funct}"|wc -l) -ge 2 ]]; then
			funct=$(cat -n "${fname}" | sed -n "${range}p" | sed '/^ *[0-9]*[ \t]*\/\*/,/\*\// d' | grep -P '^[ ]*[0-9]+[ \t]*[\w ]*function[ \t]+'"${class}"'[ \t]*\('|sed 's#//.*##g')
		fi

		if [[ $(echo "${constr}"|wc -l) -ge 2 ]] || [[ $(echo "${funct}"|wc -l) -ge 2 ]]; then echo "ERROR: ${fname}";	return; fi

		if [[ -z "${constr}" ]] && [[ ! -z "${funct}" ]]; then
			lnum=$(echo "${funct}"|sed 's#^[ ]*##g'|grep -o '^[0-9]\+')
			sig=$(sed -n "${lnum}$(echo "${funct}"|grep -q '{'|| echo ',/{/')"'p' "${fname}"|sed '2,$ s#^[ \t]*##g;s#//.*##g'|sed ':a;N;$!ba;s#[\r\n]# #g'|sed "${fmt}"|sed 's#)[^)]*$#)#')
			proto=$(echo "${sig}"|sed "s#${class}[^(]*(#__construct(#"|sed "${fmt}")
			call=$(echo "${sig}"|sed 's#&\$#\$#'|sed 's#\$[A-Za-z0-9_]+#&\n#g'|sed "s#.*${class}[^(]*(#\$this->${class}(#"|sed 's#(.*##g')
			params=$(echo "${sig}"|sed 's#&\$#\$#'|sed 's#\$[A-Za-z0-9_]\+#\n&\n#g'|grep '^\$'|sed ':a;N;$!ba;s#[\r\n]#, #g')
			#dump="error_log(__FILE__.':'.__LINE__.' ${class}()'.PHP_EOL,3,'/tmp/log'); "
			if [[ ! -z "${params}" ]]; then params=" ${params} ";fi
			echo -n "${lnum}."; ec=""
			if [[ -z "${nosave}" ]]; then sed -i "${lnum}"' i\'"${proto}"' { '"${dump}"''"${call}"'('"${params}"'); }' "${fname}"; fi
		fi
	done < <(grep -Po '^[ \t]*class[ \t]+[^ /(<]+( [\w]+)*' "${fname}")
	if [[ -z "${ec}" ]]; then echo -ne "${N} "; fi
}

function run_construct_format() {
	echo -ne "${B}";
	fname="$1"
	if [[ ! -f "${fname}" ]]; then echo "file ${fname} not found"; return; fi

	while IFS= read -r line; do
		buf=$(php -r '
			$buf = explode( ":",$argv[1] );
			preg_match( "/^([ \t]*)(.*)function/", $buf[1], $matchs );
			$final   = preg_match( "/final/",   $matchs[2])? "final "   : "";
			$static  = preg_match( "/static/",  $matchs[2])? "static "  : "";
			$context = preg_match( "/private/", $matchs[2])? "private " : ( preg_match( "/protected/", $matchs[2] )? "protected " : "public " );
			echo $buf[0].PHP_EOL.$matchs[1].$context.$final.$static."function __construct(".PHP_EOL;
		' "${line}")
		if [[ -z "${buf}" ]]; then continue; fi
		lnum=$(echo "${buf}"|head -n 1)
		exp=$(echo "${buf}"|tail -n 1)
		if [[ ! "${line}" == "${lnum}:${exp}" ]]; then
			echo -n "${lnum}."; ec="";
			if [[ -z "${nosave}" ]]; then sed -i ${lnum}' s#^[^(]*(#'"${exp}"'#' "${fname}"; fi
		fi
	done < <(grep -Pno '^[\w\d\t ]*function[ \t]+__construct[ \t]*\(' "${fname}")

	if [[ -z "${ec}" ]]; then echo -ne "${N} "; fi
}

if [[ "${#flist[@]}" -eq 0 ]]; then
	echo -n 'Searching files... ';
	while IFS= read -r -d $'\0' line; do flist+=("${line}"); done < <(find -type f -iname '*.php' -print0)
	echo -e "${R}${#flist[@]}${N} found. done."
fi

if [[ ! -z "${debug}" ]]; then set -x; fi

for filename in "${flist[@]}"; do
	ec="n"
	echo -ne "${G}${filename}${N}: ";

	run_construct_check "${filename}";
	run_construct_format "${filename}";

	if [[ -z "${ec}" ]]; then echo -e "${N}";
	else echo -ne "\r\033[0K\r"; fi
done
echo -e "${N}";
