<?php
/**
  * Ahead WebSoft Technologies Pvt Ltd.
  * @copyright  Copyright 2006-2026 Ahead WebSoft Technologies Pvt Ltd.
  * @license    https://www.socialengine.com/policies
*/
class Core_Plugin_Job_FileDownload extends Core_Plugin_Job_Abstract
{
  protected function _execute()
  {
    $file = $this->getParam('file');
    $url = $this->getParam('url');
    
    // File and url must be strings
    if( !is_string($file) || '' == $file ) {
      throw new Core_Model_Exception('File was not specified');
    }
    if( !is_string($url) || '' == $url ) {
      throw new Core_Model_Exception('URL was not specified');
    }

    // Parse url and check for validity
    $urlParts = parse_url($url);
    if( empty($urlParts['scheme']) ) {
      $urlParts['scheme'] = 'http';
    }
    if( empty($urlParts['host']) ) {
      throw new Core_Model_Exception('URL does not have a host');
    }
    if( empty($urlParts['path']) ) {
      $urlParts['path'] = '';
      //throw new Core_Model_Exception('URL does not have a path');
    }
    
    // Add application path if path isn't absolute
    if( $file[0] != '/' && $file[0] != '\\' && ($file[1] != ':' || $file[2] != '\\') ) {
      $file = APPLICATION_PATH . DIRECTORY_SEPARATOR . $file;
    }
    
    // Check if file exists and is not writable
    if( file_exists($file) && !is_writable($file) ) {
      throw new Core_Model_Exception('File exists and is not writable');
    }

    // Check if parent directory doesn't exist or is not writable
    $parentDir = dirname($file);
    if( !is_dir($parentDir) || !is_writable($parentDir) ) {
      throw new Core_Model_Exception('Parent directory does not exist or is not writable');
    }


    // Prepare curl
    $ch = curl_init();
    $mh = curl_multi_init();
    $fh = fopen($file, 'w');

    // Initialize default options
    if( strtoupper($this->getParam('method', 'GET')) == 'POST' ) {
      curl_setopt($ch, CURLOPT_POST, true);
    }
    $versionInfo = curl_version();
    curl_setopt($ch, CURLOPT_USERAGENT, 'curl/' . $versionInfo['version'] . ' (' . PHP_OS . '; SocialEngine)');
    curl_setopt($ch, CURLOPT_TIMEOUT, 3600); // Sigh @todo fix this
    curl_setopt($ch, CURLOPT_FAILONERROR, true);
    curl_setopt($ch, CURLOPT_REFERER, '');

    // Initialize custom options
    if( null != ($params = $this->getParam('params')) && is_array($params) ) {
      foreach( $params as $key => $value ) {
        if( !is_string($key) ) continue;
        $key = 'CURLOPT_' . strtoupper($key);
        if( defined($key) ) {
          curl_setopt($ch, constant($key), $value);
        }
      }
    }

    // Initialize required options
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_FILE, $fh);
    
    // Initialize mutli handle
    curl_multi_add_handle($mh, $ch);

    // Execute handles
    $running = null;
    $lastUpdate = 0;
    do {
      usleep(100 * 1000); // 100 milliseconds = 0.1 seconds
      curl_multi_exec($mh, $running);
      $info = curl_getinfo($ch);
      // Update info (once every second)
      if( microtime(true) > $lastUpdate + 1 ) {
        $lastUpdate = microtime(true);
        $this->_data['total'] = $info['download_content_length'];
        $this->_data['progress'] = $info['size_download'];
        $this->_data['speed'] = $info['speed_download'];
        $this->_data['mime'] = $info['mime'];
        // Update in db
        $this->_job->getTable()->update(array(
          'progress' => ($this->_data['total'] <= 0 ? 0 : $this->_data['progress'] / $this->_data['total']),
          'data' => Zend_Json::encode($this->_data),
        ), array(
          'job_id = ?' => $this->_job->job_id,
        ));
      }
    } while( $running > 0 );

    // Process info
    if( curl_errno($ch) > 0 ) {
      // throw on curl errors
      throw new Core_Model_Exception(curl_error($ch), curl_errno($ch));
    }

    // Close the handles
    curl_multi_remove_handle($mh, $ch);
    curl_multi_close($mh);
    curl_close($ch); // necessary?
    
    // Ok, we're done!
    $this->_setIsComplete(true);
  }
}
