<?
/**
 * VoiceOne Webservices Interface
 *
 * @package voiceone_webservices
 * @subpackage  ivr
 */ 

//******************************************************************************
//****************               IVR GENERAL                ********************
//******************************************************************************


// ---- getIvr(id:int):Ivr[] ---------------------------------------------------
/**
 * Get all IVRs
 *
 * @return array ivr[] using the database record structure
 */
function getIvr($id){
  global $db;
  if(($id!=0)&&($id!="")) $condition="AND id=$id "; else $condition="";
  $qry="SELECT * FROM cw_ivr WHERE parent = 0 $condition ORDER BY name";
  $res=$db->Execute($qry);
  while ($arr=$res->FetchRow()) $ret[]=$arr;
  return $ret;
}

// ---- getChildNodes(id:int, parent:int):IvrNode[] ----------------------------
function getChildNodes($id){
  $ret=array();
  if(($id!=0)&&($id!="")){
    $root=getIvrNode($id,0);
    if(is_array($root)){
      $ret=$root;
      $children=getIvrNode(0,$id,true);
      if(is_array($children)) $ret=array_merge($ret,$children);
    }
  } 
  return $ret;
}

// ---- getIvrNode(id:int, parent:int):IvrNode[] -------------------------------
function getIvrNode($id=0,$parent=0,$recursive=false) {
  global $db;
  $ret=array();
  //Extract nodes
  if($id==0 AND $parent==0){ 
    // if parameters are null, select all nodes
    $qry="SELECT * FROM cw_ivr";
    $res=$db->Execute($qry);
    while ($arr=$res->FetchRow()) { 
      $ret[]=$arr;
    }
  }else if($parent!=0){
    // else if parent node is given,select all nodes which have given node as parent
    $qry="SELECT * FROM cw_ivr WHERE parent=$parent ORDER BY `order`";
    $res=$db->Execute($qry);
    while ($arr=$res->FetchRow()) { 
      $ret[]=$arr;
    }
    if(($recursive===true)&&(is_array($ret))){
      $nodeList=$ret;
      foreach($nodeList as $n){
        $ret_recoursive=getIvrNode(0,$n["id"],true);
        if(is_array($ret_recoursive)) $ret=array_merge($ret,$ret_recoursive);
      } 
    }
  }else if ($id!=0) {
    // else if node id is given, to select that node
    $qry="SELECT * FROM cw_ivr WHERE id=$id";
    $res=$db->Execute($qry);
    while ($arr=$res->FetchRow()) { 
      $ret[]=$arr;
    }
  }
  // return
  return $ret;
}

