<?php

if (!defined('ABSPATH'))
    exit; // Exit if accessed directly

class PTB_Upgrader extends WP_Upgrader {

    private $cookies;

    function upgrade_strings() {
        $this->strings['up_to_date'] = __('The plugin is at the latest version.', 'ptb');
        $this->strings['no_package'] = __('Update package not available.', 'ptb');
        $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>&#8230;', 'ptb');
        $this->strings['unpack_package'] = __('Unpacking the update&#8230;', 'ptb');
        $this->strings['remove_old'] = __('Removing the old version of the plugin&#8230;', 'ptb');
        $this->strings['remove_old_failed'] = __('Could not remove the old plugin.', 'ptb');
        $this->strings['process_failed'] = __('Plugin update failed.', 'ptb');
        $this->strings['process_success'] = __('Plugin updated successfully.', 'ptb');
    }

    function upgrade($plugin, $url, $cookies) {
        $this->cookies = $cookies;

        $this->init();
        $this->upgrade_strings();

        add_filter('upgrader_pre_install', array(&$this, 'deactivate_plugin_before_upgrade'), 10, 2);
        add_filter('upgrader_clear_destination', array(&$this, 'delete_old_plugin'), 10, 4);

        $this->run(array(
            'package' => $url,
            'destination' => WP_PLUGIN_DIR,
            'clear_destination' => true,
            'clear_working' => true,
            'hook_extra' => array(
                'plugin' => $plugin
            )
        ));

        // Cleanup our hooks, in case something else does a upgrade on this connection.
        remove_filter('upgrader_pre_install', array(&$this, 'deactivate_plugin_before_upgrade'));
        remove_filter('upgrader_clear_destination', array(&$this, 'delete_old_plugin'));

        if (!$this->result || is_wp_error($this->result))
            return $this->result;
    }

    function download_package($package) {

        if (!preg_match('!^(http|https|ftp)://!i', $package) && file_exists($package)) //Local file or remote?
            return $package; //must be a local file..

        if (empty($package))
            return new WP_Error('no_package', $this->strings['no_package']);

        $this->skin->feedback('downloading_package', $package);

        $download_file = $this->download_url($package);

        if (is_wp_error($download_file))
            return new WP_Error('download_failed', $this->strings['download_failed'], $download_file->get_error_message());

        return $download_file;
    }

    function download_url($url, $timeout = 300) {
        //WARNING: The file is not automatically deleted, The script must unlink() the file.
        if (!$url)
            return new WP_Error('http_no_url', __('Invalid URL Provided.', 'ptb'));

        $tmpfname = wp_tempnam($url);
        if (!$tmpfname)
            return new WP_Error('http_no_file', __('Could not create Temporary file.', 'ptb'));

        $response = wp_safe_remote_get($url, array('cookies' => $this->cookies, 'timeout' => $timeout, 'stream' => true, 'filename' => $tmpfname));

        if (is_wp_error($response)) {
            unlink($tmpfname);
            return $response;
        }

        if (200 != wp_remote_retrieve_response_code($response)) {
            unlink($tmpfname);
            return new WP_Error('http_404', trim(wp_remote_retrieve_response_message($response)));
        }

        return $tmpfname;
    }

    //Hooked to pre_install
    function deactivate_plugin_before_upgrade($return, $plugin) {

        if (is_wp_error($return)) //Bypass.
            return $return;

        $plugin = isset($plugin['plugin']) ? $plugin['plugin'] : '';
        if (empty($plugin))
            return new WP_Error('bad_request', $this->strings['bad_request']);
    }

    //Hooked to upgrade_clear_destination
    function delete_old_plugin($removed, $local_destination, $remote_destination, $plugin) {
        global $wp_filesystem;

        if (is_wp_error($removed))
            return $removed; //Pass errors through.

        $plugin = isset($plugin['plugin']) ? $plugin['plugin'] : '';
        if (empty($plugin))
            return new WP_Error('bad_request', $this->strings['bad_request']);

        $plugins_dir = $wp_filesystem->wp_plugins_dir();
        $this_plugin_dir = trailingslashit(dirname($plugins_dir . $plugin));

        if (!$wp_filesystem->exists($this_plugin_dir)) //If it's already vanished.
            return $removed;

        // If plugin is in its own directory, recursively delete the directory.
        if (strpos($plugin, '/') && $this_plugin_dir !== $plugins_dir) //base check on if plugin includes directory separator AND that it's not the root plugin folder
            $deleted = $wp_filesystem->delete($this_plugin_dir, true);
        else
            $deleted = $wp_filesystem->delete($plugins_dir . $plugin);

        if (!$deleted)
            return new WP_Error('remove_old_failed', $this->strings['remove_old_failed']);

        return true;
    }

    //return plugin info.
    function plugin_info() {
        if (!is_array($this->result) || empty($this->result['destination_name']))
            return false;

        $plugin = get_plugins('/' . $this->result['destination_name']); //Ensure to pass with leading slash
        if (empty($plugin))
            return false;

        $pluginfiles = array_keys($plugin); //Assume the requested plugin is the first in the list

        return $this->result['destination_name'] . '/' . $pluginfiles[0];
    }

}