Common Functions

  
<?php

	define('ROOT_URL', "api.fonts.com");
	define('MAIN_API_URL',"/rest/");

	define('PROJECTS', "Projects/");
	define('PROJECTSTYLES', "ProjectStyles/");
	define('PROJECTSTYLESEXPORT', "ProjectStylesExport/");
	define('PROJECTSTYLESIMPORT', "ProjectStylesImport/");
	define('SELECTORS', "Selectors/");
	define('DOMAINS', "Domains/");
	define('FONTS', "Fonts/");
	define('MESSAGE', "Message");
	define('SUCCESS', "Success");

class XMLToAssocArray {

  protected $_xml = '';

  public function __construct($xmlString){
    $this->_xml = new SimpleXmlElement($xmlString);
  }
  
  public function get(){
    return $this->_arrify($this->_xml);
  }

  protected function _arrify($entity){
    $arr = array();
    $entity = $this->_getSingleLevelTraversible($entity);
    foreach($entity as $property => $value){
      $element = $this->_getElementForThisLevel($value);
      $arr[$property] = $element;
    }
    return $arr;
  }

  protected function _getSingleLevelTraversible($entity){
    /* Must use get_object_vars because SimpleXML implements traversible interface, flattening out structure */
    return (is_object($entity)) ? get_object_vars($entity) : $entity;
  }

  protected function _getElementForThisLevel($value){
    if($this->_hasMoreLevels($value)) {
      return $this->_arrify($value);
    } else {
      return (string) $value;
    }
  }

  protected function _hasMoreLevels($value){
    return (is_array($value) || is_object($value));
  }

}

class ArraySearch {

  protected $_haystack = array();

  public function __construct($haystack){
    $this->_haystack = $haystack;
  }

  public function getArrayContaining($value){
    foreach($this->_haystack as $element){
      if(in_array($value, $element)) return $element;
    }
    return array();
  }
}

class Services_WFS{

	protected $wfspid = null;
	protected $uri = null;
	protected $wfspParams = null;
	protected $curlPost = null;
	protected $completeResponses = false;
	protected $_header = null;
	protected $_autoPublish = false;

	protected $public_key = null;
	protected $private_key = null;
	protected $api_key = null;
	
	/**
	* constructs a new WFS API instance
	*/
	public function __construct(){
	  $this->uri = "xml/";
	  $this->completeResponses = false;
	}
	
	/**
	*Set the required credentials needed to access the WFS API
	* @param string $publicKey
	* @param string $privateKey
	* @param string $apiKey
	* @return string - message that the server returned to test query.
	*/
	public function setCredentials($publicKey, $privateKey, $apiKey){
	  $this->public_key = $publicKey;
	  $this->private_key = $privateKey;
	  $this->api_key = $apiKey;
	}
	
	/**
	* set the id of the project that this object will use in requests to Web Fonts Service
	* @param string pid - the project id
	* @return string - message that the server returned to test query.
	*/
	public function setProjectKey($pkey){
	  $this->wfspid = $pkey;
	}


	/**
	* Change the return format in the request.
	* This automatically causes the API to return complete json/xml responses from the server to the caller
	* @param string $newFormat "json" for json, otherwise defaults to "xml"
	*/
	public function setOutputFormat($newFormat=""){
	  if($newFormat == "json"){
	    $this->uri = str_replace("xml/", "json/", $this->uri);
	    $this->completeResponses = true;
	  } elseif($newFormat == "xml"){	
	    $this->uri = str_replace("json/", "xml/", $this->uri);	
	    $this->completeResponses = true;
	  } else {
	    $this->uri = 'xml/';
	    $this->completeResponses = false;
	  }
	  
	}
	
