<?php 
/*
 * Created on 2008 Jun 22
 * by Martin Wernstahl <m4rw3r@gmail.com>
 */
class migrate extends Controller{
	var $ignore_classes = array('array','array_object','migrate','controller');
	function migrate(){
		parent::Controller();
		$this->load->database();
		$this->load->dbforge();
		$this->load->helper('url');
		if(file_exists(APPPATH.'/current_db_ver.txt'))
			$this->current = file_get_contents(APPPATH.'/current_db_ver.txt');
		else
			$this->current = 0;
	}
	function index(){
		$classes = array();
		foreach(get_declared_classes() as $class){
			if(stripos($class,'migrate') !== false && $class != 'migrate' && class_exists($class)){
				$classes[] = $class;
			}
		}
?>
<ul>
<?php foreach($classes as $class){
	$version = substr($class,8);
	echo "<li>".anchor('migrate/to/'.$version,$version)."</li>";
}
?>
</ul>

<?php
	}
	function to($version){
		if($version == $this->current){
			echo "<p>already at version $version</p>";
			return;
		}
		if($this->current < $version)
			$inc = 2;
		else
			$inc = 0;
		for($i = $this->current + $inc; ($i <= $version && $inc == 2) || ($i > $version && $inc == 0); $i = $i - 1 + $inc){
			$name = "migrate_".str_pad($i,3,'0',STR_PAD_LEFT);
			$obj = new $name();
			if($inc == 1)
				$obj->up($this);
			else
				$obj->down($this);
		}
		file_put_contents(APPPATH.'/current_db_ver.txt',$version);
		echo "<p>Done migrating to version $version</p>";
	}
}
class migrate_002{
	function up($CI){
		echo "going to version 2";
	}
	function down($CI){
		echo "going down from version 2";
	}
}
class migrate_001 extends IRM{
	function up(&$CI){
		echo "going to version 1";
		/*table('testaaaa')
			->column('id')
				->type('int')
				->options(array('auto_increment' => true,
					'unsigned' => true))
				->primary(true)
				->end()
			->column('lft')
				->type('int')
				->options(array('unsigned' => true))
				->index(true)
				->end()
			->column('rgt')
				->type('int')
				->options(array('unsigned' => true))
				->end()
			->column('title')
				->type('varchar')
				->options(array('constraint' => 100))
				->end()
					->execute();*/
	}
}
/**
 * 
 */
abstract class IRM{
	function IRM(){
		$CI =& get_instance();
		$this->db =& $CI->db;
		$this->dbforge =& $CI->dbforge;
	}
	abstract function up(&$CI);
	function down(&$CI){
		echo '!!!!';
	}
}
class IRM_table{
	var $columns = array();
	var $name;
	var $new_name;
	var $db;
	var $edited = true;
	var $new = true;
	function IRM_table($name, $options){
		$this->name = $name;
		$this->options = $options;
		$CI =& get_instance();
		$this->db =& $CI->db;
		$this->dbforge =& $CI->dbforge;
		$this->_load();
	}
	function _load(){
		if($this->db->table_exists($this->name)){
			foreach($this->db->list_fields($this->name) as $col){
				$obj  = new IRM_column($this->name,array($col, 'table_obj' => &$this));
				$obj->existing_name = $col;
				$obj->edited = false;
				$this->columns[] = $obj;
			}
			$this->edited = false;
			$this->new = false;
		}
	}
	function &rename($name){
		$this->new_name = $name;
		return $this;
	}
	function &column($name = null, $type = null, $options = array()){
		foreach($this->columns as $col){
			if($col->name == $name)
				return $col;
		}
		$args = array_merge(func_get_args(), array('table_obj' => &$this));
		$col = new IRM_column($this->name, $args);
		$this->columns[] =& $col;
		return $col;
	}
	function drop(){
		$this->dbforge->drop_table($this->name);
	}
	function execute(){
		if($this->new){
			foreach($this->columns as $column){
				if($column->edited == true)
					$column->execute(true);
			}
		}
		if($this->edited == true)
			$this->dbforge->create_table($this->name, TRUE);
		if(!$this->new){
			foreach($this->columns as $column){
				if($column->edited == true)
					$column->execute();
			}
		}
		if($this->new_name){
			$this->dbforge->rename_table($this->name,$this->new_name);
			$this->name = $this->new_name;
			foreach($this->columns as $col){
				$col->table = $this->name;
			}
		}
	}
}
class IRM_column{
	var $table;
	/**
	 * The new settings for this column
	 */
	var $opts;
	var $name;
	var $existing_name;
	var $type;
	var $edited = true;
	var $drop = false;
	var $index = false;
	var $primary = false;
	function IRM_column($table, $options = array()){
		$this->table = $table;
		$this->name = isset($options[0]) && $options[0] != null ? $options[0] : null;
		$this->type = isset($options[1]) && $options[1] != null ? $options[1] : null;
		$this->opts = isset($options[2]) && $options[2] != null ? $options[2] : array();
		$this->table_obj = isset($options['table_obj']) ? $options['table_obj'] : null;
		$CI =& get_instance();
		$this->db =& $CI->db;
		$this->dbforge =& $CI->dbforge;
	}
	function &name($name){
		$this->name = $name;
		$this->edited = true;
		return $this;
	}
	function &type($type){
		$this->type = $type;
		$this->edited = true;
		return $this;
	}
	function &primary($val = true){
		$this->primary = $val;
		$this->edited = true;
		return $this;
	}
	function &index($val = true){
		$this->index = $val;
		$this->edited = true;
		return $this;
	}
	function &options($options){
		$this->opts = $options;
		$this->edited = true;
		return $this;
	}
	function &drop(){
		$this->drop = true;
		$this->edited = true;
		return $this;
	}
	function execute($new = false){
		if($this->edited){
			if($this->drop && !$new){
				$this->dbforge->drop_column($this->table, $this->name);
				return;
			}
			if(!$new && $this->existing_name != null && $this->existing_name != $this->name){
				// rename
				$opts = array_merge(array(
						'name' => $this->name,'type' => $this->type),$this->opts);
				$opts = array(
						$this->existing_name => $opts);
				$this->dbforge->modify_column($this->table,$opts);
			}
			else{
				// add
				$opts = array_merge(array('type' => $this->type),$this->opts);
				$opts = array($this->name => $opts);
				if($new){
					$this->dbforge->add_field($opts);
				}
				else{
					$this->dbforge->add_column($this->table,$opts);
				}
			}
			if($this->primary){
				$this->dbforge->add_key($this->name, true);
			}
			if($this->index){
				$this->dbforge->add_key($this->name);
			}
		}
	}
	function &end(){
		return $this->table_obj;
	}
}
function &table($name, $options = array()){
	$table = new IRM_table($name, $options);
	return $table;
}
function &add_column($table, $name, $type = 'int', $options = array()){
	$obj = new IRM_column($table,array($name,$type,$options));
	$obj->execute();
}
?>