#!/usr/bin/php -q
<?
# CICrud 0.1
# Author Vladimir Grubor (grubor@gmail.com)
# Use ./cicrud.php  [(m)odel|(c)ontroller|(v)iew|(a)ll] [CI project folder] [table] [fields]
# or php cicrud.php  [(m)odel|(c)ontroller|(v)iew|(a)ll] [CI project folder] [table] [fields]
# cat textfile | xargs ./cicrud.php  [(m)odel|(c)ontroller|(v)iew|(a)ll] [CI project folder] [table]
# Script will overwrite existing file....

#Configuration

require_once("spyc.php5");

$author = 'Vladimir Grubor (grubor@gmail.com)';
$cifolder = '/system/application/'; // or 'system/application/'
$date = date('d.m.Y H:i'); // Date time format

#Parms
$mvc = $_SERVER['argv'][1];
$folder =getcwd() . $cifolder;
$table = $_SERVER['argv'][2];
$formDefsFolder= getcwd() . "/crud/formDefs/";

#table definition array for YAML to interpret
$table_def = array();

function model()
{
    global $folder,$table,$author,$date;
    $modelname = 'mod'.$table.'.php';
    $model = $folder.'/models/'.$modelname;
    echo "\nGenerating model...\n";
    $fp = fopen($model, 'w');
    fwrite($fp, "<?php if (!defined('BASEPATH')) exit('No direct script access allowed');\n");
    fwrite($fp, "/**\n");
    fwrite($fp, "* $table model\n");
    fwrite($fp, "*\n");
    fwrite($fp, "* @author $author\n");
    fwrite($fp, "* @date $date\n");
    fwrite($fp, "*/\n");
    fwrite($fp, "class mod$table extends Model {\n");
    fwrite($fp, '    var $id'.";\n");
    for($i=3;$i<count($_SERVER['argv']);$i++)
    {
        fwrite($fp, '    var $'.$_SERVER['argv'][$i].";\n");
    }
    fwrite($fp, "\n");
    fwrite($fp, '    var $select'.";\n");
    fwrite($fp, '    var $order'.";\n");
    fwrite($fp, '    var $limit'.";\n");
    fwrite($fp, '    var $limit2'.";\n");
    fwrite($fp, "\n");
    fwrite($fp, "    function mod$table(){\n");
    fwrite($fp, "        parent::Model();\n");
    fwrite($fp, "        \$this->load->database();\n");
    
    fwrite($fp, "    }\n\n");
    fwrite($fp, "    // --------------------------------------------------------------------\n\n");
    fwrite($fp,"    /**
    * Get rows from $table
    *
    * @access public
    * @param none
    * @return object
    */\n" );
    fwrite($fp, "    function get(){\n");
    fwrite($fp, "        if (\$this->id) \$this->db->where('id',\$this->id);\n");
    for($i=3;$i<count($_SERVER['argv']);$i++)
    {
        $var = $_SERVER['argv'][$i];
        fwrite($fp, "        if (\$this->$var) \$this->db->where('$var',\$this->$var);\n");
    }
    fwrite($fp, "        if (\$this->select) \$this->db->select(\$this->select);\n");
    fwrite($fp, "        if (\$this->order) \$this->db->order_by(\$this->order);\n");
    fwrite($fp, "        if (\$this->limit) \$this->db->limit(\$this->limit);\n");
    fwrite($fp, "        if (\$this->limit2) \$this->db->limit(\$this->limit,\$this->limit2);\n");
    fwrite($fp, "        \$query = \$this->db->get('$table');\n");
    fwrite($fp, "        if (\$this->id) return \$query->row();\n");
    fwrite($fp, "        else return \$query;\n");
    fwrite($fp, "    }\n\n");
    fwrite($fp, "    // --------------------------------------------------------------------\n\n");
    fwrite($fp,"    /**
    * Update or insert to $table
    *
    * @access public
    * @param none
    * @return integer
    */\n" );
    fwrite($fp, "    function save(){\n");
    for($i=3;$i<count($_SERVER['argv']);$i++)
    {
        $var = $_SERVER['argv'][$i];
        fwrite($fp, "        if (\$this->$var) \$this->db->set('$var',\$this->$var);\n");
    }
    fwrite($fp, "        if (\$this->id)\n        {\n");

    fwrite($fp, "            \$this->db->where('id',\$this->id);\n");
    fwrite($fp, "            \$this->db->update('$table');\n");
    fwrite($fp, "            return \$this->id;\n");
    fwrite($fp, "        }\n");
    fwrite($fp, "        else\n        {\n");
    
    fwrite($fp, "            \$this->db->insert('$table');\n");
    fwrite($fp, "            return \$this->db->insert_id();\n");
    fwrite($fp, "        }\n");
    fwrite($fp, "    }\n\n");
    fwrite($fp, "    // --------------------------------------------------------------------\n\n");
    fwrite($fp,"    /**
    * Delete row from $table
    *
    * @access public
    * @param integer
    * @return void
    */\n" );
    fwrite($fp, "    function del(\$id){\n");
    fwrite($fp, "            if (!is_array(\$id) || count(\$id) < 1) return;\n");
    fwrite($fp, "            \$ids = array_keys(\$id);\n");
    fwrite($fp, "            \$this->db->where_in('id', \$ids);\n");
    fwrite($fp, "            \$this->db->limit(count(\$ids));\n");
    fwrite($fp, "            \$this->db->delete('$table');\n");    
    fwrite($fp, "    }\n");
    fwrite($fp, "}\n");
    fwrite($fp, "/* End of file $modelname */\n");
    fwrite($fp, "/* Location: ./application/models/$modelname */\n");
    fclose($fp);
    
}

function controller()
{
    global $folder,$table,$author,$date;
    $controllername = $table;
    $controller = $folder.'/controllers/'.$controllername.'.php';
    $model = 'mod'.$table;
    echo "Generating controller...\n";
    $fp = fopen($controller, 'w');
    fwrite($fp,"<?php if (!defined('BASEPATH')) exit('No direct script access allowed');\n");
    
    fwrite($fp, "/**\n");
    fwrite($fp, "* $table controller\n");
    fwrite($fp, "*\n");
    fwrite($fp, "* @author $author\n");
    fwrite($fp, "* @date $date\n");
    fwrite($fp, "*/\n");
    
    fwrite($fp,"class $controllername extends Controller {\n\n");
    fwrite($fp,"    function $controllername(){\n");
    fwrite($fp,"        parent::Controller();\n");
    fwrite($fp,"        \$this->load->model('mod$table');\n");
	fwrite($fp,"        \$this->load->helper(\"url\");\n");
	fwrite($fp,"        \$this->load->helper(\"form\");\n");
    fwrite($fp,"    }\n\n");
    
    fwrite($fp,"    function index(){\n");
    fwrite($fp,"        \$data['$table'] = \$this->".$model."->get();\n");
    fwrite($fp,"        \$this->load->view(\"$table/list_view\", \$data);\n");
    fwrite($fp,"    }\n\n");
    // ADD: =====================================
    fwrite($fp,"    function add(){\n");
    fwrite($fp,"		\$this->load->library(\"validation\");\n\n");
    for($i=3;$i<count($_SERVER['argv']);$i++)
    {
        $var = $_SERVER['argv'][$i];
        fwrite($fp, "		\$rules['$var'] = 'trim|required';\n");
    }
    fwrite($fp,"		\$this->validation->set_rules(\$rules);\n\n");
	
	for($i=3;$i<count($_SERVER['argv']);$i++)
    {
        $var = $_SERVER['argv'][$i];
        fwrite($fp, "		\$fields['$var'] = '$var';\n");
    }
    fwrite($fp,"		\$this->validation->set_fields(\$fields);\n\n");
    fwrite($fp,"		\$this->validation->set_error_delimiters('<li>', '</li>');\n\n");
    fwrite($fp,"		if(\$this->validation->run())	{\n");
	
	for($i=3;$i<count($_SERVER['argv']);$i++)
    {
        $var = $_SERVER['argv'][$i];
        fwrite($fp, "			\$this->".$model."->$var = \$this->input->post(\"$var\");\n");
    }
    fwrite($fp,"			\$this->".$model."->save();\n");
    fwrite($fp,"			redirect(\"/$table\");\n");
    fwrite($fp,"		} else {\n");
	fwrite($fp,"				\$this->load->view(\"$table/add_view\");\n		\n\n		}\n");
    fwrite($fp,"    }\n\n");
	
	//
    // EDIT =========================================
	//
	
    fwrite($fp,"    function edit(\$id){\n");
	fwrite($fp,"		\$this->load->library(\"validation\");\n\n");
    for($i=3;$i<count($_SERVER['argv']);$i++)
    {
        $var = $_SERVER['argv'][$i];
        fwrite($fp, "		\$rules['$var'] = 'trim|required';\n");
    }
    fwrite($fp,"		\$this->validation->set_rules(\$rules);\n\n");
	
	for($i=3;$i<count($_SERVER['argv']);$i++)
    {
        $var = $_SERVER['argv'][$i];
        fwrite($fp, "		\$fields['$var'] =  '$var';\n");
    }
    fwrite($fp,"    	\$this->validation->set_fields(\$fields);\n\n");
	fwrite($fp,"		\$this->validation->set_error_delimiters('<li>', '</li>');\n\n");
    fwrite($fp,"    	if(\$this->validation->run())	{\n");
	
	for($i=3;$i<count($_SERVER['argv']);$i++)
    {
        $var = $_SERVER['argv'][$i];
        fwrite($fp, "			\$this->".$model."->$var = \$this->input->post(\"$var\");\n");
    }
	fwrite($fp,"        	\$this->".$model."->id = \$id;\n");
    fwrite($fp,"			\$this->".$model."->save();\n");
	fwrite($fp,"			redirect(\"/$table\");\n");
    fwrite($fp,"		} else {\n\n");
	fwrite($fp,"        	\$this->".$model."->id = \$id;\n");
	fwrite($fp,"			\$editable = \$this->".$model."->get();\n");
	fwrite($fp, "			\$data['id'] = \$editable->id;\n");
    for($i=3;$i<count($_SERVER['argv']);$i++)
    {
        $var = $_SERVER['argv'][$i];
        fwrite($fp, "			\$data['$var'] = \$editable->$var;\n");
    }
    fwrite($fp,"			\$this->load->view(\"$table/edit_view\", \$data);\n		\n		}\n");
    fwrite($fp,"    }\n\n");
	
	//
    // DEL =====================================
	//
	
    fwrite($fp,"    function del(\$id=null){\n");
    fwrite($fp,"        \$id = \$this->input->post('id');\n");
    fwrite($fp,'        $this->mod'.$table."->del(\$id);\n");
    fwrite($fp,"        redirect('$controllername');\n");
    fwrite($fp,"    }\n\n");
    fwrite($fp,"}\n");
    fwrite($fp, "/* End of file $controllername */\n");
    fwrite($fp, "/* Location: ./application/controllers/$controllername.php */\n");
    fclose($fp);
}

function get_field($fieldname, $type, $create_editable=0)	{
	$return_val = "";
	switch(strtolower($type))	{
		case "text":
			$return_val = "<label for=\"$fieldname\">$fieldname</label>		<input type=\"text\" name=\"$fieldname\" id=\"$fieldname\" ";
			if($create_editable)	{
				$return_val .= "value=\"<?= (\$this->validation->$fieldname) ? \$this->validation->$fieldname : \$$fieldname ?>\"";
			} else {
				$return_val .= "value=\"<?= (\$this->validation->$fieldname) ? \$this->validation->$fieldname : \"\" ?>\"";
			}
			/*if(count($properties) > 1)	{
				foreach($properties as $property)	{
					$return_val .= " " . addslashes($property);
				}
			}*/
			$return_val .= "><br/>\n";
			break;
			
		case "file":
			$return_val = "<label for=\"$fieldname\">$fieldname</label>		<input type=\"file\" name=\"$fieldname\" id=\"$fieldname\" ";
			if($create_editable)	{
				$return_val .= "value=\"<?= (\$this->validation->$fieldname) ? \$this->validation->$fieldname : \$$fieldname ?>\"";
			} else {
				$return_val .= "value=\"<?= (\$this->validation->$fieldname) ? \$this->validation->$fieldname : \"\" ?>\"";
			}
			/*if(count($properties) > 1)	{
				foreach($properties as $property)	{
					$return_val .= " " . addslashes($property);
				}
			}*/
			$return_val .= "><br/>\n";
			break;
			
		case "textarea":
			$return_val = "<label for=\"$fieldname\">$fieldname</label><textarea name=\"$fieldname\" id=\"$fieldname\">";
			$return_val .= "<?= (\$this->validation->$fieldname) ? \$this->validation->$fieldname : \"\" ?></textarea";
			$return_val .= "><br/>\n";
			break;
		case "radio":
			$return_val = "	<label for=\"$fieldname\">$fieldname</label>	<input type=\"radio\" name=\"$fieldname\" id=\"$fieldname\" ";
			if($create_editable)	{
				$return_val .= "value=\"<?= (\$this->validation->$fieldname) ? \$this->validation->$fieldname : \"1\" ?>\" <?=(\$$fieldname) ? \"checked='checked'\" : \"\" ?>";
			} else {
				$return_val .= "value=\"<?= (\$this->validation->$fieldname) ? \$this->validation->$fieldname : \"1\" ?>\"";
			}
			/*if(count($properties) > 1)	{
				foreach($properties as $property)	{
					$return_val .= " " . addslashes($property);
				}
			}*/
			
			/*$return_val .= " <?php echo set_radio('$fieldname', '" . $properties[1] . "'); ?> ";*/
			$return_val .= "><br/>\n";
			break;
		case "checkbox":
			$return_val = "	<label for=\"$fieldname\">$fieldname</label>	<input type=\"checkbox\" name=\"$fieldname\" id=\"$fieldname\" ";
			if($create_editable)	{
				$return_val .= "value=\"<?= (\$this->validation->$fieldname) ? \$this->validation->$fieldname : \"1\" ?>\" <?=(\$$fieldname) ? \"checked='checked'\" : \"\" ?>";
			} else {
				$return_val .= "value=\"<?= (\$this->validation->$fieldname) ? \$this->validation->$fieldname : \"1\" ?>\"";
			}
			/*if(count($properties) > 1)	{
				foreach($properties as $property)	{
					$return_val .= " " . addslashes($property);
				}
			}
			
			$return_val .= " <?php echo set_radio('$fieldname', '" . $properties[1] . "'); ?> ";*/
			$return_val .= "><br/>\n";
			break;
		case "submit":
			$return_val = "<input type='submit' name='submit' value='" . $type . "'";
			break;
		
	
	}
	
	if(strtolower($fieldname) == "special")	{
		$return_val = $type . "\n";
		
	}
	
	return $return_val;
}

function create_form($create_editable=0, $config)	{
	global $folder,$table,$author,$date;
	$form = "<form action=\"/" . $config['tablename'];
	
	
	
	if($create_editable)	{
		$form .= "/edit/<?=\$id?>\" method=\"post\">\n	<fieldset>";
	} else {
		$form .= "/add\" method=\"post\">\n	<fieldset>";
	}
	$form .= "<?php if(!empty(\$this->validation->error_string)) { ?>\n
	<fieldset>\n
		<legend>Errors</legend>\n
		<ul><?=\$this->validation->error_string; ?></ul> \n
	</fieldset><br/>\n
	<?php } ?>\n";
	unset($config['tablename']);
	
	foreach($config as $fieldname => $type)	{
		$form .= get_field($fieldname, $type, $create_editable);
	}
	

	$form .= "<input type=\"submit\" name=\"submit\" ";
	if($create_editable)	{
		$form .= "value=\"Save\">\n";
	} else {
		$form .= "value=\"Add\">\n";
	}
	$form .= "	</fieldset>\n</form>\n";
	return $form;
}

function view($config)
{
	global $folder,$table,$author,$date;
	$viewfolder = $folder."/views/".$table;
	@mkdir($viewfolder);
	echo "Generating Views...\n";
	$fp = fopen($viewfolder."/add_view.php", 'w');
	fwrite($fp, create_form(FALSE, $config));
    fclose($fp);
	
	$fp = fopen($viewfolder."/edit_view.php", 'w');
	fwrite($fp, create_form(TRUE, $config));
    fclose($fp);
	
	$fp = fopen($viewfolder."/list_view.php", 'w');
	
	fwrite($fp, "<form action='/$table/del' method='post'><table>\n");
	
	fwrite($fp, "	<tr>\n");

	for($i=3;$i<count($_SERVER['argv']);$i++)
    {
        $var = $_SERVER['argv'][$i];
        fwrite($fp, "	<td>$var</td>\n");
    }
	fwrite($fp, "	<td>&nbsp;</td><td>delete?</td>\n");
	fwrite($fp, "	</tr>\n");
	
	fwrite($fp, "<?php \nforeach(\$" . $table . "->result() as \$row) {\n");
	fwrite($fp, "echo \"<tr>\";\n");
	for($i=3;$i<count($_SERVER['argv']);$i++)
    {
        $var = $_SERVER['argv'][$i];
        fwrite($fp, "	echo \"<td>\" . \$row->$var . \"</td>\";\n");
    }
	fwrite($fp, "	echo \"<td><a href='/$table/edit/\$row->id'>Edit</a></td>\";\n");
	fwrite($fp, "	echo \"<td><input type='checkbox' name='id[\$row->id]' value='0'  /></td>\";\n");
	fwrite($fp, "echo \"</tr>\";\n");
	fwrite($fp, "}\n?>\n");
	
	fwrite($fp, "</table><input type='submit' name='submit' value='Delete'></form>\n");
	fwrite($fp, "<a href=\"/$table/add\">Add</a>\n");
	fclose($fp);
}

function getConfigFile($configFilename)	{
	global $formDefsFolder;
	$input = Spyc::YAMLLoad($formDefsFolder . $configFilename . ".yml");
	$config = array();
	foreach($input as $key => $arrays)	{
		$config["tablename"] =  $key;
		if(is_array($arrays))	{
			foreach($arrays as $item => $array)	{
				$config[ $item ] = $array[0];
			}
		}
	}
	
	return $config;
}

function createConfig($configFilename)	{
	global $formDefsFolder;
	$output = array();
	$fields = array();
	if(!file_exists($formDefsFolder . $configFilename . ".yml"))	{
		
		for($i=3;$i<count($_SERVER['argv']);$i++)
		{
			$var = $_SERVER['argv'][$i];
			$fields[$var] = array("text");
		}
		$output[$configFilename] = $fields;
		$yaml = Spyc::YAMLDump($output);
		$fp = fopen($formDefsFolder . $configFilename . ".yml", 'w');
		fwrite($fp, $yaml);
		fclose($fp);
	}

}

if ($mvc && $folder && $table)
{
	
    if (!is_dir($folder)) die("Error: Wrong CI Project folder please place in your CI root/crud folder : Use php crud/create [(m)odel|(c)ontroller|(v)iew|(a)ll] [table] [fields]\n");
    
	createConfig($table); 
	$config = getConfigFile($table);
	
	if ($mvc == 'm' or $mvc == 'model') model();
    else if ($mvc == 'c' or $mvc == 'controller') controller();
    else if ($mvc == 'v' or $mvc == 'view') view($config);
    else if ($mvc == 'a' or $mvc == 'all')
    {
		
        model();
        controller();
        view($config);
		
		
    }
    else die("Error: wrong argument (m) (v) (c) or (a)ll. Use php cicrud.php [(m)odel|(c)ontroller|(v)iew|(a)ll] [CI project folder] [table] [fields]\n");
}
else die("Error: no arguments. Use php crud/create [(m)odel|(c)ontroller|(v)iew|(f)file|(a)ll] [CI project folder] [table] [fields]\n");
?> 