	/**
	 * Set request parameters.
	 * @param int start - the start page
	 * @param int  limit - how many entries to fetch per page
	 */
	public function setWfspParams($start = "", $limit = ""){
	  if(is_numeric($start) && is_numeric($limit)){
	    $this->wfspParams = "&wfspstart=".$start."&wfsplimit=".$limit;
	  } else {
	    $this->wfspParams = null;
	  }
	}
	
	
	/**
	* Parse the $response into associative array
	* @param string response - the response from the api
	* @return string array - associative array of key-value-pairs
	*/
	protected function parseOutput($response, $potentialSingleElement = array()){
	  if($this->completeResponses === true) return $response;
	  $format = new XMLToAssocArray($response);
	  $parsed = $format->get();
	  if(empty($potentialSingleElement) || $this->completeResponses) {
	    return $parsed;
	  } else {
	    return $this->_turnSingleElementIntoOneElementArray($parsed, $potentialSingleElement);
	  }
	}

	/**
	* The API will not return a collection for a single element, this turns it into one
	* @param string parsed - the parsed API response
	* @return string array - the parsed API response with single elements in array
	*/
	protected function _turnSingleElementIntoOneElementArray($parsed, $potentialSingleElement){
	  extract($potentialSingleElement);
	  if(isset($parsed[$base][$search])) {
	    $parsed[$base] = array($parsed[$base]);
	  }
	  return $parsed;
	}

	protected function _listInternal($type){
	  $method = 'list' . ucfirst($type);
	  if(method_exists($this, $method)){
	    $caller = clone $this;
	    $caller->setOutputFormat();
	    $result = $caller->{$method}();
	    unset($caller);
	    return $result;
	  }
	}

	/*****************************************
	**************PROJECT FUNCTIONS***********
	*****************************************/

	/**
	* List all projects associated with this $wfs-object
	* @return an associative array of project name => project key -value pairs or xml/json if completeResponses is true
	**/
	public function listProjects(){
	  $limit = ($this->wfspParams) ? '?' . substr($this->wfspParams, 1) : '';
	  $response = $this->wfs_getInfo_post("", PROJECTS . $limit);	
	  return $this->_parseProjects($response);
	}
  
	/**
	* Protected helper function used to pass requests to parser function
	* @param string response - the response we want processed
	* @return string array - an associative array with project information
	*/
	protected function _parseProjects($response){
	  $potentialSingle = array('base' => 'Project', 'search' => 'ProjectKey');
	  return $this->parseOutput($response, $potentialSingle);
	}

	/****
	* Project adding function
	*@param string $wfs_project_name
	*@return string
	****/
	public function addProject($wfs_project_name) {
	  $this->curlPost.='&wfsproject_name='.$wfs_project_name;
	  $request = PROJECTS . $this->wfspParams;
	  $response = $this->wfs_getInfo_post("create", $request);
	  return $this->_parseProjects($response);
	}
  
  	/*
	* Project deleting function
	*@param string - name of project to delete
	*@return string - the remaining projects
	*/
	public function deleteProject($wfs_project_name){
	  $projectKey = $this->findProjectKeyByName($wfs_project_name);
	  if($projectKey){
	    return $this->deleteProjectByKey($projectKey);
	  } else{
	    return $this->listProjects();
	  }
	}

  	/*
	* Project deleting function
	*@param string - id of project to delete
	*@return string - the remaining projects
	*/
	public function deleteProjectByKey($projectKey){
	  $request = PROJECTS ."?wfspid=" .urlencode($projectKey) . $this->wfspParams;
	  $response = $this->wfs_getInfo_post("delete", $request);
	  return $this->_parseProjects($response);
	}
  
  	/**
	*Return the projectID corresponging the given project name
	*@param string projectName - the project name whose ID we want to get
	*@return string - the ID of the project, or null if not found
	*/
	public function findProjectKeyByName($projectName){
	  $projectList = $this->_listInternal('Projects');
	  $search = new ArraySearch($projectList['Project']);
	  $result = $search->getArrayContaining($projectName);
	  return empty($result) ? null : $result['ProjectKey']; 	
	}

    	/**
	*Changes name of project
	*@param string wfspid - the project id
	*@param string newName - the projects new name
	*@return array project list
	*/
	public function editProject($wfspid, $newName){
	  $this->curlPost = 'wfsproject_name=' . $newName;
	  $response = $this->wfs_getInfo_post("update", 'Projects/?wfspid=' . urlencode($wfspid));
	  return $this->_parseProjects($response);
	}


