<?php
	/****************************** conversion function ********************************/
	function camelToLower($string) {
		$str = str_replace("_", ' ', $string);
		$str = preg_replace("/[^A-Za-z ]/", '', $str);
		$str = str_replace(" ", '', $str);
		return $str;
	}
	
	function lowerToCamel($string) {
		$str = str_replace("_", ' ', $string);
		$str = ucwords(strtolower($str));
		$str = str_replace(" ", '', $str);
		return $str;
	}
	
	function allToLower($string) {
		$str = trim($string);
		$str = str_replace("_", ' ', $str);
		$str = preg_replace('/\s\s+/', ' ', $str);
		$str = preg_replace("/[^A-Za-z ]/", '', $str);
		$str = str_replace(" ", '_', $str);
		$str = strtolower($str);
		return $str;
	}
	
	function lowerToName($string) {
		$str = ucwords(strtolower($string));
		$str = str_replace("_", ' ', $str);
		return $str;
		
	}
	
	function cut_str($html,$opener,$closer) {
		$start = strpos($html,$opener,0) + strlen($opener);
		
		if ($start > 0 && $start < strlen($html)) {		
			$end = strpos($html,$closer,$start);
		} else { $end = 0; $start = 0; } 
		
		$length = $end - $start;
		return substr($html,$start,$length);
	}

	/****************************** sidebar function ********************************/
	function get_mvc_files() {
		$models = array();
		$controllers= array();
		$views = array();
		$scaffold = array();
		$real_scaffold = array();
		
		foreach (glob("../../controllers/*.php") as $filename) { 
			$controllers[] = str_replace("../../controllers/","",$filename); 
			
			$sc = str_replace("../../controllers/","",$filename);
			$sc = str_replace(".php","",$sc);
			if (array_key_exists($sc,$scaffold)) {
				$scaffold[$sc]++;
			} else {
				$scaffold[$sc] = 1;
			}
		}
		foreach (glob("../../models/*.php") as $filename) { 
			$models[] = str_replace("../../models/","",$filename); 
			$sc = preg_replace('/([A-Z])([A-Z])/', '$1_$2', $filename);
			$sc = str_replace("../../models/","",strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $sc)));
			$sc = str_replace(".php","",$sc);
			
			if (array_key_exists($sc,$scaffold)) {
				$scaffold[$sc]++;
			} else {
				$scaffold[$sc] = 1;
			}
		}
		
		$public = array();
		foreach (glob("../../views/*") as $filename) { 
			if (is_dir($filename)) {				
				$sc = str_replace("../../views/","",$filename);				
				if (array_key_exists($sc,$scaffold)) { 
					$scaffold[$sc]++;
				} else {
					$scaffold[$sc] = 1;
				}
				
				$dir = array();
				foreach (glob("$filename/*") as $f) {
					if (!is_dir($f)) {				
						$dir[] = str_replace("$filename/","",$f);
					} else {
						$subdir = array();
						foreach (glob("$f/*") as $sf) {
							$subdir[] = array("name"=>str_replace("$f/","",$sf),"path"=>$sf);
						}
						$dir[] = array("name"=>str_replace("$filename/","",$f),"files"=>$subdir);
					}					
				}
				$views[] = array("name"=>str_replace("../../views/","",$filename),"files" => $dir);
				if ($sc == "public") $public = array_pop($views);
			}
		}
		
		if (count($public) > 0) {
			array_unshift($views,$public);
		}
		
		foreach (glob("../../views/*") as $filename) { if (!is_dir($filename)) $views[] = str_replace("../../views/","",$filename); }

		foreach ($scaffold as $key => $val ) {
			if ($val == 3) {
				$real_scaffold[] = array("name"=>$key,"check"=>scaffold_check_md5($key));
			}
		}
		
		return array("scaffolds"=>$real_scaffold,"models"=>$models,"views"=>$views,"controllers"=>$controllers);
	}
	
	function gen_render($file,$data) {		
		$h2o = new h2o($file, array());
        return $h2o->render($data);
	}
	
	function isNotAvailable($name) {		
		$mvc = get_mvc_files();
		
		foreach ($mvc["scaffolds"] as $scaff) {
			if ($name == $scaff) return true;
		}
		
		return false;
	}
	
	function remove($path) {
		error_reporting(0);
		chmod($path, 0777);
		error_reporting(E_ALL ^E_NOTICE);
		
		if (is_dir($path)) {
			rmdir($path);
		} else {
			unlink($path);
		}
	}
	
	function get_fields($fields) {
		foreach ($fields as $key=>$val) {
			$return[$key] = allToLower($val);
		}
		return $return;
	}
	
	function get_relation() {
		$relations = array();
		
		if (isset($_POST['relation'])) { 
			foreach ($_POST['relation'] as $relation) {
				$relations[] = array("name"=>$relation,"camel"=>lowerToCamel($relation));
			}
			
			return $relations;
		}
	}
	
	/**********************************************************/
	/************************ routing *************************/
	/**********************************************************/
	
	/*************** edit file *********************/
	function gen_edit() {
		$file = $_GET['file'];
		if ($file == "" || !is_file($file)) { redir_by_id("generator"); }
		
		$content = file_get_contents($file);
		$ext = substr($file,strrpos($file,".") +1,strlen($file) +1 -strrpos($file,"."));
		
		if ($ext == "") {
			$ext = "none";
		}
		
		$save_path = explode("?",$_SERVER['REQUEST_URI']);
		$root = getcwd();
		$root = str_replace("tempe/generator","",$root);
		$root = str_replace("tempe\generator","",$root);
		
		$save_path =  str_replace("generator/edit/","/edit",$save_path[0]) . "_save.php?file=$root".str_replace("../../","",$file);
		$path = str_replace("../../","",$file);
		$path = explode("/",$path);
		
		Slim::render('/editor.html',array(
			'files'=>get_mvc_files(),
			'content'=>$content,
			'mode'=>$ext,
			'file'=>$file,
			'path'=>$path,
			'save_path'=> $save_path
		));
	}
	
	Slim::get("/edit",function() {
		gen_edit();
	})->name("generator_edit");	
	
	/*************** Generate Authentication ****************/
	Slim::get("/auth",function() {
		Slim::render('auth.html',array(
			'files'=>get_mvc_files()
		));
	})->name("auth");
	
	/*************** Generate Scaffold ****************/
	Slim::get("/",function() {
		Slim::render('generator.html',array(
			'files'=>get_mvc_files()
		));
	})->name("generator");
	
	function gen_md5($name,$path) {
		if (is_file($path)) { 
			$file = file_get_contents($path);
			$md5 = R::dispense("md5");
			$md5->path = $path;
			$md5->md5 = md5($file);
			$md5->name = $name;
			R::store($md5);
		}
	}
	
	function scandir_through($dir) {
		$items = glob($dir . '/*');

		for ($i = 0; $i < count($items); $i++) {
			if (is_dir($items[$i])) {
				$add = glob($items[$i] . '/*');
				$items = array_merge($items, $add);
			}
		}

		return $items;
	}
	
	function scaffold_gen_md5($name) {
		gen_md5($name,"../../models/" . lowerToCamel($name) .".php");
		gen_md5($name,"../../controllers/".$name.".php");
		$viewfiles = scandir_through("../../views/" . $name);
		
		foreach ($viewfiles as $v) {
			if (is_file($v))
			gen_md5($name,$v);
		}
	}
	function scaffold_check_md5($name) {
		$q = "select * from md5 where name='$name'";
		$file = R::getAll($q);
		foreach ($file as $f) {
			if (is_file($f['path'])) 
			$content = file_get_contents($f['path']);
			if ($f['md5'] != md5($content)) { 
				return "changed";
			}
		}
		return "unchanged";
		
	}
	
	function scaffold_new() {
		$keyword = array('public','generator','index','columns','all','this');
		$name = $_POST['name'];
		if (in_array(allToLower($name),$keyword)) {
			Slim::flash('error',"Error: Cannot use $name, please use another name.");
		}
		else if (isNotAvailable($name)) {
			Slim::flash('error',"Error: Duplicate name $name, please use another name or delete current $name.");
		} else {
			post_model();
			post_view();
			post_controller();
			
			$relations = get_relation();
			if ($relations != null) {
				foreach ($relations as $r) {
					$q = "delete from md5 where path='../../models/".lowerToCamel($r['name']).".php'";
					$file = R::exec($q);
					
					gen_md5($name,"../../models/" . lowerToCamel($r['name']) .".php");
				}
			}
			scaffold_gen_md5($name);
			
			if (!isset($_SESSION['flash']['error']))
				Slim::flash('info',"Model,View,Controller \"$name\" generated");
		}
	}
	    
	Slim::post("/",function() {
		scaffold_new();
		redir_by_id("generator");
	});
	
	/*************** Delete Scaffold *********************/
	
	function scaffold_del($id) {	
		$class = lowerToCamel($id);
		
		if (!isset($id)) { redir_by_id("generator"); die(); }
		
		if (file_exists("../../models/$class.php")) remove("../../models/$class.php");
		if (file_exists("../../controllers/$id.php")) remove("../../controllers/$id.php");
		 
		foreach (glob("../../views/$id/*") as $filename) { 
			if (is_dir($filename)) {
				foreach (glob($filename. "/*") as $f) {
					remove($f);
				}
			}
			remove($filename);
		}
		
		$q = "delete from md5 where name='$id'";
		$file = R::exec($q);
		
		if (is_dir("../../views/$id")) remove("../../views/$id");		
	}
	Slim::get("/del_scaffold",function() {
		$id = $_GET['name'];
		scaffold_del($id);
		redir_by_id("generator");
	})->name("generator_del_scaffold");
	
	/*************** Edit Scaffold *********************/
	Slim::get("/edit_scaffold",function() {
		$id = $_GET['name'];
		if ($id == "") redir_by_id("generator");
		
		$class = lowerToCamel($id);
		$path = "../../models/$class.php";
		
		if (!is_file($path)) { 
			redir_by_id("generator");
			die();
		}
		
		$file = file_get_contents($path);
		
		//get name
		$name = $id;
		
		//get required fields
		$required = cut_str($file,'$rules = array();' . "\n","\n\t\t".'$errors = ');
		$required = explode('		$rules[] = "required,',$required);
		unset($required[0]);
		foreach ($required as $key=>$r) {
			$a = explode(",",$r);
			$required[$key] = $a[0];
		}
		
		//get fields
		$pos1 = strpos($file,"private static \$columns = \"");
		$pos2 = strpos($file,"\";",$pos1);
		$fields = substr($file,$pos1 +27,$pos2 - ($pos1 +27));
		$fields = explode(",",$fields); 
		
		$path = "../../views/$name/edit.html";
		$html = file_get_contents($path);
		require("../phpQuery-onefile.php");
		phpQuery::newDocument($html);
		
		foreach ($fields as $f) {
			$vl = array();
			$type = pq("[name=$f]")->attr("type");
			if ($type == null) {
				if (pq("select[name=$f]")->length > 0) $type = "select";
				else $type = "date";
			}
			if ($type == "radio" || $type == "checkbox") {
				for ($i = 0;$i < pq("input[name=$f]")->length; $i++) {
					$vl[] = array("label"=>pq("input[name=$f]")->eq($i)->parent()->text(),"value"=>pq("input[name=$f]")->eq($i)->val());
				};
			}
			if ($type == "select") {
				for ($i = 0;$i < pq("select[name=$f] option")->length; $i++) {
					$vl[] = array("label"=>pq("select[name=$f] option")->eq($i)->text(),"value"=>pq("select[name=$f] option")->eq($i)->val());
				};
			}
			$field_req = false;
			foreach ($required as $r) {
				if ($f == $r) { $field_req = true; break; }
			}
			$uf[] = array("name"=>$f,"type"=>$type,"required"=>$field_req,"value_label"=>$vl);
		}
		
		Slim::render('generator_edit.html',array(
			'files'=>get_mvc_files(),
			'name'=>$name,
			'fields'=>$uf
		));
	})->name("generator_edit_scaffold");
	
	Slim::post("/edit_scaffold",function() {
		if (isset($_GET['name'])) {
			$id = $_GET['name'];
			gen_view_field($id);
			scaffold_del($id);
			scaffold_new();
			redir_by_id("generator_edit_scaffold",array(),"?name={$_POST['name']}");
		} else {
			redir_by_id("generator");
		}
	});
	
	/***************** Generate Model *****************/
	Slim::get("/models",function() {
		Slim::render('model.html',array(
			'files'=>get_mvc_files()
		));
	})->name("generator_model");
	
	function post_model() {
		$name = allToLower($_POST['name']);
		$fields = get_fields($_POST['fields']);
		$types = get_fields($_POST['types']);
		$required = get_fields($_POST['required']);
		$module = (isset($_GET['module']) ? $_GET['module'] : "");
		
		
		if ($name != "" && count($fields) > 0 && $fields[0] != "") {
			$class = lowerToCamel($name);
			
			$fields_name = array();
			$fields_type = array();
			foreach ($fields as $key=>$f) {
				if ($f != "") {
					$fields_name[] = $f;
					$fields_type[] = $types[$key];
					$user_fields[] = array("name"=>$f,"type"=>$types[$key],"required"=>$required[$key]);
				}
			}
			
			if ($module == "auth") $module_path = 'template/auth/model.php';
			else $module_path = 'template/model.php';
			
			$generated = gen_render($module_path,array(
				'name' => $name,
				'class'=> $class,
				'columns'=>implode(",",$fields_name),
				'types'=>implode(",",$fields_type),
				'fields'=>$user_fields,
			));
			
			error_reporting(0);
			$content = file_put_contents("../../models/$class.php", $generated);
			chmod("../../models/$class.php", 0777);
			error_reporting(E_ALL ^E_NOTICE);
			
			if (!empty($content)) {
				Slim::flash('info',"Model $class generated.");
			} else {
				Slim::flash('error',"Error: Model File creation failed, permission denied. $content");
			}
		}	
		else {
			Slim::flash('error',"Error: Name or fields is not complete.");
		}	
	}	
	
	Slim::post("/models",function() {
		post_model();
		redir_by_id("generator_model");
	});
	
	/********************* Generate View *******************/
	Slim::get("/views",function() {
		Slim::render('/view.html',array(
			'files'=>get_mvc_files()
		));
	})->name('generator_view');
	
	function gen_view_field($scaffold,$mode = 'view') {
		$name = $scaffold;
		
		$fields_only = get_fields($_POST['fields']);
		$types = get_fields($_POST['types']);
		
		
		foreach ($fields_only as $key=>$f) {
			if ($f != "") {
				$value_label = array();
				if ($types[$key] == "dropdown" || $types[$key] == "checkbox" || $types[$key] == "radio") {
					$values = $_POST["{$f}_value"];
					$labels = $_POST["{$f}_label"];
					
					foreach($values as $vkey=>$v) {
						$value_label[] = array("value"=>$v,"label"=>$labels[$vkey]);
					}
				}
				
				$fields[] = array("name"=>$f,"type"=>$types[$key],"value_label"=>$value_label);
			}
		}
		if ($fields != "") { 
			if ($mode == 'login') {
				$content = "
			<form method='post'>
			<table>
				<tr>
					<td>{$fields[0]['name']}</td>
					<td><input type='text' name='{$fields[0]['name']}'/></td>
				</tr>
				<tr>
					<td>{$fields[1]['name']}</td>
					<td><input type='password' name='{$fields[1]['name']}'/></td>
				</tr>
				<tr>
					<td colspan='2'>
						<input type='submit' value='Login' />
					</td>
				</tr>
			</table>
			</form>
			";
			}
			else if ($mode == 'list') {
				$content = '<tr>
				<th>id</th>';
				foreach ($fields as $f) {
					$content .= "\n\t\t\t\t<th>{$f['name']}</th>";
				}
				$content .= "\n\t\t\t\t<th></th>\n\t\t\t".'</tr>
		{% for row in data %}
			<tr>
				<td>{{row.id}}</td>';
				foreach ($fields as $f) {
					$content .= "\n\t\t\t\t<td>{{row.{$f['name']}}}</td>";
				}
				$content .= '
				<td><a href="{% nav '.$name.' %}/{{ row.id }}">view</a>
				<a href="{% nav '.$name.'_edit %}/{{ row.id }}">edit</a>
				<a href="{% nav '.$name.'_del %}/{{ row.id }}">del</a></td>
			</tr>
		{% endfor %}';
			} else {
				$content = '<table cellpadding="0" cellspacing="0" border="0">' ."\n";
				foreach ($fields as $key=>$f) {
					$item = "\t\t\t\t<tr>\n\t\t\t\t\t<td>{{ field }}</td>\n\t\t\t\t\t<td>{{ value }}</td>\n\t\t\t\t</tr>\n";
					
					if ($mode == 'edit' || $mode == 'new') {
						switch ($f['type']) {
							case "string":
								$value = '<input type="text" name="'.$f['name'].'" value="{{ data.'.$f['name'].' }}"/>';
							break;
							case "dropdown":
								$value = "\n\t\t\t\t\t\t".'<select name="'.$f['name'].'">';
								foreach ($f['value_label'] as $vl) {
									$value .= "\n\t\t\t\t\t\t\t".'<option value="'.$vl['value'].'" {% if data.'.$f['name'].' == "'.$vl['value'].'"%}selected="selected"{%endif%}>'.$vl['label'].'</option>';
								}
								$value .= "\n\t\t\t\t\t\t".'</select>'."\n\t\t\t\t\t";
							break;
							case "checkbox":
								$value = "";
								foreach ($f['value_label'] as $vl) {
									$value .= "\n\t\t\t\t\t\t<label><input type=\"checkbox\" name=\"{$f['name']}\" value=\"{$vl['value']}\" {% if data.{$f['name']} == \"{$vl['value']}\"%}checked=\"checked\"{%endif%}/>{$vl['label']}</label>";
								} $value .= "\n\t\t\t\t\t";
							break;
							case "radio":
								$value = "";
								foreach ($f['value_label'] as $vl) {
									$value .= "\n\t\t\t\t\t\t<label><input type=\"radio\" name=\"{$f['name']}\" value=\"{$vl['value']}\" {% if data.{$f['name']} == \"{$vl['value']}\"%}checked=\"checked\"{%endif%}/>{$vl['label']}</label>";
								} $value .= "\n\t\t\t\t\t";
							break;
							case "date":
								$value = "{% date {$f['name']} year[2011-2030] %}";
							break;
						}
					} else if ($mode == 'view') {
						$value = "{{ data.{$f['name']} }}";
					}
					$item = str_replace("{{ value }}",$value,$item);
					$item = str_replace("{{ field }}",lowerToName($f['name']),$item);
					
					$content .= $item;
				}
				$content .= "\t\t\t</table>";
			}
			
			return $content;
		}
		return "";
	}
	
	function post_view() {
		$name = allToLower($_POST['name']);
		$fields = get_fields($_POST['fields']);
		
		
		if ($name != "" && count($fields) > 0 && $fields[0] != "") {
			$class = lowerToCamel($name);
			$view = lowerToName($_POST['name']);	
			$error = 0;
			
			//create view (and relation) directory
			error_reporting(0);
			mkdir("../../views/$name");
			chmod("../../views/$name", 0777);
			error_reporting(E_ALL ^E_NOTICE);
			
			//generate view file
			$module = $_GET['module'];
			if ($module == "auth") { $module_path = 'template/auth/view/*'; } 
			else { $module_path = 'template/view/*'; } 

			foreach (glob($module_path) as $path) { 
				$file = explode("/",$path);
				$file = $file[count($file) -1];
				$content = file_get_contents($path);
				$content = str_replace("[[view]]","$view",$content);
				$content = str_replace("[[name]]","$name",$content);
					
				if ($file == "view.html") {
					$content = str_replace("[[fields]]",gen_view_field($name,'view'),$content);
				} else if ($file == "edit.html") {
					$content = str_replace("[[fields]]",gen_view_field($name,'edit'),$content);
				} else if ($file == "new.html") {
					$content = str_replace("[[fields]]",gen_view_field($name,'new'),$content);
				} else if ($file == "login.html") {
					$content = str_replace("[[fields]]",gen_view_field($name,'login'),$content);					
				} else {
					$content = str_replace("[[fields]]",gen_view_field($name,'list'),$content);					
				} 
				
				$error += file_put_contents("../../views/$name/$file", $content);
				chmod("../../views/$name/$file", 0777);
			}
				
			//create view relation directory
			if ($error > 0) {
				Slim::flash('info',"View $name generated.");
			} else {
				Slim::flash('error',"Error: View File creation failed, permission denied. $error");
			}
		}	
		else {
			Slim::flash('error',"Error: Name or fields is not complete.");
		}	
	}
	
	Slim::post("/views",function() {
		post_view();
		redir_by_id("generator_view");
	});
	
	/******************* Generate Controller **********************/
	Slim::get("/controllers",function() {
		Slim::render('/controller.html',array(
			'files'=>get_mvc_files()
		));
	})->name("generator_controller");
	
	function post_controller() {
		$name = allToLower($_POST['name']);
		$fields = get_fields($_POST['fields']);
		$types = get_fields($_POST['types']);
		$required = get_fields($_POST['required']);
		$module = (isset($_GET['module']) ? $_GET['module'] : "");
		
		if ($name != "" && count($fields) > 0 && $fields[0] != "") {
			$class = lowerToCamel($name);

			$fields_name = array();
			$fields_type = array();
			foreach ($fields as $key=>$f) {
				if ($f != "") {
					$fields_name[] = $f;
					$fields_type[] = $types[$key];
					$user_fields[] = array("name"=>$f,"type"=>$types[$key],"required"=>$required[$key]);
				}
			}
			
			if ($module == "auth") { $module_path = 'template/auth/controller.php';
			} else { $module_path = 'template/controller.php'; }
			
			$generated = gen_render($module_path,array(
				'name' => $name,
				'class'=> $class,
				'columns'=> implode(",",$fields),
				'types'=>implode(",",$fields_type),
				'fields'=>$user_fields
			));
			
			error_reporting(0);
			$content = file_put_contents("../../controllers/$name.php", $generated);
			chmod("../../controllers/$name.php", 0777);
			error_reporting(E_ALL ^E_NOTICE);
			if (!empty($content)) {
				Slim::flash('info',"Controller $class generated.");
			} else {
				Slim::flash('error',"Error: Controller File creation failed, permission denied. $content");
			}
		}	
		else {
			Slim::flash('error',"Error: Name or fields is not complete.");
		}	
	}
	
	Slim::post("/controllers",function() {
		post_controller();
		redir_by_id("generator_controller");
	});	
?>
