<?php
class package
{
    const VERSION = 'version';
    const CHANGES = 'changes';
    const INSTALL = 'install.php';
    const URL = 'http://updates.goshee.com';
    
    ////////////////////////////////////////////////////////////////////////////
    // Construct and destruct functions.
    
    ////////////////////////////////////////////////////////////////////////////
    // Overload functions.

    ////////////////////////////////////////////////////////////////////////////
    // Interface functions.
    
    public static function get_list()
    {
        $data = file_get_contents(self::URL);
        
        if (false === $data) {
            throw new Exception('Update server not available.');
        }
        
        $data = json_decode($data);
        
        if (false === $data || null === $data) {
            throw new Exception('Update server data is not valid.');
        }
        
        if (property_exists($data, 'error')) {
            throw new Exception($data->error);
        }
        
        return $data->packages;
    }
    
    public static function get($version)
    {
        $data = file_get_contents(self::URL . '?' . http_build_query(compact('version')));
        
        if (false === $data) {
            throw new Exception('Update server not available.');
        }
        
        $data = json_decode($data);
        
        if (false === $data || null === $data) {
            throw new Exception('Update server data is not valid.');
        }
        
        if (property_exists($data, 'error')) {
            throw new Exception($data->error);
        }
        
        if (!count($data->packages)) {
            throw new Exception('Package does not exist.');
        }
        
        return $data->packages[0];
    }
    
    public static function get_version()
    {
        if (!is_file(self::VERSION)) {
            throw new Exception('Package version file does not exist.');
        }
        
        return file_get_contents(self::VERSION);
    }
    
    public static function install($version)
    {
        $current = self::get_version();
        
        if ($version < $current) {
            throw new Exception('Version is out of date.');
        } else if ($version == $current) {
            throw new Exception('Version is up to date.');
        }
        
        $package = self::get($version);
        $data = file_get_contents($package->url);
        
        if (false === $data) {
            throw new Exception('Package archive is not available.');
        }
        
        $directory = sys_get_temp_dir() . '/' . md5(microtime(true) . $version) . '/';
        $file = $version . '.zip';
        mkdir($directory);
        file_put_contents($directory . $file, $data);
        $archive = new ZipArchive;
        
        if (!$archive->open($directory . $file)) {
            throw new Exception('Failed to open package archive.');
        }
        
        if (!$archive->extractTo($directory)) {
            throw new Exception('Failed to extract package archive.');
        }
        
        $archive->close();
        
        if (!file_exists($directory . self::INSTALL)) {
            throw new Exception('Package archive is missing install file.');
        }
        
        if (!file_exists($directory . self::CHANGES)) {
            throw new Exception('Package archive is missing changes file.');
        }
        
        if (!file_exists($directory . self::VERSION)) {
            throw new Exception('Package archive is missing version file.');
        }
        
        $changes = file_get_contents($directory . self::CHANGES);
        
        if (false === $changes) {
            throw new Exception('Package archive change file could not be opened.');
        }
        
        $version = file_get_contents($directory . self::VERSION);
        
        if (false === $version) {
            throw new Exception('Package archive versuib file could not be opened.');
        }
        
        if (!ob_start()) {
            throw new Exception('Cannot start output buffer.');
        }
        
        require $directory . self::INSTALL;
        
        file_put_contents(self::CHANGES, 'Version ' . $version . "\n\n" . $changes . "\n\n", FILE_APPEND);
        
        if (!file_put_contents(self::VERSION, $version)) {
            throw new Exception('Version file could not be updated.');
        }
        
        $log = ob_get_clean();
        
        if (!$log) {
            throw new Exception('Cannot retrieve output buffer.');
        }
        
        return $log;
    }
    
    ////////////////////////////////////////////////////////////////////////////
    // Internal functions.
}