	/*****************************************
	************DOMAIN FUNCTIONS**************
	*****************************************/

	/*
	* List domains from the project 
	*/
	public function listDomains(){
	  $request = DOMAINS . "?wfspid=" . $this->wfspid . $this->wfspParams;
	  $response = $this->wfs_getInfo_post("", $request);	
	  return $this->parseOutput($response);
	}
	
	/**
	*Return the domainID corresponging the given domain name
	*@param string domainName - the domain name whose ID we want to get
	*@return string - the ID of the domain, or null if not found
	*/
	public function findDomainIdByName($domainName){
	  $domainList = $this->_listInternal('Domains');
	  $search = new ArraySearch($domainList['Domain']);
	  $result = $search->getArrayContaining($domainName);
	  return empty($result) ? null : $result['DomainID']; 	
	}

	/*
	* Domain adding function
	*@param string $wfs_domain_name
	*@return string
	*/
	public function addDomain($wfs_domain_name) {
	  $this->curlPost.='&wfsdomain_name='.$wfs_domain_name;
	  $request = DOMAINS . "?wfspid=" . $this->wfspid . $this->wfspParams;
	  $request .= ($this->_autoPublish) ? '' : '&wfsnopublish=1';
	  $response = $this->wfs_getInfo_post("create", $request);
	  return $this->parseOutput($response);
	}

	/*
	* Domain deleting function that can delete by domain name
	*@param string - name of domain to delete
	*@return array - the remaining domains in the project
	*/
	public function deleteDomain($wfs_domain_name){
	  $domainId = $this->findDomainIdByName($wfs_domain_name);
	  if($domainId){
	    return $this->deleteDomainById($domainId);
	  } else {
	    return $this->listDomains();
	  }
	}


	/*
	* Domain deleting function that deletes by domain id
	*@param string - id of domain to delete
	*@return array - the remaining domains in the project
	*/
	public function deleteDomainById($domainId){
	  $request = DOMAINS ."?wfspid=" . $this->wfspid . "&wfsdomain_id=".urlencode($domainId) . $this->wfspParams;
	  $request .= ($this->_autoPublish) ? '' : '&wfsnopublish=1';
	  $response = $this->wfs_getInfo_post("delete", $request);
	  return $this->parseOutput($response);
	}

	/*
	* Domain editing function
	*@param string $old_domain_name - the old name of domain
	*@param string $new_domain_name - the new name of domain
	*@return string - the domains in the project
	*/
	public function editDomain($old_domain_name, $new_domain_name) {
	  $wfs_domain_id = $this->findDomainIdByName($old_domain_name);
	  if(empty($wfs_domain_id)) return $this->listDomains();
	  $this->curlPost .= '&wfsdomain_name=' . $new_domain_name;
	  $request = DOMAINS . "?wfspid=" . $this->wfspid . $this->wfspParams . '&wfsdomain_id='.urlencode($wfs_domain_id);
	  $request .= ($this->_autoPublish) ? '' : '&wfsnopublish=1';
	  return $this->_executeEditDomainRequest($request);
	}


	/*
	* Utility function to wrap domain edit in try catch
	*@param string $request
	*@return array - the domains in the project
	*/
	protected function _executeEditDomainRequest($request){
	  try {
	    $response = $this->wfs_getInfo_post("update", $request);
	  } catch(Exception $e){
	    return array('Message' => 'Fail', 'Error' => 'Domain may not exist on this project.');
	  }
	  return $this->parseOutput($response);
	}


	/*****************************************
	************SELECTOR FUNCTIONS************
	*****************************************/

	/*
	* List Selectors from the project 
	*/
	public function listSelectors(){
	  $request = SELECTORS . "?wfspid=" . $this->wfspid . $this->wfspParams;
	  $response = $this->wfs_getInfo_post("", $request);	
	  return $this->_parseSelectors($response);
	}
	
	/**
	* Protected helper function used to pass requests to parser function
	* @param string msg - the message from which we want selectors extracted
	* @return string array - an associative array with selector information
	*/
	protected function _parseSelectors($response){
	  $potentialSingle = array('base' => 'Selector', 'search' => 'SelectorID');
	  return $this->parseOutput($response, $potentialSingle);
	}