// ---- putIvrNode(node:IvrNode):int -------------------------------------------
function putIvrNode($node) {
  global $db,$asteriskAppDelimeter;
  // Extract node fields to vars
  extract($node);
  // If id is setted, delete old node    
  if($id!="" and $id!="0") {
    //retrieve the current (old) order number
    $qry="SELECT `order`,`parent` FROM cw_ivr WHERE id=$id";
    $res=$db->Execute($qry);
    $arr=$res->FetchRow();
    $oldPos=$arr["order"];
    $parent=$arr["parent"];
    delIvrNode($id,false,false);
  }else{
    $id="null";
  }
  //if no order is assigned, append as the last node
  if($order=="0" or $order=="") {
    if($parent=="") $parent=0;
    $res=$db->Execute("SELECT COUNT(*) as howmuch FROM cw_ivr WHERE parent=$parent");
    $arr=$res->FetchRow();
    $order=$arr["howmuch"]+1;
  }
  //check for swap node
  $qry="SELECT * FROM cw_ivr WHERE `order`=$order AND `parent`=$parent";
  $res=$db->Execute($qry);
  if($res->RecordCount()>0){
    if((isset($oldPos))&&($oldPos<$order)){
    	$qry="UPDATE cw_ivr SET `order`=(`order`-1) WHERE `order`<=$order AND `order`>$oldPos AND `parent`=$parent";
    }else if((isset($oldPos))&&($oldPos>$order)){
    	$qry="UPDATE cw_ivr SET `order`=(`order`+1) WHERE `order`>=$order AND `order`<$oldPos AND `parent`=$parent";
    }else{
      $qry="UPDATE cw_ivr SET `order`=(`order`+1) WHERE `order`>=$order AND `parent`=$parent";
    }	
    $db->Execute($qry);
  }
  //check for swap node
  /*
  $qry="SELECT * FROM cw_ivr WHERE `order`=$order AND `parent`=$parent";
  $res=$db->Execute($qry);
  if($res->RecordCount()>0){
    $arr = $res->FetchRow();
    $nodeToSwap=$arr["id"];
    //if no order is assigned, append as the last node
    if($oldPos==""){
      if($parent=="") $parent=0;
      $res=$db->Execute("SELECT COUNT(*) as howmuch FROM cw_ivr WHERE parent=$parent");
      $arr=$res->FetchRow();
      $oldPos=$arr["howmuch"]+1;
    }
    $qry="UPDATE cw_ivr SET `order`=$oldPos WHERE id=$nodeToSwap";
    $db->Execute($qry);
  }
  */
  //insert the new node
  $qry="INSERT INTO cw_ivr (`id`,`name`,`type`,`parent`,`order`, `key`, `maudio`, `waudio`, `beep`, `macro`, `parameter`, `link`, `timesegment`, ";
  $qry.="`taudio`, `trepeat`, `ttimes`, `iaudio`, `irepeat`, `itimes`, `tmacro`, `tparameter`, `imacro`, `iparameter`) ";
  $qry.="VALUES ($id,'".string2sql($name)."',".$type.",'".$parent."','".$order."','".string2sql($key)."','".$maudio."','".$waudio."','".$beep."','".$macro."',";
  $qry.="'".string2sql($parameter)."','".$link."','".$timesegment."','".$taudio."','".$trepeat."','".$ttimes."','".$iaudio."','".$irepeat."','".$itimes."',";
  $qry.="'".$tmacro."','".string2sql($tparameter)."','".$imacro."','".string2sql($iparameter)."')";
  $res=$db->Execute($qry);
  if ($res===false) return new soap_fault('Server','','IVR creation error, mysql INSERT command failed');
  else $node_id=$db->Insert_ID();
  if($id=="null") $id=$node_id;
  //if node is root insert in ast_config
  if($parent==0){
    $context="ivr_".$id; 
    putAstConfig("extensions.conf", $context, "", "", "IVR ".$name, 1);
    putAstConfig("extensions.conf", $context, "exten", "s,1,AGI(playivr.php".$asteriskAppDelimeter."id=$id)");
    //reload asterisk
    $status=pbxSwitch("status");
    if($status=="ON") sendCommand("reload");
  }
  //return node id
  return $id;
}

// ---- delIvrNode(id:int):int -------------------------------------------------
function delIvrNode($id,$recursive=true,$reload=true) {
  global $db;
  // Delete all node's children
  if($recursive===true){
    $ret=getIvrNode(0,$id,false);
    if(is_array($ret)){
      foreach($ret as $childNode) delIvrNode($childNode["id"],true,false);
    }
  }
  // If it is root node, delete from ast_config
  $ret=getIvrNode($id,0,false);
  if(is_array($ret)){
    $node=$ret[0];
    if($node["parent"]==0){
      $context="ivr_".$node["id"];
      delAstConfig("extensions.conf", $context);
      if($reload===true){  
        $status=pbxSwitch("status");
        if($status=="ON") sendCommand("reload");
      }
    }
  }
  // Delete Node
  $qry="DELETE FROM cw_ivr WHERE id=$id";
  $res=$db->Execute($qry);
  if ($res===false) return new soap_fault('Server','','Ivr remove error, mysql DELETE command failed');
  return 1;
}

//******************************************************************************
//***********               IVR AUDIO MANAGEMENT                ****************
//******************************************************************************

// ---- getIvrAudioFile():audiofile[] ------------------------------------------
/**
 * Get list of audiofiles available in IVR
 * @return array audiofile[] using the database record structure
 */
function getIvrAudioFile() {
  global $db; 
    $catIVR_id=getCatidByTagname("IVR");
    $qry="SELECT * FROM `cw_sounds_file` WHERE `category`=".$catIVR_id." AND `language`='en' ORDER BY name";
    $res=$db->Execute($qry); 
    while($arr=$res->FetchRow()) {
      //$tmp=ereg(".*/(.*)", $arr["filepath"], $div1); //DEPRECATED IN PHP 5.3
      //$name_complete=$div1[1];
      $name_complete=basename($arr["filepath"]);
      $ret["name"]=substr($name_complete,0,-4); 
      $ret["filename"]=$name_complete; 
      $ret["date"]=$arr["lastmodified"];
      $ret["id"]=$arr["id"]; 
      $result[]=$ret;
    }
  return $result;
}

