<?php

class Migrator{

    private static $instance;

    private $instaled;
    private $phisical;

    private $uninstall = Array();
    private $downgrade = Array();

    private $upgrade = Array();
    private $install = Array();

    private function __construct(){
        $this->load_installed_plugins();
        $this->load_physical_plugins();
    }

    private static function newObj(){
        if (!isset( self::$instance )) {
            self::$instance = new Migrator();
        }
        return self::$instance;
    }

    public static function getInstance(){
        if (!isset(self::$instance)) {
            return self::newObj();
        }
        return self::$instance;
    }

    private function save(){
        $out = '';
        foreach ($this->instaled as $instaled){
            $out .= "[$instaled->name]\n";
            $out .= "name=$instaled->name\n";
            $out .= "version=$instaled->version\n\n";
        }
        file_put_contents(DIR_CONFIG.'/modules.ini', $out);
    }

    private function is_satisfy($name, $version){
        if(!isset($this->instaled[$name])){
            return false;
        }
        if($this->instaled[$name]->version >= $version){
            return true;
        }
        return false;
    }

    private function is_satisfy_array($array){
        foreach ($array as $item){
            if( !self::is_satisfy($item->name, $item->version) ){
                return false;
            }
        }
        return true;
    }

    public function update_plugin_version($name, $version){
        echo "Atualizando $name para versão $version\n";
        if( isset($this->instaled[$name]) ){
            $this->instaled[$name]->version = $version;
            return;
        }
        $this->instaled[$name] = new stdClass();
        $this->instaled[$name]->name = $name;
        $this->instaled[$name]->version = $version;
    }

    private function load_installed_plugins(){
        $installed = parse_ini_file(DIR_CONFIG.'/modules.ini', true);

        foreach ($installed as $key => $item) {
            $installed[$key] = (object) $item;
        }

        return $this->instaled = $installed;
    }

    private function load_physical_plugins(){
        $module_configs = Array();
        $plugins = Array();

        $rdi = new RecursiveDirectoryIterator(DIR_MODULE);

        foreach(new RecursiveIteratorIterator($rdi) as $file){
            if( strpos($file, 'version.php') ){
                $module_configs[] = str_replace('version.php','', $file);
            }
        }
        foreach ($module_configs as $module_config) {
            $plugin = new stdClass();
            include $module_config . 'version.php';
            $plugins[$plugin->name] = $plugin;
            if(is_file( $module_config . 'db/Migrate.php') ){
                //echo 'aaaaaaaaaaaa';
                include $module_config . 'db/Migrate.php';
            }
        }
        $this->phisical = $plugins;
    }

    public function physical_list(){
        return $this->phisical;
    }

    public function installed_list(){
        return $this->instaled;
    }

    public function instal_list(){
        return $this->install;
    }

    public function uninstal_list(){
        return $this->uninstall;
    }

    public function sort_plugins(){
        foreach ($this->phisical as $key => $plugin){
            if( !isset($this->instaled[$key]) ){
                $this->install[] = $plugin;
                continue;
            }
            if( $this->instaled[$key]->version < $plugin->version){
                $this->upgrade[] = $plugin;
                continue;
            }
            if( $this->instaled[$key]->version > $plugin->version){
                $this->downgrade[] = $plugin;
                continue;
            }
            $this->uninstall[] = $plugin;
        }
    }

    public function execute_plan(){
        $status = false;
        while(! $status ){
            $this->sort_plugins();
            $status = true;
            
            foreach ($this->install as $key => $item) {
                if( isset($item->require) ){
                    if( !self::is_satisfy_array($item->require) ){ $status = false; continue; }
                }
                if(!self::is_satisfy($item->name, $item->version) ){
                    if(!function_exists($item->name.'_upgrade')){
                        $this->update_plugin_version($item->name, $item->version);
                        $this->upgrade[] = $item;
                        unset($this->install[$key]);
                        continue;
                    }
                    call_user_func($item->name.'_upgrade', 0);
                    $this->upgrade[] = $this->instaled[$item->name];
                    unset($this->install[$key]);
                    $status = false;
                }
            }
            
            foreach ($this->upgrade as $item) {
                if( isset($item->require) ){
                    if( !self::is_satisfy_array($item->require) ){ $status = false; continue; }
                }
                if(!self::is_satisfy($item->name, $item->version) ){
                    if(!function_exists($item->name.'_upgrade')){
                        $this->update_plugin_version($item->name, $item->version);
                        continue;
                    }
                    call_user_func($item->name.'_upgrade', $this->instaled[$item->name]->version);
                    $status = false;
                }
            }
        }
        $this->save();
    }

}