<?php
/**
* This class handles all methods of the RPCs
*/
class remotecontrol_handle
{
    /**
     * @var AdminController
     */
    protected $controller;

    /**
     * Constructor, stores the action instance into this handle class
     *
     * @access public
     * @param AdminController $controller
     * @return void
     */
    public function __construct(AdminController $controller)
    {
        $this->controller = $controller;
    }


    /**
     * RPC routine to create a session key.
     *
     * @access public
     * @param string $username
     * @param string $password
     * @return string
     */
    public function get_session_key($username, $password)
    {
        if ($this->_doLogin($username, $password))
        {
            $this->_jumpStartSession($username);
            $sSessionKey = randomChars(32);
            $sDatabasetype = Yii::app()->db->getDriverName();

            $session = new Session;
            $session->id = $sSessionKey;
            $session->expire = time() + Yii::app()->getConfig('iSessionExpirationTime');
            if($sDatabasetype=='sqlsrv' || $sDatabasetype=='mssql' || $sDatabasetype=='dblib')
                $username=new CDbExpression('CONVERT(VARBINARY(MAX), '.$db->quoteValue($username).')');            
            $session->data = $username;
            $session->save();
            return $sSessionKey;
        }
        else
            return array('status' => 'Invalid user name or password');
    }

    /**
     * Closes the RPC session
     *
     * @access public
     * @param string $sSessionKey
     * @return string
     */
    public function release_session_key($sSessionKey)
    {
        Session::model()->deleteAllByAttributes(array('id' => $sSessionKey));
        $criteria = new CDbCriteria;
        $criteria->condition = 'expire < ' . time();
        Session::model()->deleteAll($criteria);
        return 'OK';
    }

    /**
     * RPC Routine to get settings.
     *
     * @access public
     * @param string $sSessionKey Auth Credentials
     * @param string $sSetttingName Name of the setting to get
     * @return string The requested value
     */
   public function get_site_settings($sSessionKey,$sSetttingName)
    {
       if ($this->_checkSessionKey($sSessionKey))
       {
		   if(Permission::model()->hasGlobalPermission('superadmin','read'))
		   {
			   if (Yii::app()->getConfig($sSetttingName) !== false)
					return Yii::app()->getConfig($sSetttingName);
				else
					return array('status' => 'Invalid setting');
			}
			else
				return array('status' => 'Invalid setting');
        }
        else
			return array('status' => 'Invalid session key');
    }


	/* Survey specific functions */

	/**
     * RPC Routine to add an empty survey with minimum details.
     * Used as a placeholder for importing groups and/or questions.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID The wish id of the Survey to add
     * @param string $sSurveyTitle Title of the new Survey
     * @param string $sSurveyLanguage	Default language of the Survey
     * @param string $sformat Question appearance format
     * @return array|string|int
     */
	public function add_survey($sSessionKey, $iSurveyID, $sSurveyTitle, $sSurveyLanguage, $sformat = 'G')
	{
		Yii::app()->loadHelper("surveytranslator");
		if ($this->_checkSessionKey($sSessionKey))
        {
			if (Permission::model()->hasGlobalPermission('surveys','create'))
			{
				if( $sSurveyTitle=='' || $sSurveyLanguage=='' || !array_key_exists($sSurveyLanguage,getLanguageDataRestricted()) || !in_array($sformat, array('A','G','S')))
					return array('status' => 'Faulty parameters');

				$aInsertData = array('template' => 'default',
									'owner_id' => Yii::app()->session['loginID'],
									'active' => 'N',
									'language'=>$sSurveyLanguage,
									'format' => $sformat
									);

				if (!is_null($iSurveyID))
					$aInsertData['wishSID'] = $iSurveyID;

				try
				{
					$iNewSurveyid = Survey::model()->insertNewSurvey($aInsertData);
					if (!$iNewSurveyid)
							return array('status' => 'Creation Failed');

					$sTitle = html_entity_decode($sSurveyTitle, ENT_QUOTES, "UTF-8");

					// Load default email templates for the chosen language
					$oLanguage = new Limesurvey_lang($sSurveyLanguage);
					$aDefaultTexts = templateDefaultTexts($oLanguage, 'unescaped');
					unset($oLanguage);

					$bIsHTMLEmail = false;

					$aInsertData = array(
						'surveyls_survey_id' => $iNewSurveyid,
						'surveyls_title' => $sTitle,
						'surveyls_language' => $sSurveyLanguage,
						);

					$langsettings = new SurveyLanguageSetting;
					$langsettings->insertNewSurvey($aInsertData);
					Permission::model()->giveAllSurveyPermissions(Yii::app()->session['loginID'], $iNewSurveyid);

					return (int)$iNewSurveyid;
				}
				catch(Exception $e)
				{
					return array('status' => $e->getmessage());
				}
			}
			else
				return array('status' => 'No permission');
		}
		else
			return array('status' => 'Invalid session key');
	}

    /**
     * RPC Routine to delete a survey.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID The id of the Survey to be deleted
     * @return array Returns Status
     */
    public function delete_survey($sSessionKey, $iSurveyID)
    {
        if ($this->_checkSessionKey($sSessionKey))
        {
            if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'delete'))
            {
                Survey::model()->deleteSurvey($iSurveyID,true);
                return array('status' => 'OK');
            }
            else
                return array('status' => 'No permission');
        }
        else
			return array('status' => 'Invalid session key');
    }

    /**
     * RPC Routine to import a survey - imports lss,csv,xls or survey zip archive.
     *
     * @access public
     * @param string $sSessionKey Auth Credentials
     * @param string $sImportData String containing the BASE 64 encoded data of a lss,csv,xls or survey zip archive
     * @param string $sImportDataType  lss,csv,xls or zip
     * @param string $sNewSurveyName The optional new name of the survey
     * @param integer $DestSurveyID This is the new ID of the survey - if already used a random one will be taken instead
     * @return array|integer iSurveyID  - ID of the new survey
     */
    public function import_survey($sSessionKey, $sImportData, $sImportDataType, $sNewSurveyName=NULL, $DestSurveyID=NULL)
    {
        if ($this->_checkSessionKey($sSessionKey))
        {
            if (Permission::model()->hasGlobalPermission('surveys','create'))
            {
                if (!in_array($sImportDataType,array('zip','csv','xls','lss'))) return array('status' => 'Invalid extension');
                Yii::app()->loadHelper('admin/import');
                // First save the data to a temporary file
                $sFullFilePath = Yii::app()->getConfig('tempdir') . DIRECTORY_SEPARATOR . randomChars(40).'.'.$sImportDataType;
                file_put_contents($sFullFilePath,base64_decode(chunk_split($sImportData)));
                $aImportResults = importSurveyFile($sFullFilePath, true, $sNewSurveyName, $DestSurveyID);
                unlink($sFullFilePath);
                if (isset($aImportResults['error'])) return array('status' => 'Error: '.$aImportResults['error']);
                else
                {
                    return (int)$aImportResults['newsid'];
                }
            }
            else
                return array('status' => 'No permission');
        }
        else
			return array('status' => 'Invalid session key');
    }

    /**
     * RPC Routine to get survey properties.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID The id of the Survey to be checked
     * @param array $aSurveySettings The properties to get
     * @return array
     */
    public function get_survey_properties($sSessionKey,$iSurveyID, $aSurveySettings)
     {
         Yii::app()->loadHelper("surveytranslator");
        if ($this->_checkSessionKey($sSessionKey))
        {
             $oSurvey = Survey::model()->findByPk($iSurveyID);
             if (!isset($oSurvey))
             {
                 return array('status' => 'Error: Invalid survey ID');
             }
             if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'read'))
                 {
                     $aBasicDestinationFields=Survey::model()->tableSchema->columnNames;
                     $aSurveySettings=array_intersect($aSurveySettings,$aBasicDestinationFields);

                     if (empty($aSurveySettings))
                         return array('status' => 'No valid Data');
                     $aResult = array();
                     foreach($aSurveySettings as $sPropertyName)
                     {
                         $aResult[$sPropertyName]=$oSurvey->$sPropertyName;
                     }
                     return $aResult;
                 }
             else
                 return array('status' => 'No permission');
         }
         else
             return array('status' => 'Invalid Session key');
     }

    /**
     * RPC Routine to set survey properties.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param integer $iSurveyID  - ID of the survey
     * @param array|struct $aSurveyData - An array with the particular fieldnames as keys and their values to set on that particular survey
     * @return array Of succeeded and failed nodifications according to internal validation.
     */
    public function set_survey_properties($sSessionKey, $iSurveyID, $aSurveyData)
    {
        if ($this->_checkSessionKey($sSessionKey))
        {
            $oSurvey=Survey::model()->findByPk($iSurveyID);
            if (is_null($oSurvey))
            {
                return array('status' => 'Error: Invalid survey ID');
            }
            if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'update'))
            {
                // Remove fields that may not be modified
                unset($aSurveyData['sid']);
                unset($aSurveyData['owner_id']);
                unset($aSurveyData['active']);
                unset($aSurveyData['language']);
                unset($aSurveyData['additional_languages']);
                // Remove invalid fields
                $aDestinationFields=array_flip(Survey::model()->tableSchema->columnNames);
                $aSurveyData=array_intersect_key($aSurveyData,$aDestinationFields);
                $oSurvey=Survey::model()->findByPk($iSurveyID);
                $aBasicAttributes = $oSurvey->getAttributes();
                $aResult = array();

                if ($oSurvey->active=='Y')
                {
                    // remove all fields that may not be changed when a survey is active
                    unset($aSurveyData['anonymized']);
                    unset($aSurveyData['datestamp']);
                    unset($aSurveyData['savetimings']);
                    unset($aSurveyData['ipaddr']);
                    unset($aSurveyData['refurl']);
                }

				if (empty($aSurveyData))
					return array('status' => 'No valid Data');

                foreach($aSurveyData as $sFieldName=>$sValue)
                {
					$oSurvey->$sFieldName=$sValue;
					try
					{
						$bSaveResult=$oSurvey->save(); // save the change to database
						//unset the value if it fails, so as to prevent future fails
						$aResult[$sFieldName]=$bSaveResult;
						if (!$bSaveResult)
							$oSurvey->$sFieldName=$aBasicAttributes[$sFieldName];
					}
					catch(Exception $e)
					{
						//unset the value that caused the exception
						$oSurvey->$sFieldName=$aBasicAttributes[$sFieldName];
					}
                }
                return $aResult;
            }
            else
                return array('status' => 'No permission');
        }
        else
			return array('status' => 'Invalid Session key');
    }

    
    /**
     * RPC Routine that launches a newly created survey.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID The id of the survey to be activated
     * @return array The result of the activation
     */
    public function activate_survey($sSessionKey, $iSurveyID)
    {
        if ($this->_checkSessionKey($sSessionKey))
        {
            $oSurvey=Survey::model()->findByPk($iSurveyID);
            if (is_null($oSurvey))
                return array('status' => 'Error: Invalid survey ID');

            if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveyactivation', 'update'))
            {
                Yii::app()->loadHelper('admin/activate');
                $aActivateResults = activateSurvey($iSurveyID);

                if (isset($aActivateResults['error'])) return array('status' => 'Error: '.$aActivateResults['error']);
                else
                {
                    return $aActivateResults;
                }
            }
            else
                return array('status' => 'No permission');
        }
 		else
			return array('status' => 'Invalid session key');
    }

    /**
     * RPC routine to export statistics of a survey to a user.
     * Returns string - base64 encoding of the statistics.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID Id of the Survey
     * @param string $docType Type of documents the exported statistics should be
     * @param string $sLanguage Optional language of the survey to use
     * @param string $graph Create graph option
     * @param int|array $groupIDs An OPTIONAL array (ot a single int) containing the groups we choose to generate statistics from
     * @return string Base64 encoded string with the statistics file
     */
    public function export_statistics($sSessionKey, $iSurveyID,  $docType='pdf', $sLanguage=null, $graph='0', $groupIDs=null)
    {
		Yii::app()->loadHelper('admin/statistics');

		$tempdir = Yii::app()->getConfig("tempdir");
		if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key');

		$oSurvey = Survey::model()->findByPk($iSurveyID);
		if (!isset($oSurvey))
			return array('status' => 'Error: Invalid survey ID');;

		if(Survey::model()->findByPk($iSurveyID)->owner_id != $_SESSION['loginID'])
			return array('status' => 'Error: No Permission');
		$aAdditionalLanguages = array_filter(explode(" ", $oSurvey->additional_languages));

		if (is_null($sLanguage)|| !in_array($sLanguage,$aAdditionalLanguages))
			$sLanguage = $oSurvey->language;

		$oAllQuestions =Question::model()->getQuestionList($iSurveyID, $sLanguage);
       	if (!isset($oAllQuestions))
				return array('status' => 'No available data');
				
        if($groupIDs!=null)
        {
            if(is_int($groupIDs))
                    $groupIDs = array($groupIDs);
                
            if(is_array($groupIDs)) 
            {   
                //check that every value of the array belongs to the survey defined
                $aGroups = QuestionGroup::model()->findAllByAttributes(array('sid' => $iSurveyID));

                foreach( $aGroups as $group)
                    $validGroups[] = $group['gid'];

                $groupIDs=array_intersect($groupIDs,$validGroups);
                
                if (empty($groupIDs))
                    return array('status' => 'Error: Invalid group ID');
                                     
               foreach($oAllQuestions as $key => $aQuestion)  
                 {
					 if(!in_array($aQuestion['gid'],$groupIDs))
						unset($oAllQuestions[$key]);	 
				 }      
            }
            else
                return array('status' => 'Error: Invalid group ID');
		}
			
       	if (!isset($oAllQuestions))
				return array('status' => 'No available data');
				
		usort($oAllQuestions, 'groupOrderThenQuestionOrder');     
        
        $aSummary = createCompleteSGQA($iSurveyID,$oAllQuestions,$sLanguage);

        $helper = new statistics_helper();
		switch ($docType)
		{
			case 'pdf':
				$sTempFile = $helper->generate_statistics($iSurveyID,$aSummary,$aSummary,$graph,$docType,'F',$sLanguage);
				$sResult = file_get_contents($sTempFile);
				unlink($sTempFile);
				break;
			case 'xls':
				$sTempFile = $helper->generate_statistics($iSurveyID,$aSummary,$aSummary,'0',$docType, 'F',$sLanguage);
				$sResult = file_get_contents($sTempFile);
				unlink($sTempFile);
				break;
			case 'html':
				$sResult = $helper->generate_statistics($iSurveyID,$aSummary,$aSummary,'0',$docType, 'DD',$sLanguage);
				break;
		}

		return base64_encode($sResult);

	}