	/**
	* Protected helper function to find out an id of selector based on its name.
	*@param string selectorName - the selector tag name whose ID we want to get
	*@return string - the ID of the selector, or null if not found
	*/
	protected function findSelectorIdByName($selectorName){
	  $selectorList = $this->_listInternal('Selectors');
	  $search = new ArraySearch($selectorList['Selector']);
	  $result = $search->getArrayContaining($selectorName);
	  return empty($result) ? null : $result['SelectorID']; 	
	}

	/*
	* Selector adding
	*@param string $wfs_selector_tag
	*@return arry list of selectors
	*/
	public function addSelector($wfs_selector_tag){
	  $this->curlPost.='&wfsselector_tag='.urlencode($wfs_selector_tag);
	  $request = SELECTORS . "?wfspid=" . $this->wfspid . $this->wfspParams;
	  $request .= ($this->_autoPublish) ? '' : '&wfsnopublish=1';
	  $response = $this->wfs_getInfo_post("create", $request);
	  return $this->_parseSelectors($response);
	}

	/*
	* Selector deletion
	*@param string $wfs_selector_tag
	*@return string - the remaining selectors in the project
	*/
	public function deleteSelector($wfs_selector_tag){
	  $selectorId = $this->findSelectorIdByName($wfs_selector_tag);
	  if($selectorId){
	    return $this->_deleteSelectorById($selectorId);
	  } else { 
	    return $this->listSelectors();
	  }
	}

	protected function _deleteSelectorById($selectorId){
	  $request = SELECTORS ."?wfspid=" . $this->wfspid . "&wfsselector_id=".urlencode($selectorId) . $this->wfspParams;
	  $request .= ($this->_autoPublish) ? '' : '&wfsnopublish=1';
	  $response =  $this->wfs_getInfo_post("delete", $request);
	  return $this->_parseSelectors($response);
	}

	/*
	* Selector deletion by SID without a lookup
	*@param string $sids comma separated list of selector ids or array of selector ids
	*@return string - the remaining selectors in the project
	*/
	public function deleteSelectorsBySid($sids){
	  $sels = (is_array($sids)) ? $sids : explode(',', $sids);
	  foreach($sels as $sid){
	    $result = $this->_deleteSelectorById($sid);
	  }
	  return $result;
	}


	/*
	* selector saving function
	* This function is used to pass the request to the server to assign font id's to selector id's
	*@param string $wfs_font_names - comma-separated list of font names
	*@param string $wfs_selector_names- comma-separated list of selector names
	*@return array - the selectors in the project
	*/
	public function saveSelector($wfs_font_names, $wfs_selector_names){
	  try {
	    $this->_prepareSelectorPostForUpdate($wfs_font_names, $wfs_selector_names);
	    $request = SELECTORS . "?wfspid=" . $this->wfspid . $this->wfspParams;
	    $request .= ($this->_autoPublish) ? '' : '&wfsnopublish=1'; 
	    $response = $this->wfs_getInfo_post("update", $request);
	    return $this->_parseSelectors($response);
	  } catch (Exception $e){
	    return array('Message' => 'Error.  Did you pass in an equal number of fonts and selectors that are both on the same project?');
	  }
	}

	protected function _prepareSelectorPostForUpdate($wfs_font_names, $wfs_selector_names){
	  $wfsFids = $this->_getFontIdsFromFontNameList($wfs_font_names);
	  $wfsSids = $this->_getSelectorIdsFromSelectorNameList($wfs_selector_names);
	  $this->_checkToMakeSureSameNumberOfArguments($wfsFids, $wfsSids);
	  $this->curlPost.='&wfsfont_ids='.urlencode(implode(",", $wfsFids));
	  $this->curlPost.='&wfsselector_ids='.urlencode(implode(",", $wfsSids));

	}

	protected function _getFontIdsFromFontNameList($wfs_font_names){
	  $fonts = $this->_listInternal('Fonts');
	  return $this->_extractMatchingValuesIntoArray($wfs_font_names, $fonts['Font'], 'FontName', 'FontID');
	}
	
