diff --git a/public_html/deployment/classes/deploy-foreman.class.php b/public_html/deployment/classes/deploy-foreman.class.php
index 172d6eaa1b8543fb884dda9b6785ed2283f43063..08bbad588db1b4fa958bd8c19790bd6b4506455a 100644
--- a/public_html/deployment/classes/deploy-foreman.class.php
+++ b/public_html/deployment/classes/deploy-foreman.class.php
@@ -1,10 +1,14 @@
 <?php
-
 /**
  * deployForeman
  * 
  * foreman access to API
  * 
+ * @example
+ * $oForeman=new deployForeman($this->_aConfig['foreman']);
+ * $aForemanHostgroups=$oForeman->getHostgroups();
+ * or
+ * $aForemanHostgroups=$oForeman->getHostgroups(array('id'=>11));
  *
  * @author hahn
  */
@@ -12,9 +16,27 @@ class deployForeman {
 
     protected $_aCfg=array();
 
-    protected $_sApi=false;
-    protected $_sApiUser=false;
-    protected $_sApiPassword=false;
+    /**
+     * alloews methods and prefixes for methods
+     * @var array
+     */
+    protected $_aAllowedMethods=array(
+        'GET'=>'get', 
+        'POST'=>'create', 
+        'PUT'=>'update', 
+        'DELETE'=>'delete'
+    );
+    
+    protected $_aApiUrls=array(
+      'hostgroups'=>'hostgroups/',
+    );
+    
+    protected $_aRequest=array();
+    
+    
+    // ----------------------------------------------------------------------
+    // constructor
+    // ----------------------------------------------------------------------
     
     
     public function __construct($aCfg) {
@@ -24,9 +46,6 @@ class deployForeman {
         }
         $this->_aCfg=$aCfg;
         
-        $this->_sApi=$aCfg['api'];
-        $this->_sApiUser=array_key_exists('user', $aCfg) ? $aCfg['user'] : false;
-        $this->_sApiPassword=array_key_exists('password', $aCfg) ? $aCfg['password'] : false;
         return true;
     }
     // ----------------------------------------------------------------------
@@ -39,46 +58,127 @@ class deployForeman {
      * @param  string $sLevel    warnlevel of the given message
      * @return bool
      */
-    private function log($sMessage, $sLevel = "info") {
+    protected function log($sMessage, $sLevel = "info") {
         global $oCLog;
         return $oCLog->add(basename(__FILE__) . " class " . __CLASS__ . " - " . $sMessage, $sLevel);
     }
     
     /**
-     * make an http get request and return the response body
+     * helper function ... get the METHOD by scanning function and search for
+     * it in _aAllowedMethods
+     * i.e. "getHostname" --> returns GET
      * 
-     * @param string  $url        url for Foreman API
-     * @param string  $method     method; one of GET|POST|PUT|DELETE
-     * @param array   $aPostData  Post data (arrray [key]=>[value]))
-     * @param integer $iTimeout
+     * @return type
+     */
+    protected function _getMethod(){
+        $sReturn='';
+        foreach ($this->_aAllowedMethods as $sMethod=>$sPrefix){
+            if (strpos($this->_aRequest['function'], $sPrefix)===0){
+                $sReturn=$sMethod;
+                continue;
+            }
+        }
+        if (!$sReturn){
+            die("ERROR in ".__CLASS__."::".__FUNCTION__.": function ".$this->_aRequest['function']." does not map to a valid method.");
+        }
+        return $sReturn;
+    }
+
+
+    /**
+     * generate an url for foreman API request based on option keys
+     * - function
+     * - id
+     * - more
+     * 
+     * TODO: multiple items with ids
+     * POST /api/compute_profiles/:compute_profile_id/compute_resources/:compute_resource_id/compute_attributes
+     * 
+     * @param type $aOptions
      * @return string
      */
+    protected function _generateUrl(){
+        $sFunction=strtolower($this->_aRequest['function']);
+        foreach (array_values($this->_aAllowedMethods) as $sMethod){
+            $sFunction=preg_replace('/^'.$sMethod.'/i', '', $sFunction);
+        }
+        if (!array_key_exists($sFunction, $this->_aApiUrls)){
+            die("ERROR in ".__CLASS__."::".__FUNCTION__.": no API method found for function [".$aOptions['function']."].");
+        }
+        $sReturn=$this->_aApiUrls[$sFunction];
+
+        if (array_key_exists('id', $this->_aRequest)){
+            $sReturn.=(int)$aOptions['id'].'/';
+        }
+        if (array_key_exists('more', $this->_aRequest)){
+            $sReturn.=$aOptions['more'].'/';
+        }
+        return $sReturn;
+    }
     
-    private function _httpCall($url, $method='GET', $aPostData = false, $iTimeout = 5) {
-        $this->log(__FUNCTION__ . " start");
+    /**
+     * add parameter for search and paging in an foreman API URL
+     * 
+     * @return string
+     */
+    protected function _generateParams(){
+        $sUrl=$this->_aRequest['url'];
+        $sReturn=$sUrl.(strpos($sUrl, '?') ? '' : '?');
+        
+        // TODO: "sort by" and "sort order" ... need to be added here ... somehow
+        foreach(array('page', 'per_page', 'search') as $sParam){
+            if (array_key_exists($sParam, $this->_aRequest)){
+                $sReturn.='&'.$sParam.'='.urlencode($this->_aRequest[$sParam]);
+            }
+        }
+        return $sReturn;
+    }
+    /**
+     * make an http get request and return the response body
+     * it is called by _makeRequest
+     * $aRequest contains subkeys
+     * - url
+     * - method; one of GET|POST|PUT|DELETE
+     * - postdata; for POST only
+     * 
+     * @param array   $aRequest   arrayurl for Foreman API
+     * @return string
+     */
+    protected function _httpCall($aRequest=false, $iTimeout = 5) {
+        if ($aRequest){
+            $this->_aRequest=$aRequest;
+        }
+        // $url, $method='GET', $aPostData = false, $iTimeout = 5
+        $this->log(__FUNCTION__ . " start <pre>".print_r($this->_aRequest,1)."</pre>");
         if (!function_exists("curl_init")) {
             die("ERROR: PHP CURL module is not installed.");
         }
-        $sFullUrl=$this->_sApi.$url;
-        $this->log(__FUNCTION__ . " ".$method." $sFullUrl");
+        
+        $sApiUrl=$this->_aCfg['api'];
+        $sApiUser=array_key_exists('user', $this->_aCfg) ? $this->_aCfg['user'] : false;
+        $sApiPassword=array_key_exists('password', $this->_aCfg) ? $this->_aCfg['password'] : false;
+
+        $sFullUrl=$sApiUrl.$this->_aRequest['url'];
+        $this->log(__FUNCTION__ . " ".$this->_aRequest['method']." $sFullUrl");
         $ch = curl_init($sFullUrl);
 
-        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
-        if ($method==='POST'){
-            curl_setopt($ch, CURLOPT_POSTFIELDS, $aPostData);
+        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->_aRequest['method']);
+        if ($this->_aRequest['method']==='POST'){
+            curl_setopt($ch, CURLOPT_POSTFIELDS, $this->_aRequest['postdata']);
         }
         curl_setopt($ch, CURLOPT_HEADER, 1);
         curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
         curl_setopt($ch, CURLOPT_TIMEOUT, $iTimeout);
         curl_setopt($ch, CURLOPT_USERAGENT, 'IML Deployment GUI :: ' . __CLASS__);
-        if ($this->_sApiUser){
-            curl_setopt($ch, CURLOPT_USERPWD, $this->_sApiUser.":".$this->_sApiPassword);
+        if ($sApiUser){
+            curl_setopt($ch, CURLOPT_USERPWD, $sApiUser.":".$sApiPassword);
         }
+
         $res = curl_exec($ch);
         $aReturn=array('info'=>curl_getinfo($ch), 'error'=>curl_error($ch));
         curl_close($ch);
-        $this->log(__FUNCTION__ . " done url: $url");
+        $this->log(__FUNCTION__ . " status ".$aReturn['info']['http_code'].' '.$this->_aRequest['method']." $sFullUrl");
 
         $sHeader=substr($res, 0, $aReturn['info']['header_size']);
         $aReturn['header']=explode("\n", $sHeader);
@@ -102,31 +202,41 @@ class deployForeman {
      * - _OK: flag if result is OK and complete
      * - _status: info
      * 
-     * @param string  $url        url for Foreman API
-     * @param string  $method     method; one of GET|POST|PUT|DELETE
-     * @param array   $aPostData  Post data (arrray [key]=>[value]))
+     *      * $aRequest contains subkeys
+     * - function --> to extract method and generate url
+     * - method; one of GET|POST|PUT|DELETE
+     * - postdata; for POST only
+
+     * @param array   $aRequest   arrayurl for Foreman API
      * @return array
      */
-    public function makeRequest($url, $method='GET', $aPostData = false) {
+    public function makeRequest($aRequest=false) {
+        if ($aRequest){
+            $this->_aRequest=$aRequest;
+        }
         $sStatus='unknown';
         $bOk=false;
-
-        // check name of method
-        if(array_search($method, array('GET', 'POST', 'PUT', 'DELETE'))===false){
-            die("ERROR in ".__CLASS__."::".__FUNCTION__.": method $method is invalid or not supported.");
-        }
+        
+        $this->_aRequest['method']=$this->_getMethod();
         
         // prevent missing data because of paging
-        if ($method==='GET'){
-            $url.='?per_page=1000';
+        if ($this->_aRequest['method']==='GET' && !array_key_exists('per_page', $this->_aRequest)){
+            $this->_aRequest['per_page']=1000;
         }
-        if ($method==='POST' && (!$aPostData || !count($aPostData))){
+        // check postdata
+        if ($this->_aRequest['method']==='POST' && (!array_key_exists('postdata',$this->_aRequest) || !count($this->_aRequest['postdata']))){
             die("ERROR in ".__CLASS__."::".__FUNCTION__.": missing data to make a POST request");
         }
         
-        $aReturn=$this->_httpCall($url, $method);
+        // add url parameters (search, paging)
+        $this->_aRequest['url']=$this->_generateUrl();
+        $this->_aRequest['url']=$this->_generateParams();
         
-        // --- check status
+        // ----- request
+        $aReturn=$this->_httpCall();
+        
+        // ----- check result
+        // check status
         $iStatuscode=$aReturn['info']['http_code'];
         if ($iStatuscode===0){
             $sStatus='wrong host';
@@ -142,11 +252,11 @@ class deployForeman {
             $sStatus='wrong url';
         }
         
-        // --- check result json
+        // check result json
         if($bOk){
             $aJson=json_decode($aReturn['body'], 1);
             if (is_array($aJson)){
-                if ($aJson['total'] > $aJson['per_page']){
+                if (array_key_exists('total', $aJson) && $aJson['total'] > $aJson['per_page']){
                     $bOk=false;
                     $sStatus='Http OK, but incomplete results (paging)';
                 }
@@ -162,22 +272,40 @@ class deployForeman {
         return $aReturn;
     }
 
+    
     // ----------------------------------------------------------------------
-    // public functions
+    // public foreman functions
     // ----------------------------------------------------------------------
     
     /**
      * get list of host groups as an array with [id] => [name of title]
+     * $aOptions ... can contain optional subkeys
+     * - id - id of hostgroup
+     * - more - url behind "id"
+     * - search
+     * - page
+     * - per_page
+     * 
+     * @param array  $aOptions  
      * @return boolean
      */
-    public function getHostgroups() {
+    public function getHostgroups($aOptions=array()) {
         $aReturn=array();
-        $aData=$this->makeRequest('hostgroups/', 'GET');
+
+        $this->_aRequest=$aOptions;
+        $this->_aRequest['function']=__FUNCTION__;
+        $aData=$this->makeRequest();
         
         if (!$aData['_OK']){
             return false;
         }
-        if ($aData['_json']){
+        
+        // TODO: call a general method to create result array ... baased on
+        // $aOptions['result'] ...
+        
+        if (array_key_exists('id', $aOptions)){
+            $aReturn[$aData['_json']['id']]=$aData['_json']['title'];
+        } else if (array_key_exists('_json', $aData) && count($aData['_json'])){
             foreach ($aData['_json']['results'] as $aItem){
                 $aReturn[$aItem['id']]=$aItem['title'];
             }