/**
     * RPC Routine to export submission timeline.
     * Returns an array of values (count and period)
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID Id of the Survey
     * @param string $sType (day|hour)
     * @param string $dStart
     * @param string $dEnd
     * @return array On success: The timeline. On failure array with error information
     * */
    public function export_timeline($sSessionKey, $iSurveyID, $sType, $dStart, $dEnd)
    {
		if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key');
		if (!in_array($sType, array('day','hour'))) return array('status' => 'Invalid Period');
		if (!hasSurveyPermission($iSurveyID, 'responses', 'read')) return array('status' => 'No permission');
		$oSurvey=Survey::model()->findByPk($iSurveyID);
		if (is_null($oSurvey)) return array('status' => 'Error: Invalid survey ID');
       	if (!tableExists('{{survey_' . $iSurveyID . '}}')) return array('status' => 'No available data');
       		
		$oResponses = SurveyDynamic::model($iSurveyID)->timeline($sType, $dStart, $dEnd);
		if (empty($oResponses))  return array('status' => 'No valid Data');

		return $oResponses;
		
	}
	
    /**
     * RPC routine to get survey summary, regarding token usage and survey participation.
     * Returns the requested value as string.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID Id of the Survey to get summary
     * @param string $sStatName Name of the sumamry option
     * @return string The requested value
     */
   public function get_summary($sSessionKey,$iSurveyID, $sStatName)
    {
       $aPermittedStats = array();
       if ($this->_checkSessionKey($sSessionKey))
       {
			$aPermittedTokenStats = array('token_count',
									'token_invalid',
									'token_sent',
									'token_opted_out',
									'token_completed'
									);
			$aPermittedSurveyStats  = array('completed_responses',
									'incomplete_responses',
									'full_responses'
									);
			$aPermittedStats = array_merge($aPermittedSurveyStats, $aPermittedTokenStats);
			$oSurvey = Survey::model()->findByPk($iSurveyID);
			if (!isset($oSurvey))
				return array('status' => 'Invalid surveyid');

			if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'read'))
			{
				if(in_array($sStatName, $aPermittedTokenStats))
				{
					if (tableExists('{{tokens_' . $iSurveyID . '}}'))
					{
						$summary = Token::model($iSurveyID)->summary();
					}
					else
						return array('status' => 'No available data');
				}

				if(in_array($sStatName, $aPermittedSurveyStats) && !tableExists('{{survey_' . $iSurveyID . '}}'))
					return array('status' => 'No available data');

				if (!in_array($sStatName, $aPermittedStats))
					return array('status' => 'No such property');


				switch($sStatName)
				{
					case 'token_count':
						if (isset($summary))
							return $summary['count'];
						break;
					case 'token_invalid':
						if (isset($summary))
							return $summary['invalid'];
						break;
					case 'token_sent':
						if (isset($summary))
							return $summary['sent'];
						break;
					case 'token_opted_out':
						if (isset($summary))
							return $summary['optout'];
						break;
					case 'token_completed';
						if (isset($summary))
							return $summary['completed'];
						break;
					case 'completed_responses':
						return SurveyDynamic::model($iSurveyID)->count('submitdate IS NOT NULL');
						break;
					case 'incomplete_responses':
						return SurveyDynamic::model($iSurveyID)->countByAttributes(array('submitdate' => null));
						break;
					case 'full_responses';
						return SurveyDynamic::model($iSurveyID)->count();
						break;
					default:
						return array('status' => 'Data is not available');
				}
			}
			else
			return array('status' => 'No permission');
        }
        else
			return array('status' => 'Invalid session key');
    }

	/*Survey language specific functions */

    /**
     * RPC Routine to add a survey language.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param integer $iSurveyID ID of the survey where a token table will be created for
     * @param string $sLanguage  A valid language shortcut to add to the current survey. If the language already exists no error will be given.
     * @return array Status=>OK when successfull, otherwise the error description
     */
    public function add_language($sSessionKey, $iSurveyID, $sLanguage)
    {
        if ($this->_checkSessionKey($sSessionKey))
        {
            $oSurvey=Survey::model()->findByPk($iSurveyID);
            if (is_null($oSurvey))
            {
                return array('status' => 'Error: Invalid survey ID');
            }
            if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'update'))
            {
                Yii::app()->loadHelper('surveytranslator');
                $aLanguages=getLanguageData();

                if(!isset($aLanguages[$sLanguage]))
                {
                    return array('status' => 'Invalid language');
                }
                $oSurvey=Survey::model()->findByPk($iSurveyID);
                if ($sLanguage==$oSurvey->language)
                {
                    return array('status' => 'OK');
                }
                $aLanguages=$oSurvey->getAdditionalLanguages();
                $aLanguages[]=$sLanguage;
                $aLanguages=array_unique($aLanguages);
                $oSurvey->additional_languages=implode(' ',$aLanguages);
                try
                {
                    $oSurvey->save(); // save the change to database
                    $languagedetails=getLanguageDetails($sLanguage);

                    $insertdata = array(
                    'surveyls_survey_id' => $iSurveyID,
                    'surveyls_language' => $sLanguage,
                    'surveyls_title' => '',
                    'surveyls_dateformat' => $languagedetails['dateformat']
                    );
                    $setting= new SurveyLanguageSetting;
                    foreach ($insertdata as $k => $v)
                        $setting->$k = $v;
                    $setting->save();
                    fixLanguageConsistency($iSurveyID,$sLanguage);
                    return array('status' => 'OK');
                }
                catch(Exception $e)
                {
                    return array('status' => 'Error');
                }

            }
            else
                return array('status' => 'No permission');
        }
    }

    /**
     * RPC Routine to delete a survey language.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param integer $iSurveyID ID of the survey where a token table will be created for
     * @param string $sLanguage  A valid language shortcut to delete from the current survey. If the language does not exist in that survey no error will be given.
     * @return array Status=>OK when successfull, otherwise the error description
     */
    public function delete_language($sSessionKey, $iSurveyID, $sLanguage)
    {
        if ($this->_checkSessionKey($sSessionKey))
        {
            $oSurvey=Survey::model()->findByPk($iSurveyID);
            if (is_null($oSurvey))
            {
                return array('status' => 'Error: Invalid survey ID');
            }

            if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'update'))
            {

                Yii::app()->loadHelper('surveytranslator');
                $aLanguages=getLanguageData();

                if(!isset($aLanguages[$sLanguage]))
                {
                    return array('status' => 'Invalid language');
                }
                $oSurvey=Survey::model()->findByPk($iSurveyID);
                if ($sLanguage==$oSurvey->language)
                {
                    return array('status' => 'Cannot remove base language');
                }
                $aLanguages=$oSurvey->getAdditionalLanguages();
                unset($aLanguages[$sLanguage]);
                $oSurvey->additional_languages=implode(' ',$aLanguages);
                try
                {
                    $oSurvey->save(); // save the change to database
                    SurveyLanguageSetting::model()->deleteByPk(array('surveyls_survey_id' => $iSurveyID, 'surveyls_language' => $sLanguage));
                    cleanLanguagesFromSurvey($iSurveyID,$oSurvey->additional_languages);
                    return array('status' => 'OK');
                }
                catch(Exception $e)
                {
                    return array('status' => 'Error');
                }

            }
            else
                return array('status' => 'No permission');
        }
    }


    /**
     * RPC Routine to get survey language properties.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID Dd of the Survey
     * @param array $aSurveyLocaleSettings Properties to get
     * @param string $sLang Language to use
     * @return array The requested values
     */
   public function get_language_properties($sSessionKey,$iSurveyID, $aSurveyLocaleSettings, $sLang=NULL)
    {
		Yii::app()->loadHelper("surveytranslator");
       if ($this->_checkSessionKey($sSessionKey))
       {
			$oSurvey = Survey::model()->findByPk($iSurveyID);
			if (!isset($oSurvey))
			{
				return array('status' => 'Error: Invalid survey ID');
			}
			if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'read'))
				{
					$aBasicDestinationFields=SurveyLanguageSetting::model()->tableSchema->columnNames;
					$aSurveyLocaleSettings=array_intersect($aSurveyLocaleSettings,$aBasicDestinationFields);

					if ($sLang == NULL || !array_key_exists($sLang,getLanguageDataRestricted()))
						$sLang = $oSurvey->language;


					$oSurveyLocale=SurveyLanguageSetting::model()->findByAttributes(array('surveyls_survey_id' => $iSurveyID, 'surveyls_language' => $sLang));
					$aResult = array();

					if (empty($aSurveyLocaleSettings))
					return array('status' => 'No valid Data');

					foreach($aSurveyLocaleSettings as $sPropertyName)
					{
							$aResult[$sPropertyName]=$oSurveyLocale->$sPropertyName;
						//$aResult[$sPropertyName]=$aLangAttributes[$sPropertyName];
					}
					return $aResult;
				}
			else
				return array('status' => 'No permission');
        }
        else
			return array('status' => 'Invalid Session key');
    }

    /**
     * RPC Routine to set survey language properties.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param integer $iSurveyID  - ID of the survey
     * @param array|struct $aSurveyLocaleData - An array with the particular fieldnames as keys and their values to set on that particular survey
     * @param string $sLanguage - Optional - Language to update  - if not give the base language of the particular survey is used
     * @return array Status=>OK, when save successful otherwise error text.
     */
    public function set_language_properties($sSessionKey, $iSurveyID, $aSurveyLocaleData, $sLanguage=NULL)
    {
        Yii::app()->loadHelper("surveytranslator");
        if ($this->_checkSessionKey($sSessionKey))
        {
            $oSurvey=Survey::model()->findByPk($iSurveyID);
            if (is_null($oSurvey))
            {
                return array('status' => 'Error: Invalid survey ID');
            }

            if (is_null($sLanguage))
            {
                $sLanguage=$oSurvey->language;
            }

			if (!array_key_exists($sLanguage,getLanguageDataRestricted()))
				return array('status' => 'Error: Invalid language');

            if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveylocale', 'update'))
            {
                // Remove fields that may not be modified
                unset($aSurveyLocaleData['surveyls_language']);
                unset($aSurveyLocaleData['surveyls_survey_id']);

                // Remove invalid fields
                $aDestinationFields=array_flip(SurveyLanguageSetting::model()->tableSchema->columnNames);

                $aSurveyLocaleData=array_intersect_key($aSurveyLocaleData,$aDestinationFields);
                $oSurveyLocale = SurveyLanguageSetting::model()->findByPk(array('surveyls_survey_id' => $iSurveyID, 'surveyls_language' => $sLanguage));

                $aLangAttributes = $oSurveyLocale->getAttributes();
                $aResult = array();

                if (empty($aSurveyLocaleData))
					return array('status' => 'No valid Data');

                foreach($aSurveyLocaleData as $sFieldName=>$sValue)
                {
					$oSurveyLocale->$sFieldName=$sValue;
					try
					{
						// save the change to database - Every single change alone - to allow for validation to work
						$bSaveResult=$oSurveyLocale->save();
						$aResult[$sFieldName]=$bSaveResult;
						//unset failed values
						if (!$bSaveResult)
							$oSurveyLocale->$sFieldName=$aLangAttributes[$sFieldName];
					}
					catch(Exception $e)
					{
						$oSurveyLocale->$sFieldName=$aLangAttributes[$sFieldName];
					}
                }
                $aResult['status'] = 'OK';
                return $aResult;
            }
            else
                return array('status' => 'No permission');
        }
        else
			return array('status' => 'Invalid Session key');
    }

	/* Group specific functions */

    /**
     * RPC Routine to add an empty group with minimum details.
     * Used as a placeholder for importing questions.
     * Returns the groupid of the created group.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID Dd of the Survey to add the group
     * @param string $sGroupTitle Name of the group
     * @param string $sGroupDescription	 Optional description of the group
     * @return array|int The id of the new group - Or status
     */
  	public function add_group($sSessionKey, $iSurveyID, $sGroupTitle, $sGroupDescription='')
	{
		if ($this->_checkSessionKey($sSessionKey))
        {
			if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'update'))
            {
				$oSurvey = Survey::model()->findByPk($iSurveyID);
				if (!isset($oSurvey))
					return array('status' => 'Error: Invalid survey ID');

				if($oSurvey['active']=='Y')
					return array('status' => 'Error:Survey is active and not editable');

				$oGroup = new QuestionGroup;
				$oGroup->sid = $iSurveyID;
				$oGroup->group_name =  $sGroupTitle;
                $oGroup->description = $sGroupDescription;
                $oGroup->group_order = getMaxGroupOrder($iSurveyID);
                $oGroup->language =  Survey::model()->findByPk($iSurveyID)->language;
				if($oGroup->save())
					return (int)$oGroup->gid;
				else
					return array('status' => 'Creation Failed');
			}
			else
				return array('status' => 'No permission');
		}
        else
            return array('status' => 'Invalid Session Key');
	}

    /**
     * RPC Routine to delete a group of a survey .
     * Returns the id of the deleted group.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID Id of the survey that the group belongs
     * @param int $iGroupID Id of the group to delete
     * @return array|int The id of the deleted group or status
     */
	public function delete_group($sSessionKey, $iSurveyID, $iGroupID)
	{
        if ($this->_checkSessionKey($sSessionKey))
        {
			$iSurveyID = sanitize_int($iSurveyID);
			$iGroupID = sanitize_int($iGroupID);
			$oSurvey = Survey::model()->findByPk($iSurveyID);
			if (!isset($oSurvey))
				return array('status' => 'Error: Invalid survey ID');

            if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveycontent', 'delete'))
            {
				$oGroup = QuestionGroup::model()->findByAttributes(array('gid' => $iGroupID));
				if (!isset($oGroup))
					return array('status' => 'Error: Invalid group ID');

				if($oSurvey['active']=='Y')
					return array('status' => 'Error:Survey is active and not editable');

				$depented_on = getGroupDepsForConditions($oGroup->sid,"all",$iGroupID,"by-targgid");
				if(isset($depented_on))
					return array('status' => 'Group with depencdencies - deletion not allowed');

				$iGroupsDeleted = QuestionGroup::deleteWithDependency($iGroupID, $iSurveyID);

				if ($iGroupsDeleted === 1)
				{
					fixSortOrderGroups($iSurveyID);
					return (int)$iGroupID;
				}
				else
					return array('status' => 'Group deletion failed');
            }
            else
                return array('status' => 'No permission');
        }
        else
            return array('status' => 'Invalid Session Key');
	}

    /**
     * RPC Routine to import a group - imports lsg,csv
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID The id of the survey that the group will belong
     * @param string $sImportData String containing the BASE 64 encoded data of a lsg,csv
     * @param string $sImportDataType  lsg,csv
     * @param string $sNewGroupName  Optional new name for the group
     * @param string $sNewGroupDescription  Optional new description for the group
     * @return array|integer iGroupID  - ID of the new group or status
     */
    public function import_group($sSessionKey, $iSurveyID, $sImportData, $sImportDataType, $sNewGroupName=NULL, $sNewGroupDescription=NULL)
    {

        if ($this->_checkSessionKey($sSessionKey))
        {
			$oSurvey = Survey::model()->findByPk($iSurveyID);
			if (!isset($oSurvey))
				return array('status' => 'Error: Invalid survey ID');

            if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'update'))
            {
				if($oSurvey->getAttribute('active') =='Y')
					return array('status' => 'Error:Survey is active and not editable');

                if (!in_array($sImportDataType,array('csv','lsg'))) return array('status' => 'Invalid extension');
				libxml_use_internal_errors(true);
                Yii::app()->loadHelper('admin/import');
                // First save the data to a temporary file
                $sFullFilePath = Yii::app()->getConfig('tempdir') . DIRECTORY_SEPARATOR . randomChars(40).'.'.$sImportDataType;
                file_put_contents($sFullFilePath,base64_decode(chunk_split($sImportData)));

				if (strtolower($sImportDataType)=='csv')
				{
					$aImportResults = CSVImportGroup($sFullFilePath, $iSurveyID);
				}
				elseif ( strtolower($sImportDataType)=='lsg')
				{
                    $sXMLdata = file_get_contents($sFullFilePath);
                    $xml = @simplexml_load_string($sXMLdata,'SimpleXMLElement',LIBXML_NONET);
					if(!$xml)
					{
						unlink($sFullFilePath);
						return array('status' => 'Error: Invalid LimeSurvey group structure XML ');
					}
					$aImportResults = XMLImportGroup($sFullFilePath, $iSurveyID);
				}
				else
					return array('status' => 'Invalid extension'); //just for symmetry!

				unlink($sFullFilePath);

				if (isset($aImportResults['fatalerror'])) return array('status' => 'Error: '.$aImportResults['fatalerror']);
                else
                {
					$iNewgid = $aImportResults['newgid'];

					$oGroup = QuestionGroup::model()->findByAttributes(array('gid' => $iNewgid));
					$slang=$oGroup['language'];
					if($sNewGroupName!='')
					$oGroup->setAttribute('group_name',$sNewGroupName);
					if($sNewGroupDescription!='')
					$oGroup->setAttribute('description',$sNewGroupDescription);
					try
					{
						$oGroup->save();
					}
					catch(Exception $e)
					{
						// no need to throw exception
					}
                    return (int)$aImportResults['newgid'];
                }
            }
            else
                return array('status' => 'No permission');
        }
        else
			return array('status' => 'Invalid session key');
    }

    /**
     * RPC Routine to find response IDs given a survey ID and a token.
     * @param string $sSessionKey
     * @param int $iSurveyID
     * @param string $sToken
     */
    public function get_response_ids($sSessionKey, $iSurveyID, $sToken)
    {
        if ($this->_checkSessionKey($sSessionKey))
        {
            $responses = SurveyDynamic::model($iSurveyID)->findAllByAttributes(array('token' => $sToken));
            $result = array();
            foreach ($responses as $response)
            {
                $result[] = (int) $response->id;
            }
            return $result;
        }
        else
        {
            return array('status' => 'Invalid Session Key');
        }
        
    }

    /**
     * RPC Routine to return properties of a group of a survey .
     * Returns array of properties
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iGroupID Id of the group to get properties
     * @param array  $aGroupSettings The properties to get
     * @return array The requested values
     */
	public function get_group_properties($sSessionKey, $iGroupID, $aGroupSettings)
	{
       if ($this->_checkSessionKey($sSessionKey))
       {
		   $oGroup = QuestionGroup::model()->findByAttributes(array('gid' => $iGroupID));
			if (!isset($oGroup))
				return array('status' => 'Error: Invalid group ID');

			if (Permission::model()->hasSurveyPermission($oGroup->sid, 'survey', 'read'))
			{
				$aBasicDestinationFields=QuestionGroup::model()->tableSchema->columnNames;
				$aGroupSettings=array_intersect($aGroupSettings,$aBasicDestinationFields);

				if (empty($aGroupSettings))
					return array('status' => 'No valid Data');

                foreach($aGroupSettings as $sGroupSetting)
                {
					$aResult[$sGroupSetting] = $oGroup->$sGroupSetting;
				}
                return $aResult;
			}
			else
				return array('status' => 'No permission');
        }
        else
            return array('status' => 'Invalid Session Key');
	}


    /**
     * RPC Routine to set group properties.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param integer $iGroupID  - ID of the survey
     * @param array|struct $aGroupData - An array with the particular fieldnames as keys and their values to set on that particular survey
     * @return array Of succeeded and failed modifications according to internal validation.
     */
    public function set_group_properties($sSessionKey, $iGroupID, $aGroupData)
    {
        if ($this->_checkSessionKey($sSessionKey))
        {
            $oGroup=QuestionGroup::model()->findByAttributes(array('gid' => $iGroupID));
            if (is_null($oGroup))
            {
                return array('status' => 'Error: Invalid group ID');
            }
            if (Permission::model()->hasSurveyPermission($oGroup->sid, 'survey', 'update'))
            {
                $aResult = array();
                // Remove fields that may not be modified
                unset($aGroupData['sid']);
                unset($aGroupData['gid']);
                // Remove invalid fields
                $aDestinationFields=array_flip(QuestionGroup::model()->tableSchema->columnNames);
                $aGroupData=array_intersect_key($aGroupData,$aDestinationFields);
				$aGroupAttributes = $oGroup->getAttributes();
				if (empty($aGroupData))
					return array('status' => 'No valid Data');

                foreach($aGroupData as $sFieldName=>$sValue)
                {
						//all dependencies this group has
						$has_dependencies=getGroupDepsForConditions($oGroup->sid,$iGroupID);
						//all dependencies on this group
						$depented_on = getGroupDepsForConditions($oGroup->sid,"all",$iGroupID,"by-targgid");
						//We do not allow groups with dependencies to change order - that would lead to broken dependencies

						if((isset($has_dependencies) || isset($depented_on))  && $sFieldName == 'group_order')
							$aFailed[$sFieldName]='Group with dependencies - Order cannot be changed';
						else
						{
							$oGroup->setAttribute($sFieldName,$sValue);
						}
						try
						{
							// save the change to database - one by one to allow for validation to work
							$bSaveResult=$oGroup->save();
							fixSortOrderGroups($oGroup->sid);
							$aResult[$sFieldName] = $bSaveResult;
							//unset failed values
							if (!$bSaveResult)
								$oGroup->$sFieldName=$aGroupAttributes[$sFieldName];
						}
						catch(Exception $e)
						{
							//unset values that cause exception
							$oGroup->$sFieldName=$aGroupAttributes[$sFieldName];
						}
                }
                return $aResult;
            }
            else
                return array('status' => 'No permission');
        }
        else
			return array('status' => 'Invalid Session key');
    }

    /* Question specific functions */


    /**
     * RPC Routine to delete a question of a survey .
     * Returns the id of the deleted question.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int iQuestionID Id of the question to delete
     * @return array|int Id of the deleted Question or status
     */
	public function delete_question($sSessionKey, $iQuestionID)
	{
        if ($this->_checkSessionKey($sSessionKey))
        {
			$oQuestion = Question::model()->findByAttributes(array('qid' => $iQuestionID));
			if (!isset($oQuestion))
				return array('status' => 'Error: Invalid question ID');

			$iSurveyID = $oQuestion['sid'];

            if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveycontent', 'delete'))
            {
				$oSurvey = Survey::model()->findByPk($iSurveyID);

				if($oSurvey['active']=='Y')
					return array('status' => 'Survey is active and not editable');
				$iGroupID=$oQuestion['gid'];

				$oCondition = Condition::model()->findAllByAttributes(array('cqid' => $iQuestionID));
				if(count($oCondition)>0)
					return array('status' => 'Cannot delete Question. Others rely on this question');

				LimeExpressionManager::RevertUpgradeConditionsToRelevance(NULL,$iQuestionID);

				try
				{
					Condition::model()->deleteAllByAttributes(array('qid' => $iQuestionID));
					QuestionAttribute::model()->deleteAllByAttributes(array('qid' => $iQuestionID));
					Answer::model()->deleteAllByAttributes(array('qid' => $iQuestionID));

					$sCriteria = new CDbCriteria;
					$sCriteria->addCondition('qid = :qid or parent_qid = :qid');
					$sCriteria->params[':qid'] = $iQuestionID;
					Question::model()->deleteAll($sCriteria);

					DefaultValue::model()->deleteAllByAttributes(array('qid' => $iQuestionID));
					QuotaMember::model()->deleteAllByAttributes(array('qid' => $iQuestionID));
					Question::updateSortOrder($iGroupID, $iSurveyID);

                return (int)$iQuestionID;
				}
				catch(Exception $e)
                {
                    return array('status' => 'Error');
                }

            }
            else
                return array('status' => 'No permission');
        }
        else
			return array('status' => 'Invalid session key');
	}


    /**
     * RPC Routine to import a question - imports lsq,csv.
     *
     * @access public
     * @param string $sSessionKey
     * @param int $iSurveyID The id of the survey that the question will belong
     * @param int $iGroupID The id of the group that the question will belong
     * @param string $sImportData String containing the BASE 64 encoded data of a lsg,csv
     * @param string $sImportDataType  lsq,csv
     * @param string $sMandatory Optional Mandatory question option (default to No)
     * @param string $sNewQuestionTitle  Optional new title for the question
     * @param string $sNewqQuestion An optional new question
     * @param string $sNewQuestionHelp An optional new question help text
     * @return array|integer iQuestionID  - ID of the new question - Or status
     */
    public function import_question($sSessionKey, $iSurveyID,$iGroupID, $sImportData, $sImportDataType, $sMandatory='N', $sNewQuestionTitle=NULL, $sNewqQuestion=NULL, $sNewQuestionHelp=NULL)
    {
        if ($this->_checkSessionKey($sSessionKey))
        {
			$oSurvey = Survey::model()->findByPk($iSurveyID);
			if (!isset($oSurvey))
				return array('status' => 'Error: Invalid survey ID');

            if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'update'))
            {
				if($oSurvey->getAttribute('active') =='Y')
					return array('status' => 'Error:Survey is Active and not editable');

				$oGroup = QuestionGroup::model()->findByAttributes(array('gid' => $iGroupID));
				if (!isset($oGroup))
					return array('status' => 'Error: Invalid group ID');

				$sGroupSurveyID = $oGroup['sid'];
				if($sGroupSurveyID != $iSurveyID)
					return array('status' => 'Error: Missmatch in surveyid and groupid');

                if (!in_array($sImportDataType,array('csv','lsq'))) return array('status' => 'Invalid extension');
				libxml_use_internal_errors(true);
                Yii::app()->loadHelper('admin/import');
                // First save the data to a temporary file
                $sFullFilePath = Yii::app()->getConfig('tempdir') . DIRECTORY_SEPARATOR . randomChars(40).'.'.$sImportDataType;
                file_put_contents($sFullFilePath,base64_decode(chunk_split($sImportData)));

				if (strtolower($sImportDataType)=='csv')
				{
					$aImportResults = CSVImportQuestion($sFullFilePath, $iSurveyID, $iGroupID);
				}
				elseif ( strtolower($sImportDataType)=='lsq')
				{
                    $sXMLdata = file_get_contents($sFullFilePath);
                    $xml = @simplexml_load_string($sXMLdata,'SimpleXMLElement',LIBXML_NONET);
					if(!$xml)
					{
						unlink($sFullFilePath);
						return array('status' => 'Error: Invalid LimeSurvey question structure XML ');
					}
					$aImportResults =  XMLImportQuestion($sFullFilePath, $iSurveyID, $iGroupID);
				}
				else
					return array('status' => 'Really Invalid extension'); //just for symmetry!

				unlink($sFullFilePath);

				if (isset($aImportResults['fatalerror'])) return array('status' => 'Error: '.$aImportResults['fatalerror']);
                else
                {
					fixLanguageConsistency($iSurveyID);
					$iNewqid = $aImportResults['newqid'];

					$oQuestion = Question::model()->findByAttributes(array('sid' => $iSurveyID, 'gid' => $iGroupID, 'qid' => $iNewqid));
					if($sNewQuestionTitle!=NULL)
						$oQuestion->setAttribute('title',$sNewQuestionTitle);
					if($sNewqQuestion!='')
						$oQuestion->setAttribute('question',$sNewqQuestion);
					if($sNewQuestionHelp!='')
						$oQuestion->setAttribute('help',$sNewQuestionHelp);
					if(in_array($sMandatory, array('Y','N')))
						$oQuestion->setAttribute('mandatory',$sMandatory);
					else
						$oQuestion->setAttribute('mandatory','N');

					try
					{
						$oQuestion->save();
					}
					catch(Exception $e)
					{
						// no need to throw exception
					}
                    return (int)$aImportResults['newqid'];
                }
            }
            else
                return array('status' => 'No permission');
        }
        else
			return array('status' => 'Invalid session key');
    }


    /**
     * RPC Routine to return properties of a question of a survey.
     * Returns string
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iQuestionID Id of the question to get properties
     * @param array $aQuestionSettings The properties to get
     * @param string $sLanguage Optional parameter language for multilingual questions
     * @return array The requested values
     */
	public function get_question_properties($sSessionKey, $iQuestionID, $aQuestionSettings, $sLanguage=NULL)
	{
       if ($this->_checkSessionKey($sSessionKey))
       {
		    Yii::app()->loadHelper("surveytranslator");
			$oQuestion = Question::model()->findByAttributes(array('qid' => $iQuestionID));
			if (!isset($oQuestion))
				return array('status' => 'Error: Invalid questionid');

		    $iSurveyID = $oQuestion->sid;

			if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'read'))
			{
				if (is_null($sLanguage))
					$sLanguage=Survey::model()->findByPk($iSurveyID)->language;

				if (!array_key_exists($sLanguage,getLanguageDataRestricted()))
					return array('status' => 'Error: Invalid language');

				$oQuestion = Question::model()->findByAttributes(array('qid' => $iQuestionID, 'language'=>$sLanguage));
				if (!isset($oQuestion))
					return array('status' => 'Error: Invalid questionid');

				$aBasicDestinationFields=Question::model()->tableSchema->columnNames;
				array_push($aBasicDestinationFields,'available_answers')	;
				array_push($aBasicDestinationFields,'subquestions')	;
				array_push($aBasicDestinationFields,'attributes')	;
				array_push($aBasicDestinationFields,'attributes_lang')	;
				array_push($aBasicDestinationFields,'answeroptions')	;
				$aQuestionSettings=array_intersect($aQuestionSettings,$aBasicDestinationFields);

				if (empty($aQuestionSettings))
					return array('status' => 'No valid Data');

                $aResult=array();
                foreach ($aQuestionSettings as $sPropertyName )
                {
					if ($sPropertyName == 'available_answers' || $sPropertyName == 'subquestions')
					{
						$oSubQuestions =  Question::model()->findAllByAttributes(array('parent_qid' => $iQuestionID,'language'=>$sLanguage ),array('order'=>'title') );
						if (count($oSubQuestions)>0)
						{
	    					$aData = array();
							foreach($oSubQuestions as $oSubQuestion)
							{
								if($sPropertyName == 'available_answers')
									$aData[$oSubQuestion['title']]= $oSubQuestion['question'];
								else
								{
									$aData[$oSubQuestion['qid']]['title']= $oSubQuestion['title'];
									$aData[$oSubQuestion['qid']]['question']= $oSubQuestion['question'];
									$aData[$oSubQuestion['qid']]['scale_id']= $oSubQuestion['scale_id'];
								}

							}

							$aResult[$sPropertyName]=$aData;
						}
						else
							$aResult[$sPropertyName]='No available answers';
					}
					else if ($sPropertyName == 'attributes')
					{
						$oAttributes =  QuestionAttribute::model()->findAllByAttributes(array('qid' => $iQuestionID, 'language'=> null ),array('order'=>'attribute') );
						if (count($oAttributes)>0)
						{
							$aData = array();
							foreach($oAttributes as $oAttribute)
								$aData[$oAttribute['attribute']]= $oAttribute['value'];

							$aResult['attributes']=$aData;
						}
						else
							$aResult['attributes']='No available attributes';
					}
					else if ($sPropertyName == 'attributes_lang')
					{
						$oAttributes =  QuestionAttribute::model()->findAllByAttributes(array('qid' => $iQuestionID, 'language'=> $sLanguage ),array('order'=>'attribute') );
						if (count($oAttributes)>0)
						{
							$aData = array();
							foreach($oAttributes as $oAttribute)
								$aData[$oAttribute['attribute']]= $oAttribute['value'];

							$aResult['attributes_lang']=$aData;
						}
						else
							$aResult['attributes_lang']='No available attributes';
					}
					else if ($sPropertyName == 'answeroptions')
					{
						$oAttributes = Answer::model()->findAllByAttributes(array('qid' => $iQuestionID, 'language'=> $sLanguage ),array('order'=>'sortorder') );
						if (count($oAttributes)>0)
						{
							$aData = array();
							foreach($oAttributes as $oAttribute) {
								$aData[$oAttribute['code']]['answer']=$oAttribute['answer'];
								$aData[$oAttribute['code']]['assessment_value']=$oAttribute['assessment_value'];
								$aData[$oAttribute['code']]['scale_id']=$oAttribute['scale_id'];
							}
							$aResult['answeroptions']=$aData;
						}
						else
							$aResult['answeroptions']='No available answer options';
					}
					else
					{
							$aResult[$sPropertyName]=$oQuestion->$sPropertyName;
					}
				}
                return $aResult;
			}
			else
				return array('status' => 'No permission');
        }
        else
			return array('status' => 'Invalid session key');
	}

    /**
     * RPC Routine to set question properties.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param integer $iQuestionID  - ID of the question
     * @param array|struct $aQuestionData - An array with the particular fieldnames as keys and their values to set on that particular question
     * @param string $sLanguage Optional parameter language for multilingual questions
     * @return array Of succeeded and failed modifications according to internal validation.
     */
    public function set_question_properties($sSessionKey, $iQuestionID, $aQuestionData,$sLanguage=NULL)
    {
        if ($this->_checkSessionKey($sSessionKey))
        {
            Yii::app()->loadHelper("surveytranslator");
            $oQuestion=Question::model()->findByAttributes(array('qid' => $iQuestionID));
            if (is_null($oQuestion))
                return array('status' => 'Error: Invalid group ID');

			$iSurveyID = $oQuestion->sid;

            if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'update'))
            {
				if (is_null($sLanguage))
					$sLanguage=Survey::model()->findByPk($iSurveyID)->language;

				if (!array_key_exists($sLanguage,getLanguageDataRestricted()))
					return array('status' => 'Error: Invalid language');

				$oQuestion = Question::model()->findByAttributes(array('qid' => $iQuestionID, 'language'=>$sLanguage));
				if (!isset($oQuestion))
					return array('status' => 'Error: Invalid questionid');

                // Remove fields that may not be modified
                unset($aQuestionData['qid']);
                unset($aQuestionData['gid']);
                unset($aQuestionData['sid']);
                unset($aQuestionData['parent_qid']);
                unset($aQuestionData['language']);
                unset($aQuestionData['type']);
                // Remove invalid fields
                $aDestinationFields=array_flip(Question::model()->tableSchema->columnNames);
                $aQuestionData=array_intersect_key($aQuestionData,$aDestinationFields);
                $aQuestionAttributes = $oQuestion->getAttributes();

				if (empty($aQuestionData))
					return array('status' => 'No valid Data');

                foreach($aQuestionData as $sFieldName=>$sValue)
                {
					//all the dependencies that this question has to other questions
					$dependencies=getQuestDepsForConditions($oQuestion->sid,$oQuestion->gid,$iQuestionID);
					//all dependencies by other questions to this question
					$is_criteria_question=getQuestDepsForConditions($oQuestion->sid,$oQuestion->gid,"all",$iQuestionID,"by-targqid");
					//We do not allow questions with dependencies in the same group to change order - that would lead to broken dependencies

					if((isset($dependencies) || isset($is_criteria_question))  && $sFieldName == 'question_order')
						$aFailed[$sFieldName]='Questions with dependencies - Order cannot be changed';
					else
					{
						$oQuestion->setAttribute($sFieldName,$sValue);
					}

					try
					{
						$bSaveResult=$oQuestion->save(); // save the change to database
						Question::model()->updateQuestionOrder($oQuestion->gid, $oQuestion->sid);
						$aResult[$sFieldName]=$bSaveResult;
						//unset fields that failed
						if (!$bSaveResult)
							$oQuestion->$sFieldName=$aQuestionAttributes[$sFieldName];
					}
					catch(Exception $e)
					{
						//unset fields that caused exception
						$oQuestion->$sFieldName=$aQuestionAttributes[$sFieldName];
					}
                }
                return $aResult;
            }
            else
                return array('status' => 'No permission');
        }
        else
			return array('status' => 'Invalid Session key');
    }


    

	/* Participant-Token specific functions */



    /**
     * RPC Routine to add participants to the tokens collection of the survey.
     * Returns the inserted data including additional new information like the Token entry ID and the token string.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID Id of the Survey
     * @param struct $aParticipantData Data of the participants to be added
     * @param bool Optional - Defaults to true and determins if the access token automatically created
     * @return array The values added
     */
    public function add_participants($sSessionKey, $iSurveyID, $aParticipantData, $bCreateToken=true)
    {
        if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key');
        $oSurvey=Survey::model()->findByPk($iSurveyID);
        if (is_null($oSurvey))
        {
            return array('status' => 'Error: Invalid survey ID');
        }

        if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'create'))
        {
            if (!Yii::app()->db->schema->getTable('{{tokens_' . $iSurveyID . '}}'))
                return array('status' => 'No token table');
			$aDestinationFields = array_flip(Token::model($iSurveyID)->getMetaData()->tableSchema->columnNames);
			foreach ($aParticipantData as &$aParticipant)
            {
                $token = Token::create($iSurveyID);
                $token->setAttributes(array_intersect_key($aParticipant,$aDestinationFields));
				if  ($bCreateToken)
				{
					$token->generateToken();
				}
				if ($token->save())
				{
					$aParticipant = $token->getAttributes();
				}
				else
				{
					$aParticipant["errors"] = $token->errors;
				}
            }
            return $aParticipantData;
        }
        else
            return array('status' => 'No permission');
    }

    /**
     * RPC Routine to delete multiple participants of a Survey.
     * Returns the id of the deleted token
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID Id of the Survey that the participants belong to
     * @param array $aTokenIDs Id of the tokens/participants to delete
     * @return array Result of deletion
     */
	public function delete_participants($sSessionKey, $iSurveyID, $aTokenIDs)
	{
        if ($this->_checkSessionKey($sSessionKey))
        {
			$iSurveyID = sanitize_int($iSurveyID);

			$oSurvey = Survey::model()->findByPk($iSurveyID);
			if (!isset($oSurvey))
				return array('status' => 'Error: Invalid survey ID');

			if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'delete'))
			{
				if(!tableExists("{{tokens_$iSurveyID}}"))
					return array('status' => 'Error: No token table');

				$aResult=array();
				foreach($aTokenIDs as $iTokenID)
				{
					$token = Token::model($iSurveyID)->findByPk($iTokenID);
					if (!isset($token))
						$aResult[$iTokenID]='Invalid token ID';
					elseif($token->delete())
						$aResult[$iTokenID]='Deleted';
					else
						$aResult[$iTokenID]='Deletion went wrong';
				}
				return $aResult;
            }
            else
                return array('status' => 'No permission');
        }
        else
            return array('status' => 'Invalid Session Key');
	}


    /**
      * RPC Routine to return settings of a token/participant of a survey .
      *
      * @access public
      * @param string $sSessionKey Auth credentials
      * @param int $iSurveyID Id of the Survey to get token properties
      * @param int $iTokenID Id of the participant to check
      * @param array $aTokenProperties The properties to get
      * @return array The requested values
      */
	public function get_participant_properties($sSessionKey, $iSurveyID, $iTokenID, $aTokenProperties)
	{
       if ($this->_checkSessionKey($sSessionKey))
       {
			$surveyidExists = Survey::model()->findByPk($iSurveyID);
			if (!isset($surveyidExists))
				return array('status' => 'Error: Invalid survey ID');

			if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'read'))
			{
				if(!tableExists("{{tokens_$iSurveyID}}"))
					return array('status' => 'Error: No token table');

				$token = Token::model($iSurveyID)->findByPk($iTokenID);
				if (!isset($token))
					return array('status' => 'Error: Invalid tokenid');

				$result = array_intersect_key(array_flip($aTokenProperties), $token->attributes);
                if (empty($result))
				{
					return array('status' => 'No valid Data');
				}
				else
				{
					return $result;
				}

                
			}
			else
				return array('status' => 'No permission');
        }
        else
            return array('status' => 'Invalid Session Key');
	}

    /**
     * RPC Routine to set properties of a survey participant/token.
     * Returns array
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID Id of the survey that participants belong
     * @param int $iTokenID Id of the participant to alter
     * @param array|struct $aTokenData Data to change
     * @return array Result of the change action
     */
	public function set_participant_properties($sSessionKey, $iSurveyID, $iTokenID, $aTokenData)
	{
       if ($this->_checkSessionKey($sSessionKey))
       {
			$oSurvey = Survey::model()->findByPk($iSurveyID);
			if (!isset($oSurvey))
				return array('status' => 'Error: Invalid survey ID');

			if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'update'))
			{
				if(!tableExists("{{tokens_$iSurveyID}}"))
					return array('status' => 'Error: No token table');

				$oToken = Token::model($iSurveyID)->findByPk($iTokenID);
				if (!isset($oToken))
					return array('status' => 'Error: Invalid tokenid');

				$aResult = array();
				// Remove fields that may not be modified
				unset($aTokenData['tid']);

				$aBasicDestinationFields = array_flip($oToken->getTableSchema()->columnNames);
				$aTokenData = array_intersect_key($aTokenData,$aBasicDestinationFields);

				if (empty($aTokenData))
					return array('status' => 'No valid Data');

				$oToken->setAttributes($aTokenData, false);
				if ($oToken->save())
				{
					return $oToken->attributes;
				}
			}
			else
				return array('status' => 'No permission');
        }
        else
            return array('status' => 'Invalid Session Key');
	}


	/**
      * RPC Routine to return the ids and info of groups belonging to survey .
      * Returns array of ids and info.
      *
      * @access public
      * @param string $sSessionKey Auth credentials
      * @param int $iSurveyID Id of the Survey containing the groups
      * @return array The list of groups
      */
	public function list_groups($sSessionKey, $iSurveyID)
	{
       if ($this->_checkSessionKey($sSessionKey))
       {
			$oSurvey = Survey::model()->findByPk($iSurveyID);
			if (!isset($oSurvey))
				return array('status' => 'Error: Invalid survey ID');

			if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'read'))
			{
				$oGroupList = QuestionGroup::model()->findAllByAttributes(array("sid"=>$iSurveyID));
				if(count($oGroupList)==0)
					return array('status' => 'No groups found');

				foreach ($oGroupList as $oGroup)
				{
					$aData[]= array('id'=>$oGroup->primaryKey,'group_name'=>$oGroup->attributes['group_name']);
				}
				return $aData;
			}
			else
				return array('status' => 'No permission');
        }
        else
            return array('status' => 'Invalid Session Key');
	}

   /**
    * RPC Routine to return the ids and info  of token/participants of a survey.
    * if $bUnused is true, user will get the list of not completed tokens (token_return functionality).
    * Parameters iStart and ilimit are used to limit the number of results of this call.
    *
    * @access public
    * @param string $sSessionKey Auth credentials
    * @param int $iSurveyID Id of the survey to list participants
    * @param int $iStart Start id of the token list
    * @param int  $iLimit Number of participants to return
    * @param bool $bUnused If you want unused tokensm, set true
    * @return array The list of tokens
    */
	public function list_participants($sSessionKey, $iSurveyID, $iStart=0, $iLimit=10, $bUnused=false)
	{
       if ($this->_checkSessionKey($sSessionKey))
       {
			$oSurvey = Survey::model()->findByPk($iSurveyID);
			if (!isset($oSurvey))
				return array('status' => 'Error: Invalid survey ID');

			if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'read'))
			{
				if(!tableExists("{{tokens_$iSurveyID}}"))
					return array('status' => 'Error: No token table');

				if($bUnused)
					$oTokens = Token::model($iSurveyID)->incomplete()->findAll(array('limit' => $iLimit, 'offset' => $iStart));
				else
					$oTokens = Token::model($iSurveyID)->findAll(array('limit' => $iLimit, 'offset' => $iStart));

				if(count($oTokens)==0)
					return array('status' => 'No Tokens found');

				foreach ($oTokens as $token)
					{
						$aData[] = array(
									'tid'=>$token->primarykey,
									'token'=>$token->attributes['token'],
									'participant_info'=>array(
														'firstname'=>$token->attributes['firstname'],
														'lastname'=>$token->attributes['lastname'],
														'email'=>$token->attributes['email'],
														    ));
					}
				return $aData;
			}
			else
				return array('status' => 'No permission');
        }
        else
            return array('status' => 'Invalid Session Key');
	}

	/**
     * RPC Routine to return the ids and info of questions of a survey/group.
     * Returns array of ids and info.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID Id of the survey to list questions
     * @param int $iGroupID Optional id of the group to list questions
     * @param string $sLanguage Optional parameter language for multilingual questions
     * @return array The list of questions
     */
	public function list_questions($sSessionKey, $iSurveyID, $iGroupID=NULL, $sLanguage=NULL)
	{
       if ($this->_checkSessionKey($sSessionKey))
       {
			Yii::app()->loadHelper("surveytranslator");
			$oSurvey = Survey::model()->findByPk($iSurveyID);
			if (!isset($oSurvey))
				return array('status' => 'Error: Invalid survey ID');

			if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'read'))
			{
				if (is_null($sLanguage))
					$sLanguage=$oSurvey->language;

				if (!array_key_exists($sLanguage,getLanguageDataRestricted()))
					return array('status' => 'Error: Invalid language');

				if($iGroupID!=NULL)
				{
					$oGroup = QuestionGroup::model()->findByAttributes(array('gid' => $iGroupID));
					$sGroupSurveyID = $oGroup['sid'];

					if($sGroupSurveyID != $iSurveyID)
						return array('status' => 'Error: IMissmatch in surveyid and groupid');
					else
						$aQuestionList = Question::model()->findAllByAttributes(array("sid"=>$iSurveyID, "gid"=>$iGroupID,"parent_qid"=>"0","language"=>$sLanguage));
				}
				else
					$aQuestionList = Question::model()->findAllByAttributes(array("sid"=>$iSurveyID,"parent_qid"=>"0", "language"=>$sLanguage));

				if(count($aQuestionList)==0)
					return array('status' => 'No questions found');

				foreach ($aQuestionList as $oQuestion)
				{
					$aData[]= array('id'=>$oQuestion->primaryKey,'title'=>$oQuestion->attributes['title'],'type'=>$oQuestion->attributes['type'], 'question'=>$oQuestion->attributes['question']);
				}
				return $aData;
			}
			else
				return array('status' => 'No permission');
        }
        else
			return array('status' => 'Invalid session key');
	}

	/**
     * RPC Routine to list the ids and info of surveys belonging to a user.
     * Returns array of ids and info.
     * If user is admin he can get surveys of every user (parameter sUser) or all surveys (sUser=null)
     * Else only the syrveys belonging to the user requesting will be shown.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param string $sUser Optional username to get list of surveys
     * @return array The list of surveys
     */
	public function list_surveys($sSessionKey, $sUser=NULL)
	{
       if ($this->_checkSessionKey($sSessionKey))
       {
		   $sCurrentUser =  Yii::app()->session['user'];

		   if( Permission::model()->hasGlobalPermission('superadmin','read') )
		   {
				if ($sUser == null)
					$aUserSurveys = Survey::model()->findAll(); //list all surveys
				else
				{
				   $aUserData = User::model()->findByAttributes(array('users_name' => $sUser));
				   if (!isset($aUserData))
						return array('status' => 'Invalid user');
					else
						$sUid = $aUserData->attributes['uid'];
				}
			}
			else
			{
				if (($sCurrentUser == $sUser) || ($sUser == null) )
				{
					$sUid =  User::model()->findByAttributes(array('users_name' => $sCurrentUser))->uid;
				}
				else
					return array('status' => 'No permission');
			}

			if($sUid!=null){
			//we request user and not admin surveys
				$surveyPermissions = Permission::model()->findAllByAttributes(array('entity'=>'survey','uid'=>$sUid));
							foreach($surveyPermissions as $row)
							   $ids[] = $row['entity_id'];

							$ids = array_unique($ids);
							$aUserSurveys = Survey::model()->findAllByAttributes(array("sid"=>$ids));
			}




		   if(count($aUserSurveys)==0)
				return array('status' => 'No surveys found');

			foreach ($aUserSurveys as $oSurvey)
				{
				$oSurveyLanguageSettings = SurveyLanguageSetting::model()->findByAttributes(array('surveyls_survey_id' => $oSurvey->primaryKey, 'surveyls_language' => $oSurvey->language));
				if (!isset($oSurveyLanguageSettings))
					$aSurveyTitle = '';
				else
					$aSurveyTitle = $oSurveyLanguageSettings->attributes['surveyls_title'];
				$aData[]= array('sid'=>$oSurvey->primaryKey,'surveyls_title'=>$aSurveyTitle,'startdate'=>$oSurvey->attributes['startdate'],'expires'=>$oSurvey->attributes['expires'],'active'=>$oSurvey->attributes['active']);
				}
			return $aData;
        }
        else
			return array('status' => 'Invalid session key');
	}

	/**
     * RPC Routine to list the ids and info of users.
     * Returns array of ids and info.
     * @param string $sSessionKey Auth credentials
     * @return array The list of users
     */

	public function list_users($sSessionKey = null)
	{
		if ($this->_checkSessionKey($sSessionKey))
		{
			if( Permission::model()->hasGlobalPermission('superadmin','read') )
			{
				$users = User::model()->findAll();

				 if(count($users)==0)
					 return array('status' => 'No surveys found');

				 foreach ($users as $user)
				 {
					 $attributes = $user->attributes;
                     $attributes['permissions'] = array();
					 foreach ($user->permissions as $permission)
					 {
						 $attributes['permissions'][] = $permission->attributes;
					 }
					 unset($attributes['password']);
					 $data[] = $attributes;
				 }
				 return $data;
			}
			else
			{
				return array('status' => 'Permission denied.');
			}
		}
		else
		{
			return array('status' => 'Invalid session key');
		}
	}
    /**
     * RPC routine to to initialise the survey's collection of tokens where new participant tokens may be later added.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param integer $iSurveyID ID of the survey where a token table will be created for
     * @param array $aAttributeFields  An array of integer describing any additional attribute fields
     * @return array Status=>OK when successfull, otherwise the error description
     */
    public function activate_tokens($sSessionKey, $iSurveyID, $aAttributeFields=array())
    {
        if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key');
        if (Permission::model()->hasGlobalPermission('surveys','create'))
        {
            $oSurvey=Survey::model()->findByPk($iSurveyID);
            if (is_null($oSurvey))
            {
                return array('status' => 'Error: Invalid survey ID');
            }
            if (is_array($aAttributeFields) && count($aAttributeFields)>0)
            {
                foreach ($aAttributeFields as &$sField)
                {
                    $sField= intval($sField);
                    $sField='attribute_'.$sField;
                }
                $aAttributeFields=array_unique($aAttributeFields);
            }
            Yii::app()->loadHelper('admin/token');
            if (createTokenTable($iSurveyID, $aAttributeFields))
            {
                return array('status' => 'OK');
            }
            else
            {
                return array('status' => 'Token table could not be created');
            }
        }
        else
            return array('status' => 'No permission');
    }

    /**
     * RPC Routine to invite participants in a survey
     * Returns array of results of sending
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID ID of the survey that participants belong
     * @return array Result of the action
     */
	public function invite_participants($sSessionKey, $iSurveyID )
	{
		Yii::app()->loadHelper('admin/token');
		if (!$this->_checkSessionKey($sSessionKey))
			return array('status' => 'Invalid session key');

		$oSurvey = Survey::model()->findByPk($iSurveyID);
		if (!isset($oSurvey))
			return array('status' => 'Error: Invalid survey ID');

		if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'update'))
		{

			if(!tableExists("{{tokens_$iSurveyID}}"))
				return array('status' => 'Error: No token table');

			$iMaxEmails = (int)Yii::app()->getConfig("maxemails");
			$SQLemailstatuscondition = "emailstatus = 'OK'";

			$oTokens = TokenDynamic::model($iSurveyID);
			$aResultTokens = $oTokens->findUninvited(false, $iMaxEmails, true, $SQLemailstatuscondition);
			$aAllTokens = $oTokens->findUninvitedIDs(false, 0, true, $SQLemailstatuscondition);
            $iAllTokensCount=count($aAllTokens);
            unset($aAllTokens);
			if (empty($aResultTokens))
				return array('status' => 'Error: No candidate tokens');

			foreach($aResultTokens as $key=>$oToken)
			{
				//pattern taken from php_filter_validate_email PHP_5_4/ext/filter/logical_filters.c
				$pattern = '/^(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){255,})(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){65,}@)(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22))(?:\\.(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\]))$/iD';		

				//if(!filter_var($emailaddress, FILTER_VALIDATE_EMAIL))
				if (preg_match($pattern, $oToken['email']) !== 1)
					unset($aResultTokens[$key]);
			}

			if (empty($aResultTokens))
				return array('status' => 'Error: No candidate tokens');
			$aResult = emailTokens($iSurveyID,$aResultTokens,'invite');
			$iLeft = $iAllTokensCount - count($aResultTokens);
			$aResult['status'] =$iLeft. " left to send";

			return $aResult;
		}
		else
			return array('status' => 'No permission');
	}


    /**
     * RPC Routine to send reminder for participants in a survey
     * Returns array of results of sending
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID ID of the survey that participants belong
     * @param int $iMinDaysBetween Optional parameter days from last reminder
     * @param int $iMaxReminders Optional parameter Maximum reminders count
     * @return array Result of the action
     */
	public function remind_participants($sSessionKey, $iSurveyID, $iMinDaysBetween=null, $iMaxReminders=null )
	{
		Yii::app()->loadHelper('admin/token');
		if (!$this->_checkSessionKey($sSessionKey))
			return array('status' => 'Invalid session key');

		$oSurvey = Survey::model()->findByPk($iSurveyID);
		if (!isset($oSurvey))
			return array('status' => 'Error: Invalid survey ID');

		if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'update'))
		{
			$timeadjust = Yii::app()->getConfig("timeadjust");

			if(!tableExists("{{tokens_$iSurveyID}}"))
				return array('status' => 'Error: No token table');

			if (getEmailFormat($iSurveyID) == 'html')
				$bHtml = true;
			else
				$bHtml = false;

			$SQLemailstatuscondition = "emailstatus = 'OK'";
			$SQLremindercountcondition = '';
            $SQLreminderdelaycondition = '';
			$iMaxEmails = (int)Yii::app()->getConfig("maxemails");

			if(!is_null($iMinDaysBetween))
			{
				$compareddate = dateShift(date("Y-m-d H:i:s", time() - 86400 * $iMinDaysBetween), "Y-m-d H:i", $timeadjust);
                $SQLreminderdelaycondition = " ((remindersent = 'N' AND sent < '" . $compareddate . "')  OR  (remindersent < '" . $compareddate . "'))";
			}

			if(!is_null($iMaxReminders))
				$SQLremindercountcondition = "remindercount < " . $iMaxReminders;

			$oTokens = TokenDynamic::model($iSurveyID);
            $aAllTokens = $oTokens->findUninvitedIDs(false, 0, false, $SQLemailstatuscondition, $SQLremindercountcondition, $SQLreminderdelaycondition);
            $iAllTokensCount=count($aAllTokens);
            unset($aAllTokens); // save some memory before the next query
            
			$aResultTokens = $oTokens->findUninvited(false, $iMaxEmails, false, $SQLemailstatuscondition, $SQLremindercountcondition, $SQLreminderdelaycondition);

			if (empty($aResultTokens))
				return array('status' => 'Error: No candidate tokens');

			$aResult = emailTokens($iSurveyID, $aResultTokens, 'remind');

			$iLeft = $iAllTokensCount - count($aResultTokens);
			$aResult['status'] =$iLeft. " left to send";
			return $aResult;
		}
		else
			return array('status' => 'No permission');

	}


	/* Response specific functions */


    /**
     * RPC Routine to add a response to the survey responses collection.
     * Returns the id of the inserted survey response
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID Id of the Survey to insert responses
     * @param struct $aResponseData The actual response
     * @return int The response ID
     */
    public function add_response($sSessionKey, $iSurveyID, $aResponseData)
    {
        if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key');
        $oSurvey=Survey::model()->findByPk($iSurveyID);
        if (is_null($oSurvey))
        {
            return array('status' => 'Error: Invalid survey ID');
        }

        if (Permission::model()->hasSurveyPermission($iSurveyID, 'responses', 'create'))
        {
            if (!Yii::app()->db->schema->getTable('{{survey_' . $iSurveyID . '}}'))
                return array('status' => 'No survey response table');

            //set required values if not set

            // @todo: Some of this is part of the validation and should be done in the model instead
            if (!isset($aResponseData['submitdate']))
                $aResponseData['submitdate'] = date("Y-m-d H:i:s");
            if (!isset($aResponseData['startlanguage']))
                $aResponseData['startlanguage'] = getBaseLanguageFromSurveyID($iSurveyID);

            if ($oSurvey->datestamp=='Y')
            {
                if (!isset($aResponseData['datestamp']))
                    $aResponseData['datestamp'] = date("Y-m-d H:i:s");
                if (!isset($aResponseData['startdate']))
                    $aResponseData['startdate'] = date("Y-m-d H:i:s");
            }

            SurveyDynamic::sid($iSurveyID);
            $survey_dynamic = new SurveyDynamic;
            $aBasicDestinationFields=$survey_dynamic->tableSchema->columnNames;
            $aResponseData=array_intersect_key($aResponseData, array_flip($aBasicDestinationFields));
            $result_id = $survey_dynamic->insertRecords($aResponseData);

            if ($result_id)
                return $result_id;
            else
                return array('status' => 'Unable to add response');
        }
        else
            return array('status' => 'No permission');

    }
    
    /**
     * RPC Routine to update a response in a given survey.
     * Routine supports only single response updates.
     * Response to update will be identified either by the response id, or the token if response id is missing.
     * Routine is only applicable for active surveys with alloweditaftercompletion = Y.
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID Id of the Survey to update response
     * @param struct $aResponseData The actual response
     * @return mixed TRUE(bool) on success. errormessage on error
     */
    public function update_response($sSessionKey, $iSurveyID, $aResponseData)
    {
        if (!$this->_checkSessionKey($sSessionKey)) return 'Invalid session key';
        $oSurvey=Survey::model()->findByPk($iSurveyID);
        if (is_null($oSurvey))
        {
            return 'Error: Invalid survey ID';
        }
        if ($oSurvey->getAttribute('active') !== 'Y') {
        	return 'Error: Survey is not active.';
        }
        
        if ($oSurvey->getAttribute('alloweditaftercompletion') !== 'Y') {
        	return 'Error: Survey does not allow edit after completion.';
        }

        if (Permission::model()->hasSurveyPermission($iSurveyID, 'responses', 'update'))
        {
            if (!Yii::app()->db->schema->getTable('{{survey_' . $iSurveyID . '}}'))
                return 'Error: No survey response table';

            if (
            	!isset($aResponseData['id'])
            	&& ! isset($aResponseData['token'])
            ) {
            	return 'Error: Missing response identifier (id|token).';
            }
            
            SurveyDynamic::sid($iSurveyID);
            $oSurveyDynamic = new SurveyDynamic;
            
            if (isset($aResponseData['id'])) {
            	$aResponses = $oSurveyDynamic->findAllByPk($aResponseData['id']);
            } else {
            	$aResponses = $oSurveyDynamic->findAllByAttributes(array('token' => $aResponseData['token']));
            }
            
            if(empty($aResponses)) 
            	return 'Error: No matching Response.';
            if(count($aResponses) > 1) 
            	return 'Error: More then one matching response, updateing multiple responses at once is not supported.';
            
            $aBasicDestinationFields=$oSurveyDynamic->tableSchema->columnNames;
            $aInvalidFields= array_diff_key($aResponseData, array_flip($aBasicDestinationFields));
            if(count($aInvalidFields) > 0) 
            	return 'Error: Invalid Column names supplied: ' . implode(', ', array_keys($aInvalidFields));

            unset($aResponseData['token']);
            
            foreach ($aResponseData as $sAtributeName => $value) {
            	$aResponses[0]->setAttribute($sAtributeName, $value);
            }

            $bResult = $aResponses[0]->save(true);

            if ($bResult) {
                return $bResult;
            } else {
                return 'Unable to edit response';
            }
        } else {
            return 'No permission';
        }
    }    

    /**
     * RPC Routine to export responses.
     * Returns the requested file as base64 encoded string
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID Id of the Survey
     * @param string $sDocumentType pdf,csv,xls,doc,json
     * @param string $sLanguageCode The language to be used
     * @param string $sCompletionStatus Optional 'complete','incomplete' or 'all' - defaults to 'all'
     * @param string $sHeadingType 'code','full' or 'abbreviated' Optional defaults to 'code'
     * @param string $sResponseType 'short' or 'long' Optional defaults to 'short'
     * @param integer $iFromResponseID Optional
     * @param integer $iToResponseID Optional
     * @param array $aFields Optional Selected fields
     * @return array|string On success: Requested file as base 64-encoded string. On failure array with error information
     * */
    public function export_responses($sSessionKey, $iSurveyID, $sDocumentType, $sLanguageCode=null, $sCompletionStatus='all', $sHeadingType='code', $sResponseType='short', $iFromResponseID=null, $iToResponseID=null, $aFields=null)
    {
        if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key');
        Yii::app()->loadHelper('admin/exportresults');
        if (!tableExists('{{survey_' . $iSurveyID . '}}')) return array('status' => 'No Data, survey table does not exist.');
		if(!$maxId = SurveyDynamic::model($iSurveyID)->getMaxId()) return array('status' => 'No Data, could not get max id.');

        if (!Permission::model()->hasSurveyPermission($iSurveyID, 'responses', 'export')) return array('status' => 'No permission');
        if (is_null($sLanguageCode)) $sLanguageCode=getBaseLanguageFromSurveyID($iSurveyID);
        if (is_null($aFields)) $aFields=array_keys(createFieldMap($iSurveyID,'full',true,false,$sLanguageCode));
        if($sDocumentType=='xls'){
           // Cut down to the first 255 fields
           $aFields=array_slice($aFields,0,255);
        }
        $oFomattingOptions=new FormattingOptions();
        
        if($iFromResponseID !=null)   
			$oFomattingOptions->responseMinRecord=$iFromResponseID;
        else
			$oFomattingOptions->responseMinRecord=1;        
        
        if($iToResponseID !=null)   
            $oFomattingOptions->responseMaxRecord=$iToResponseID;
        else
            $oFomattingOptions->responseMaxRecord = $maxId;

        $oFomattingOptions->selectedColumns=$aFields;
        $oFomattingOptions->responseCompletionState=$sCompletionStatus;
        $oFomattingOptions->headingFormat=$sHeadingType;
        $oFomattingOptions->answerFormat=$sResponseType;
        $oFomattingOptions->output='file';

        $oExport=new ExportSurveyResultsService();
        $sTempFile=$oExport->exportSurvey($iSurveyID,$sLanguageCode, $sDocumentType,$oFomattingOptions, '');
        return new BigFile($sTempFile, true, 'base64');
    }

    /**
     * RPC Routine to export token response in a survey.
     * Returns the requested file as base64 encoded string
     *
     * @access public
     * @param string $sSessionKey Auth credentials
     * @param int $iSurveyID Id of the Survey
     * @param string $sDocumentType pdf,csv,xls,doc,json
     * @param string $sToken The token for which responses needed
     * @param string $sLanguageCode The language to be used
     * @param string $sCompletionStatus Optional 'complete','incomplete' or 'all' - defaults to 'all'
     * @param string $sHeadingType 'code','full' or 'abbreviated' Optional defaults to 'code'
     * @param string $sResponseType 'short' or 'long' Optional defaults to 'short'
     * @param array $aFields Optional Selected fields
     * @return array|string On success: Requested file as base 64-encoded string. On failure array with error information
     * 
     */
    public function export_responses_by_token($sSessionKey, $iSurveyID, $sDocumentType, $sToken, $sLanguageCode=null, $sCompletionStatus='all', $sHeadingType='code', $sResponseType='short', $aFields=null)
    {
        if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key');
        if (!Permission::model()->hasSurveyPermission($iSurveyID, 'responses', 'export')) return array('status' => 'No permission');
        if (!tableExists('{{survey_' . $iSurveyID . '}}')) return array('status' => 'No Data');
        if(!$oResult = SurveyDynamic::model($iSurveyID)->findByAttributes(array('token' => $sToken))) return array('status' => 'No Response found for Token');
		if ($oResult['id'])
        {
            return $this->export_responses($sSessionKey, $iSurveyID, $sDocumentType, $sLanguageCode, $sCompletionStatus, $sHeadingType, $sResponseType, $oResult['id'], $oResult['id'], $aFields);
        }
    }


    /**
     * Tries to login with username and password
     *
     * @access protected
     * @param string $sUsername The username
     * @param mixed $sPassword The Password
     * @return bool
     */
    protected function _doLogin($sUsername, $sPassword)
    {
        $identity = new UserIdentity(sanitize_user($sUsername), $sPassword);

        if (!$identity->authenticate())
        {
            return false;
        }
        else
            return true;
    }

    /**
     * Fills the session with necessary user info on the fly
     *
     * @access protected
     * @param string $username The username
     * @return bool
     */
    protected function _jumpStartSession($username)
    {
        $aUserData = User::model()->findByAttributes(array('users_name' => $username))->attributes;

        $session = array(
        'loginID' => intval($aUserData['uid']),
        'user' => $aUserData['users_name'],
        'full_name' => $aUserData['full_name'],
        'htmleditormode' => $aUserData['htmleditormode'],
        'templateeditormode' => $aUserData['templateeditormode'],
        'questionselectormode' => $aUserData['questionselectormode'],
        'dateformat' => $aUserData['dateformat'],
        'adminlang' => 'en'
        );
        foreach ($session as $k => $v)
            Yii::app()->session[$k] = $v;
        Yii::app()->user->setId($aUserData['uid']);

        $this->controller->_GetSessionUserRights($aUserData['uid']);
        return true;
    }

    /**
     * This function checks if the XML-RPC session key is valid. If yes returns true, otherwise false and sends an error message with error code 1
     *
     * @access protected
     * @param string $sSessionKey Auth credentials
     * @return bool
     */
    protected function _checkSessionKey($sSessionKey)
    {
        $criteria = new CDbCriteria;
        $criteria->condition = 'expire < ' . time();
        Session::model()->deleteAll($criteria);
        $oResult = Session::model()->findByPk($sSessionKey);

        if (is_null($oResult))
            return false;
        else
        {
            $this->_jumpStartSession($oResult->data);
            return true;
        }
    }
}