	protected function _getSelectorIdsFromSelectorNameList($wfs_selector_names){
	  $selectors = $this->_listInternal('Selectors');
	  return $this->_extractMatchingValuesIntoArray($wfs_selector_names, $selectors['Selector'], 'SelectorTag', 'SelectorID');
	}

	protected function _extractMatchingValuesIntoArray($needles, $haystack, $possibleSearch, $desiredValue){
	  $names = explode(',', $needles);
	  $matches = array();
	  $search = new ArraySearch($haystack);
	  foreach($names as $desired){
	    $result = $search->getArrayContaining($desired);
	    if(!empty($result)) {
	      $matches[] = $result[$desiredValue];
	    }
	  }
	  return $matches;
	}

	protected function _checkToMakeSureSameNumberOfArguments($firstArray, $secondArray){
	  if(count($firstArray) !== count($secondArray)) {
	    throw new Exception('Selectors being assigned do not match the number of fonts being assigned!  Are they both on the same project?');
	  }
	}


	/*****************************************
	**************STYLESHEET FUNCTIONS********
	*****************************************/
  
	/**
	* Stylesheet adding function
	*@param token $wfs_project_token (later we'll use project name)
	*@return string
	**/
	public function exportStyleSheet($wfs_project_name) {
	  $projectID = $this->findProjectKeyByName($wfs_project_name);
	  $request = PROJECTSTYLESEXPORT . "?wfspid=" . $projectID . $this->wfspParams;
	  $response = $this->wfs_getInfo_post("", $request);
	  return $this->parseOutput($response);
	}

	/**
	* Stylesheet adding function
	*@param token $wfs_project_token (later we'll use project name)
	*@return string
	**/
	public function importStyleSheet($wfs_project_token) {
	  $request = PROJECTSTYLESIMPORT . "?wfspid=" . $this->wfspid . "&wfsptoken=" . urlencode($wfs_project_token) . $this->wfspParams;
	  $response = $this->wfs_getInfo_post("", $request);
	  return $this->parseOutput($response);
	}
	
	/**
	 * Stylesheet adding function
	 *@param token $wfs_project_token 
	 *@param name $selectorIDs comma separated ids 
	 *@return string
	 **/
	public function addStyleSheet($wfs_project_token, $selectorIDs) {
	  $this->curlPost .= '&wfsselector_ids='. urlencode($selectorIDs);
	  $request = PROJECTSTYLES . "?wfspid=" . $this->wfspid . "&wfsptoken=" . urlencode($wfs_project_token) . $this->wfspParams;
	  $response = $this->wfs_getInfo_post("create", $request);
	  return $this->parseOutput($response);
	}
  

	/*****************************************
	************ACCOUNT METHODS***************
	*****************************************/

    	/**
	* Public method used to create account
	* @param string firstName - First name of user
	* @param string lastName - Last name of user
	* @param string email - Email of user
	* @return array - an associative array with status message
	*/
	public function newAccount($firstName, $lastName, $email){
	  $this->curlPost = "?wfsfirst_name={$firstName}&wfslast_name={$lastName}&wfsemail={$email}";
	  $response = $this->wfs_getInfo_post('create', 'Accounts/');
	  return $this->parseOutput($response);
	}

    	/**
	* Public method used to generate OR get user Authentication Key (public key -- private key token)
	* @param string email - Email of user
	* @param string password - Password of user
	* @return array - an associative array with status message and key
	*/
	public function getAccountAuthenticationKey($email, $password, $generate = true){
	  $this->_header = array("AppKey: " . $this->api_key, 
				 "Password: " . $password);
	  if($generate === true){
	    $response = $this->wfs_getInfo_post(null, "Accounts/?wfsemail={$email}", 'https');
	  } else {
	    $response = $this->wfs_getInfo_post(null, "GetToken/?wfsemail={$email}", 'https');
	  }
	  return $this->parseOutput($response);
	}

	/*****************************************
	**********FILTER VALUES METHOD***********
	*****************************************/
	