// ---- putIvrAudioFile(name:string, filename:string):int ----------------------
function putIvrAudioFile($name,$filename) {
  global $db, $voTools, $ivrStartingDir;
  exec("sudo $voTools getSoundsDir",$output,$retScript);
  $soundspath=$output[0];
  $file_path=$soundspath."/".$ivrStartingDir.$filename;
  $date=date("Y-m-d H:s:i");
  $catIVR_id=getCatidByTagname("IVR");
  $qry="SELECT * FROM `cw_sounds_file` WHERE `filepath`='".string2sql($file_path)."'";
  $res=$db->Execute($qry); 
  $i=0;
  while($arr=$res->FetchRow()) {
    $ret[$i]=$arr;
    $i++;
  }
  if(count($ret)>0) {
    $qry="UPDATE `cw_sounds_file` SET `name`='".string2sql($name)."', `filepath`='".string2sql($file_path)."', `lastmodified`='".$date."' WHERE `id`=".$ret[0]["id"]."";
    $res=$db->Execute($qry);
  } else {
    $qry="INSERT INTO `cw_sounds_file` ( `id` , `name` , `category` , `language` , `filepath` , `present` , `text` , `lastmodified` ) ";
    $qry.="VALUES (NULL , '".string2sql($name)."', ".$catIVR_id.", 'default', '".string2sql($file_path)."', 1, '', '".$date."');";
    $res=$db->Execute($qry);
  }
  return 1;
}

// ---- recordIvrAudioFile(filename:string, clientId:int):int ------------------
function recordIvrAudioFile($filename,$clientId) {
  global $floapi,$API_user,$API_pass,$API_host;
  //retrieve application id
  $arappl=getApplicationByName("audiorecorder");
  $AUDIO_RECORDER_APPLICATION=$arappl[0]["id"];
  //retrieve some information from db
  $clientArr=getClient($clientId,0);
  $client=$clientArr[0];
  $channelArr=getChannel(getChannelFromEntity($clientId));
  $channelName=$channelArr[0]["name"];
  $ruleId=$client["rule"];
  $ruleArr=getRule($ruleId);
  $ruleName=$ruleArr[0]["name"];
  $applicationArr=getApplication($AUDIO_RECORDER_APPLICATION);
  $application=$applicationArr[0];
  $appExtension=$application["extension"];
  //originate a call
  $entry=array('Channel'=>$channelName,'Exten'=>$appExtension,'Context'=>$ruleName,'Priority'=>1,'Callerid'=>"IVR Audio Recorder <$filename>");
  $floapi = new floAPI($API_user, $API_pass, $API_host);
  if ($floapi->socket!="") {
    $ret= $floapi->request("Originate", $entry);
    $floapi->close();
    return 1;
  } else return 0;
}

// ---- deleteIvrAudioFile(filename:string):int --------------------------------
/**
* Delete an audiofile from the database and from the filesystem. Works only in the IVR file directory
*
* @param int $id Existing file id
* @return integer 1 = ok, 0 = error (file not found or file in use)
* @todo Should inform the  user that if a  request for delete an audiofile  would break one of the IVR's and therefore nothing is deleted.
*/
function deleteIvrAudioFile($id) {
  global $db, $ivrStartingDir, $voTools;
  $sound=getSound($id);
  if(!is_array($sound)) return 0;
  $filepath=$sound[0]["filepath"];
  //delete from db
  $qry="DELETE FROM `cw_sounds_file` WHERE `id`=$id";
  $res=$db->Execute($qry);
  if($res===false) return 0;
  //delete from fs
  $mycmd="deleteAudiofile";
  $myparam1=$ivrStartingDir.str_replace($ivrStartingDir,"",strstr($filepath,$ivrStartingDir));  
  system("sudo $voTools $mycmd $myparam1");
  return 1;
}

// -- renameIvrAudioFile(id:int, newFilename:string, newName:string):int -------
/**
* Rename an audiofile in the database and in the filesystem. Works only in the IVR file directory
* If the filename is in use by any IVR, the IVR Menu is modified to match the new audiofilename
* The user has to rebuild the IVR as if he/she would do for any other change
*
* @param int $id Existing file id
* @param string $newFilename New filename provided by user
* @param string $newName New name for that file as it shows up in frontend. So far it is the same as NewFilename without extension
* @return integer 1 = ok, 0 = error (filename not found or newFilename in use)
* @todo Inform User if an IVR was modified, which IVR has to be rebuiled
*/
function renameIvrAudioFile($id, $newFilename, $newName) {
  global $db, $ivrStartingDir, $voTools;
  exec("sudo $voTools getSoundsDir",$output,$retScript);
  $soundspath=$output[0];
  $newfile_path=$soundspath."/".$ivrStartingDir.$newFilename;
  //retireve old filename
  $sound=getSound($id);
  if(!is_array($sound)) return 0;
  $filepath=$sound[0]["filepath"];
  //rename in db
  $qry="UPDATE `cw_sounds_file` SET `name`='".string2sql($newName)."' , `filepath`='".string2sql($newfile_path)."' WHERE `id`=".$id;
  $res=$db->Execute($qry);
  if($res===false) return 0;
  //rename in fs
  $myparam1=$ivrStartingDir.str_replace($ivrStartingDir,"",strstr($filepath,$ivrStartingDir)); 
  $myparam2=$ivrStartingDir.$newFilename;
  exec("sudo $voTools renameAudiofile $myparam1 $myparam2");
  return 1;
}

