<?php

// A class to handle process output - either to file, text output, or to an external site (Eggshell)

class output_base {

    private $connection;
    private $title;
    private $priority;
    private $ephemeral;
    protected $rc;
    protected $payload;
    protected $controller;
    protected $option = [];
    private $readwrite = FALSE;

    // if segmented, this will be run multiple times, each time only a specific segment is executed
    protected $segments;
    // when not FALSE, output from the task should be intercepted
    protected $asBackground = FALSE;
    
    static  $registered_module = NULL;
    
    public function __construct($priority = 0) {
        $this->Priority($priority)      // higher number takes priority over lower.
             ->Title('Untitled')
             ->Connection(NULL)
             ->Option('container', TRUE)
             ->Option('tabs', FALSE);
             
        $this->controller = new ModuleMain;
    }

    static
    public function Register() {
        $reg = new Static();
        if (static::$registered_module === NULL) {
            static::$registered_module = $reg;
        } elseif ($reg->Priority() > static::$registered_module->Priority()) {
            static::$registered_module = $reg;
        }
    }
    
    # get the active Registered transport
    static
    public function Transport() {
        return static::$registered_module;
    }

    public function Ephemeral() {
        if (func_num_args()) {
            $this->ephemeral = func_get_arg(0);
            $this->payload = $GLOBALS['loader']->GetEphemeral($this->ephemeral);
            if (!array_key_exists('current_segment', $this->payload)) {
                $this->payload['segments'] = [];            // scripts that have already been run
                $this->payload['current_segment'] = FALSE;  // segment being run
            }
            return $this;
        }
        return $this->ephemeral;
    }

    public function ReadWrite() {
        if (func_num_args()) {
            $this->readwrite = func_get_arg(0);
            return $this;
        }
        return $this->readwrite;
    }

    public function Priority() {
        if (func_num_args()) {
            $this->priority = func_get_arg(0);
            return $this;
        }
        return $this->priority;
    }

    public function Title() {
        if (func_num_args()) {
            $this->title = func_get_arg(0);
            return $this;
        }
        return $this->title;
    }

    public function Connection() {
        if (func_num_args()) {
            $this->connection = func_get_arg(0);
            return $this;
        }
        return $this->connection;
    }

    // Get/Set class-specific options
    public function Option($optionname) {
        if (func_num_args() > 1) {
            $this->option[$optionname] = func_get_arg(1);
            return $this;
        }
        return array_key_exists($optionname, $this->option) ? $this->option[$optionname] : FALSE;
    }

    public function ReturnCode() {
        if (func_num_args()) {
            $this->rc = func_get_arg(0);
            return $this;
        }
        return $this->rc;
    }

    // launch process and generate the initial HTML  
    public function Start($ephemeral_hash, $url) {
        $this->Ephemeral($ephemeral_hash);
    }
    
    public function StartConsole($server_id, $friendly, $generateContainerHTML = TRUE) {
		$hash = $GLOBALS['loader']->CreateEphemeral([
			'action' => 'console',
			'server_id' => $server_id,
            'friendly' => $friendly,
		]);

        $this->Title('Console')
                  ->Option('tabs', TRUE)
                  ->Option('server_id', $server_id)
                  ->Option('friendly', $friendly)
                  ->Option('container', $generateContainerHTML);
        $url = "/~/output/console/{$hash}";
        // eggshell::start() creates the HTML for the container
        return $this->Start($hash, $url);
    }
    
    // the process is about to be run 
    //  called from the PKP running as a background php process
    public function Prepare() {
        while (ob_get_level() > 0) {
			ob_end_flush();
		}
        $this->asBackground = TRUE;
    }
    
    // use handler to rewrite the command to use the appropriate Agent.
    public function prepareCommand($command) {
        return $command;
    }
    
    public function isBackground() {
        if (func_num_args()) {
            $this->asBackground = func_get_arg(0);
            return $this;
        }
        return $this->asBackground;
    }
    
    public function AdjustOutput($command) {
        return $command;
    }

    // has this script been executed?
    public function scriptStart($script) {
        $hash = md5($script);
        // script has been executed, don't run it again
        if (isset($this->payload['segments'][$hash]))
            return FALSE;
        
        $this->payload['current_segment'] = $hash;

        $GLOBALS['loader']->UpdateEphemeral($this->ephemeral, $this->payload);
        session_write_close();
        return TRUE;
    }

    protected function _scriptEnd() {
        $hash = $this->payload['current_segment'];
        $this->payload['current_segment'] = FALSE;
        if ($hash !== FALSE) {
            $this->payload['segments'][$hash] = 1;

            $GLOBALS['loader']->UpdateEphemeral($this->ephemeral, $this->payload);
        }
    }
    // indicate script has been executed
    // this typically will terminate the script at this point
    public function scriptEnd() {
        return $this->_scriptEnd();
    }
    
    // Restart the script, allowing it to resume from where it finished
    public function Restart() {
    }

    // the script is finished.
    public function Finish() {
        $this->payload['terminated'] = 1;
        $GLOBALS['loader']->UpdateEphemeral($this->ephemeral, $this->payload);
    }

    // the script is finished.
    public function isFinish() {
        return !empty($this->payload['terminated']);
    }

    protected function display() {
		if (!isset($this->__OUTPUT)) {
			if (!isset($GLOBALS['output_trait_info'])) {
				$GLOBALS['output_trait_info'] = new trait_info();
			}
			$this->__OUTPUT = $GLOBALS['output_trait_info'];
		}
        return $this->__OUTPUT;
    }
    
    public function fetchLastReturncode() {
        return 0;
    }
}