    	/**
	* Public method to get available filters for a search
	* @param string filterType - 'designer', 'classification', 'foundry', or 'language'
	* @param string search - associative array with search information
	* @return array - an associative array with status message and key
	*/
	public function getLibraryFilterChoices($filterType, $search = array()){
	  $query = $this->_buildBaseSearchQuery($search);
	  if($query === '') return array();
	  $response = $this->wfs_getInfo_post('', 'FilterValues/?wfsfiltertype=' . $filterType . $query);
	  return $this->_parseFilters($response);
	}

	public function getAllLibraryFilterChoices($search){
	  $query = $this->_buildBaseSearchQuery($search);
	  $query = ($query) ? '?' . substr($query,1) : '';
	  $response = $this->wfs_getInfo_post('', 'AllFilterValues/' . $query);
	  return $this->_parseFilters($response);
	}

	protected function _buildBaseSearchQuery($search){
	  extract($search);
	  $query = '';
	  if($classification) $query .= '&wfsclassificationid=' . urlencode($classification);
	  if($designer) $query .= '&wfsdesignerid=' . urlencode($designer);
	  if($foundry) $query .= '&wfsfoundryid=' . urlencode($foundry);
	  if($language) $query .= '&wfslanguageid=' . urlencode($language);
	  return $query;
	}

	protected function _parseFilters($response){
	  $potentialSingle = array('base' => 'FilterValue', 'search' => 'ValueID');
	  return $this->parseOutput($response, $potentialSingle);
	}

	/*****************************************
	 **************FILTERS METHOD*************
	*****************************************/
	
    	/**
	* Public method to get available filters
	* @return array - an associative array with status message and key
	*/
	public function getLibraryFilters(){
	  $response = $this->wfs_getInfo_post('', 'Filters/');
	  $potentialSingle = array('base' => 'Filter', 'search' => 'FilterCount');
	  return $this->parseOutput($response, $potentialSingle);	  
	}

	/*****************************************
	 **************FONT METHODS**************
	*****************************************/

	/*
	* List fonts from the project
	* @return string array - an associative array of project name/project key - pairs
	*/
	public function listFonts(){
	  $request = FONTS . "?wfspid=" . $this->wfspid . $this->wfspParams;
	  $response = $this->wfs_getInfo_post("", $request);	
	  return $this->_parseFonts($response);
	}

	protected function _parseFonts($response){
	  $potentialSingle = array('base' => 'Font', 'search' => 'FontID');
	  return $this->parseOutput($response, $potentialSingle);
	}

	/**
	*Return the fontID corresponging the given font name from a project
	*@param string fontName - the font name whose ID we want to get
	*@return string - the ID of the font, or null if not found
	*/
	public function findFontIdByName($fontName){
	  $this->setOutputFormat();
	  $fontList = $this->_listInteral('Fonts');
	  $search = new ArraySearch($fontList['Font']);
	  $result = $search->getArrayContaining($fontName);
	  return empty($result) ? null : $result['FontID']; 
	}

    	/**
	* Public method to add font to project
	* @param int wfsfid - Font ID
	* @return array - an associative array with status message
	*/
	public function addFont($wfsfid){
	  $this->curlPost = 'wfsfid=' . urlencode($wfsfid);
	  $request = 'Fonts/?wfspid=' . urlencode($this->wfspid);
	  $request .= ($this->_autoPublish) ? '' : '&wfsnopublish=1';
	  $response = $this->wfs_getInfo_post("create", $request);
	  return $this->_parseFonts($response);
	}

    	/**
	* Public method to remove a font from project
	* @param int wfsfid - Font ID
	* @return array - an associative array with status message
	*/
	public function removeFont($wfsfid){
	  $request = 'Fonts/?wfspid=' . $this->wfspid . '&wfsfid=' . $wfsfid;
	  $request .= ($this->_autoPublish) ? '' : '&wfsnopublish=1';
	  $response = $this->wfs_getInfo_post("delete", $request);
	  return $this->_parseFonts($response);
	}
	
