<?php
/*
 * FedoraClient is a PHP class to interact with web services
 *
 * Copyright (C) 2010  Remi Collet
 * http://github.com/remicollet/rpmphp.
 *
 * Inspired from python-fedora
 *
 * FedoraClient is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * python-fedora is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * See <http://www.gnu.org/licenses/>
 *
 */

define ('FEDORACLIENT_VERSION','0.1');

if (!function_exists('curl_version')) {
   die("curl extension required\n");
}
require_once('Cache/Lite.php');

abstract class FedoraClient {
   private $url;
   private $agent;
   private $debug = 0;
   protected $cache;

   function __construct ($url, array $options) {
      $dir = "/tmp/cachelite-".posix_getlogin()."/";
      @mkdir($dir);
      $this->cache = new Cache_Lite(array('memoryCaching'         => true,
                                          'cacheDir'              => $dir,
                                          'automaticSerialization'=> true));

      $this->url = $url;
      if (isset($options['agent']) && !empty($options['agent'])) {
         $this->agent = $options['agent'];
      } else {
         $this->agent = 'Fedora PHPClient/'.FEDORACLIENT_VERSION;
      }
      if (isset($options['debug']) && intval($options['debug'])>0) {
         $this->debug = intval($options['debug']);
      }
      $this->logDebug(3,__CLASS__."::".__FUNCTION__.": url='$url', agent='".$this->agent."'");
   }

   function logDebug($level, $msg) {
      if ($this->debug>=$level) {
         echo "[debug][$level] $msg\n";
      }
   }
   function sendRequest($method, array $options=array()) {
      $curl = curl_init();
        # And join to make our url.
      $url = $this->url.$method;
      curl_setopt($curl, CURLOPT_URL, $url);
        # Boilerplate so pycurl processes cookies
      curl_setopt($curl, CURLOPT_COOKIEFILE, '/dev/null');

        # Associate with the response to accumulate data
      $this->data='';
      curl_setopt($curl, CURLOPT_WRITEFUNCTION, array($this, 'receive'));

        # Follow redirect
      curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
      curl_setopt($curl, CURLOPT_MAXREDIRS, 5);

        # Set standard headers
      curl_setopt($curl, CURLOPT_HTTPHEADER, array('User-agent: '.$this->agent, 'Accept: application/json'));

        # run the request
      $this->logDebug(2,__CLASS__."::".__FUNCTION__.": call '$url'");
      curl_exec($curl);


        # Check for auth failures
        # Note: old TG apps returned 403 Forbidden on authentication failures.
        # Updated apps return 401 Unauthorized
        # We need to accept both until all apps are updated to return 401.
      $http_status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
      if ($http_status==401 || $http_status==403) {
         $this->logDebug(1,__CLASS__."::".__FUNCTION__.": http_status '$http_status' Authentication failed logging in");
         return array();
      } else if ($http_status>=400) {
         $this->logDebug(1,__CLASS__."::".__FUNCTION__.": http_status '$http_status' Unknown HTTP Server Response");
         return array();
      } else {
         $this->logDebug(2,__CLASS__."::".__FUNCTION__.": http_status '$http_status'");
      }

      $this->logDebug(2,__CLASS__."::".__FUNCTION__.": close connexion");

      curl_close($curl);
      return json_decode($this->data, true);
   }

   function receive($curl, $data) {
      $this->logDebug(9,__CLASS__."::".__FUNCTION__.": $data");
      $this->data .= $data;
      return strlen($data);
   }
}



class FedoraPkgdb extends FedoraClient {

   function __construct (array $options=array()) {
      parent::__construct('https://admin.fedoraproject.org/pkgdb/', $options);
      $this->logDebug(3,__CLASS__."::".__FUNCTION__);
   }

   function getBranches($refresh=false) {
      $rep = ($refresh ? false : $this->cache->get(__FUNCTION__,__CLASS__));
      if ($rep) {
         $this->logDebug(2,__CLASS__."::".__FUNCTION__."() get from cache");
      } else {
         $rep  =$this->sendRequest('collections');
         $this->cache->save($rep,__FUNCTION__,__CLASS__);
         $this->logDebug(2,__CLASS__."::".__FUNCTION__."() save to cache");
      }

      $branches = array();
      if (isset($rep['collections'])) {
         foreach ($rep['collections'] as $coll) if (isset($coll[0]['branchname'])) {
            $branches[$coll[0]['branchname']] = $coll[0];
         }
      }
      return $branches;
   }

   function getPackageInfo($name, $refresh=false) {
      $url="acls/name/$name";
      $rep = ($refresh ? false : $this->cache->get($url,__CLASS__));
      if ($rep) {
         $this->logDebug(2,__CLASS__."::".__FUNCTION__."($name) get from cache");
      } else {
         $rep  =$this->sendRequest($url);
         $this->cache->save($rep,$url,__CLASS__);
         $this->logDebug(2,__CLASS__."::".__FUNCTION__."($name) save to cache");
      }

      if (isset($rep['status']) && !$rep['status']) {
         $this->logDebug(1,__CLASS__."::".__FUNCTION__."($name) ".$rep['message']);
         return false;
      }
      $branches = array();
      foreach ($rep['packageListings'] as $pack) {
         $branches[$pack['collection']['branchname']] = $pack;
      }
      return $branches;
   }

   function getBranch($name, $refresh=false) {
      $branches = $this->getBranches($refresh);

      if (isset($branches[$name])) {
         return $branches[$name];
      }
      return false;
   }

   function getCritPath($refresh=false) {
      $url="lists/critpath";
      $rep = ($refresh ? false : $this->cache->get($url,__CLASS__));
      if ($rep) {
         $this->logDebug(2,__CLASS__."::".__FUNCTION__." get from cache");
      } else {
         $rep  =$this->sendRequest($url);
         $this->cache->save($rep,$url,__CLASS__);
         $this->logDebug(2,__CLASS__."::".__FUNCTION__." save to cache");
      }
      return $rep['pkgs'];
   }
}
?>