//******************************************************************************
//************               IVR DELETED METHODS                ****************
//******************************************************************************

/*
// ---- swapIvrNode(id:int, newpos:int):int --------------------------------------------------
function swapIvrNode($id,$parent,$newPos,$oldPos) {
  global $db;
  
  if ($newPos=="") return;
  if ($oldPos==newPos) return;
 
  //retrieve the current (old) order number
  $qry="SELECT * FROM cw_ivr_node WHERE `order`=$newPos AND `parent`=$parent";
  $res=$db->Execute($qry);
  if ($res->RecordCount()>0) {
    $arr = $res->FetchRow();
    $nodeToSwap=$arr["id"];
    $qry="UPDATE cw_ivr_node SET `order`=$oldPos WHERE id=$nodeToSwap";
    $db->Execute($qry);  
  }
  return;
}


// ---- moveIvrNode(id:int, direction: int):int --------------------------------------------------
// Direction=1 : up
// Direction=2: down

function moveIvrNode($id,$direction=1) {
  global $db;
  
  //retrieve the current order number
  $qry="SELECT `order`,`parent` FROM cw_ivr_node WHERE id=$id";
  $res=$db->Execute($qry);
  $arr = $res->FetchRow();
  $order=$arr["order"];
  $parent=$arr["parent"];
  if ($parent=="") $parent=0;
  

  if ($direction==1 and $order>1) {
    $res=$db->Execute("UPDATE cw_ivr_node SET `order`='$order' WHERE `parent`=$parent AND `order`=".($order-1));
    if ($db->Affected_Rows()>0) $res=$db->Execute("UPDATE cw_ivr_node SET `order`=".($order-1)." WHERE id=$id");
  } else if ($direction==2) {
    $res=$db->Execute("UPDATE cw_ivr_node SET `order`=$order WHERE `parent`=$parent AND `order`=".($order+1));
    if ($db->Affected_Rows()>0) $res=$db->Execute("UPDATE cw_ivr_node SET `order`=".($order+1)." WHERE id=$id");
  }
  if ($res===false) return new soap_fault('Server','','Ivr move error, mysql UPDATE command failed');
  else return 1;

}


// ---- compileIvr($ivr_id:int):int --------------------------------------------

function compileIvr($ivr_id) {
  global $db,$ivrPrefix,$ivrScriptConversionPath;

  //clear the old ivr
  clearIvr($ivr_id);

  //$ret=exec("$ivrScriptConversionPath &",$out);

  //build the new ivr
  _compileIvr($ivr_id);

  //if asterisk is ON, reload extensions
  $status=pbxSwitch("status");
  if($status=="ON") sendCommand("reload");

  return 1;
}  

// ---- clearIvr():int --------------------------------------------------
//private

function clearIvr($ivr_id) {
  global $db,$ivrPrefix;
  
  $qry="DELETE FROM extensions_table WHERE context like '".string2sql($ivrPrefix.$ivr_id)."%'";
  $res=$db->Execute($qry);

  $res=delAstConfig("extensions.conf",$ivrPrefix.$ivr_id."%");

  return 1;
}

// ----    _compileIvr():int     -----------------------------------------------
//private

function _compileIvr($ivr_id,$parent=0) {
  global $db,$ivrPrefix,$ivrStartingDir,$asteriskAppDelimeter;

  //retrieve the parent node name (calculate the context)
  $qry="SELECT * FROM cw_ivr_node WHERE `id`=$parent";
  $resp=$db->Execute($qry);
  $arrp=$resp->FetchRow();
  $context=$ivrPrefix.$ivr_id.$arrp["name"];
  
  //set the query for cycling through the children nodes
  if ($parent==0) {
    $i=getIvr($ivr_id);
    $rootNode=$i[0]["rootnode"];
    $qry="SELECT * FROM cw_ivr_node WHERE `id`=$rootNode";
  } else 
    $qry="SELECT * FROM cw_ivr_node WHERE `parent`=$parent ORDER BY `order`";
  
  $playBeep=false;
  $priority=1;
  $res=$db->Execute($qry);
  while ($arr = $res->FetchRow()) {
    $nodeId=$arr["id"];
    $nodeName=$arr["name"];
    $nodeParent=$arr["parent"];
    $nodeAudio=str_replace(" ","",substr($arr["audio"],0,strpos($arr["audio"],".")));
    $nodeIAudio=str_replace(" ","",substr($arr["iaudio"],0,strpos($arr["iaudio"],".")));
    $nodeTAudio=str_replace(" ","",substr($arr["taudio"],0,strpos($arr["taudio"],".")));
    $nodeContext=$ivrPrefix.$ivr_id.$nodeName;
    $nodeKey=$arr["key"];
    $nodeMacro=$arr["macro"];
    $nodeIRepeat=$arr["irepeat"];
    $nodeTRepeat=$arr["trepeat"];
    $nodeParameter=$arr["parameter"];

    //branch or leaf?
    $qry="SELECT * FROM cw_ivr_node WHERE `parent`=$nodeId";
    $resp=$db->Execute($qry);
    if ($resp->RecordCount()>0) $nodeFolder=true;
    else $nodeFolder=false;
    
    //play the audio files
    if ($nodeAudio!="") 
      putAstConfig("extensions.conf", $context, "exten", "s,".($priority++).",Background(".$ivrStartingDir.$nodeAudio.")");

    //insert the extension KEY for jumping inside the branches
    if ($nodeFolder===true) {
      if ($nodeKey=="")
        putAstConfig("extensions.conf", $context, "exten", "s,".($priority++).",Goto($nodeContext".$asteriskAppDelimeter."s".$asteriskAppDelimeter."1)");
      else 
        putAstConfig("extensions.conf", $context, "exten", "$nodeKey,1,Goto($nodeContext".$asteriskAppDelimeter."s".$asteriskAppDelimeter."1)");
    }

    //take action
    if ($nodeMacro!=0 and $nodeFolder===false) {
      $macroArr=prepareMacro($nodeMacro,$nodeParameter);
      $macroName=$macroArr[0];
      $macroParam=substr($macroArr[1],1); 
      $macroParam=$macroArr[1];  
      if ($nodeKey=="") 
        putAstConfig("extensions.conf", $context, "exten", "s,".($priority++).",Macro(".$macroName.$macroParam.")");
      else 
        putAstConfig("extensions.conf", $context, "exten", "$nodeKey,1,Macro(".$macroName.$macroParam.")");
    }
      
    //insert the INVALID and TIMEOUT extensions
    if ($nodeFolder===true) {
      $ipriority=1;
      $tpriority=1;
      if ($nodeIAudio!="") 
        putAstConfig("extensions.conf", $nodeContext, "exten", "i,".($ipriority++).",Background(".$ivrStartingDir.$nodeIAudio.")");
      if ($nodeIRepeat==1) 
        putAstConfig("extensions.conf", $nodeContext, "exten", "i,".($ipriority++).",Goto($nodeContext".$asteriskAppDelimeter."s".$asteriskAppDelimeter."1)");
      if ($nodeTAudio!="") 
        putAstConfig("extensions.conf", $nodeContext, "exten", "t,".($tpriority++).",Background(".$ivrStartingDir.$nodeTAudio.")");
      if ($nodeTRepeat==1) 
        putAstConfig("extensions.conf", $nodeContext, "exten", "t,".($tpriority++).",Goto($nodeContext".$asteriskAppDelimeter."s".$asteriskAppDelimeter."1)");
    }

    //set the playBeep variable
    if ($nodeKey!="") $playBeep=true;
    
    //recursively create the tree
    if ($nodeFolder===true) _compileIvr($ivr_id,$nodeId);
  }

  //play beep
  if ($playBeep===true)
    putAstConfig("extensions.conf", $context, "exten", "s,".($priority++).",Playback(beep)");
    putAstConfig("extensions.conf", $context, "exten", "s,".($priority++).",WaitExten()");
  
  
  //manage the root node case:
  if ($parent==0) {
    putAstConfig("extensions.conf", $context, "exten", "s,".($priority++).",Hangup");
    putAstConfig("extensions.conf", $context, "exten", "i,1,Goto($context".$asteriskAppDelimeter."s".$asteriskAppDelimeter."1)");
    putAstConfig("extensions.conf", $context, "exten", "t,1,Goto($context".$asteriskAppDelimeter."s".$asteriskAppDelimeter."1)");
  }
  
  return;
}
*/