    	/**
	* Public method to search font database
	* @param array search- associative array of filter values to search on
	* @return array - an associative array with status message, position, and 
	*/
	public function filterFonts($search){
	  $this->_setLimitIfIncluded($search);
	  $query = $this->_getSearchQuery($search);
	  $response = $this->wfs_getInfo_post('', 'AllFonts/' . $query);
	  return $this->_parseFonts($response);
	}

    	/**
	* Protected method to transmute search params from array to string
	* @param array search- associative array of filter values to search on
	* @return str - query for API
	*/
	protected function _getSearchQuery($search){
	  extract($search);
	  $query = '';
	  if($classification) $query .= '&wfsClassId=' . urlencode($classification);
	  if($designer) $query .= '&wfsDesignerId=' . urlencode($designer);
	  if($foundry) $query .= '&wfsFountryId=' . urlencode($foundry);
	  if($language) $query .= '&wfsLangId=' . urlencode($language);
	  if($keyword) $query .= '&wfsKeyword=' . urlencode($keyword);
	  if($free) $query .= '&wfsFree=' . urlencode($free);
	  if($alphabet) $query .= '&wfsAlphabet=' . urlencode($alphabet);
	  $query .= ($query === '') ? substr($this->wfspParams, 1) : $this->wfspParams;
	  return ($query === '') ? '' : '?' . substr($query, 1);
	}

    	/**
	* Protected method to extract paginiation and set if used
	* @param array search- associative array of filter values to search on
	*/
	protected function _setLimitIfIncluded($search){
	  if(is_numeric($search['limitStart']) && is_numeric($search['limit'])){
	    $this->setWfspParams($search['limitStart'], $search['limit']);
	  } 
	}

    	/**
	* Public method to publish changes
	* @return string - Status of request
	*/
	public function publish(){
	  $response = $this->wfs_getInfo_post('', 'Publish/');
	  return $this->parseOutput($response);
	}
	
	/*
	 *core function for communication with api
	 * @param string method
	 * @param string uriEnding - the uri part after http://api.fonts.com/rest/{format}/...
	 * @param string protocol - the connection type, https needed for getAccountAuthenticationKey
	 */
	public function wfs_getInfo_post($method = "", $uriEnding, $protocol = 'http'){
	  $curlurl = $protocol . '://' . ROOT_URL.MAIN_API_URL.$this->uri.$uriEnding;
	  $data="";
	  $finalHeader = $this->public_key.":".$this->sign(MAIN_API_URL.$this->uri . $uriEnding, $this->public_key, $this->private_key);
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $curlurl);
		curl_setopt($ch, CURLOPT_HEADER, 0);
		curl_setopt($ch, CURLOPT_HTTPHEADER, $this->_getHeader($finalHeader));
		switch($method){
			case "create":
				curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
				break;
			case "update":
				curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
				break;
			case "delete":
				curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
				break;
			default:
				curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
				break;
		}
		if(!empty($this->curlPost)){
			curl_setopt($ch, CURLOPT_POST, 1);
			curl_setopt($ch, CURLOPT_POSTFIELDS, $this->curlPost);
			unset($this->curlPost);
		}
		$this->_thanksWindows($ch);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		$data=curl_exec($ch);
		curl_close($ch);
		if(trim($data)==""){
			//If the server returns an empty response, there is a fatal error in the
			//request passed to the server and there's nothing we can do.
			//Die and show the last passed curl-call to the user. 
		  throw new Exception("Curl received empty response from server to call: " . $curlurl);
		}
		return $data;
	}
	/*end curl*/

	protected function _thanksWindows(&$ch){
	  if($this->_isWindows()) {
	    curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/includes/cacert.pem');
	  }
	}

	protected function _isWindows(){
	  $operatingSystem = php_uname();
	  return (stripos($operatingSystem, 'Microsoft') !== false) || (stripos($operatingSystem, 'Windows') !== false);
	}

	public function sign($message, $publicKey, $privateKey){
               return base64_encode(hash_hmac('md5', $publicKey."|".$message, $privateKey, true));
	}

	protected function _getHeader($finalHeader){
	  if($this->_header) return $this->_header;
	  return array("Authorization: " . urlencode($finalHeader), "AppKey: ".$this->api_key);
	}

} //end class Services_WFS

?>