/**
 * agi_call - place a call on asterisk server. 
 *
 * It executes Dial($callStr...) and add support for prepay system
 *
 * PRE : * if the destination is a local destinatin, this destination exist
 *	 * $extension: only use for logging purpose
 *	 * $callStr, destination for Dial application of asterisk
 *	 * $callOptions << !!!!!!!!!! USE THIS WITH CARE !!!!!!!!
 *	 * $priceConn connection price >= 0
 *	 * $price the price/minutes of the call >= 0
 * 	 * $callerId a the callerId (only the number)
 *	 * $callerIdFull : full callerId
 *	 * logIfFailed : if the function have to log a call even if it failed.
 *
 *
 * POST : * call is logged
 *	  * prepay card of the callerId is updated if the call succeed 
 * 		^ if the call is not free
 *	  * if the callerId is not a person, it checks for a owner
 *	  	of the callerId in the database and use his prepaid card
 *	  * return the price of the call
 *	  * $call->set_lastTryStatus with the return status of Application Dial
 *		in case of 'not enough of money' : "MONEY'
 */
function agi_call(&$call, $callStr, $callOptions, $priceConn, $price, $logIfFailed = true)
{
    global $db;
    $extension = $call->get_extension();
    $callerId = $call->get_cid();
    $callerIdFull = $call->get_cidFull();
    $account = $call->get_responsable();
    agi_log(DEBUG_DEBUG, "agi_call : {$callStr}, {$priceConn}, " . "{$price}, {$callerId}, {$callerIdFull}");
    // first I check if the callerId is a valid person in the database
    $query = "select P.Credit, P.Announce, P.AskHigherCost, " . "\tP.AllowOtherCID " . "  from People_PrePay_Settings as P  " . " where People_Extension = {$account}";
    $query = $db->query($query);
    check_db($query);
    if (!($row = $query->fetchRow(DB_FETCHMODE_ORDERED)) or $account != $callerId and !$row[3]) {
        // introuvable ou le responsable qui ne prend pas en charge
        $found = false;
        $credit = 0;
        $announce = false;
        $ask = false;
    } else {
        $found = true;
        $credit = $row[0];
        $announce = $row[1];
        $ask = $row[2];
    }
    if ($price + $priceConn > $credit) {
        agi_log(DEBUG_INFO, "agi_call(): not enough money");
        agi_play_soundSet(SOUNDSET_NOT_ENOUGH_MONEY, "");
        $call->set_lastTryStatus("MONEY");
        if ($logIfFailed) {
            agi_logCall($call, $price, 0, "MONEY");
        }
        return -1;
    }
    // bon on a assez de soux que pour faire l'appel.... on dial
    if ($price == 0) {
        agi_write("EXEC DIAL {$callStr}||{$callOptions}", true);
    } else {
        $maxSec = ($credit - $priceConn) / $price * 60 * 1000;
        agi_write("EXEC DIAL {$callStr}||{$callOptions}L({$maxSec})", true);
    }
    $answeredTime = agi_getVar("ANSWEREDTIME");
    $dialStatus = agi_getVar("DIALSTATUS");
    $call->set_lastTryStatus($dialStatus);
    agi_log(DEBUG_INFO, "agi_dial : {$extension} -> {$callStr} " . ": {$dialStatus} : {$answeredTime}");
    $total = $priceConn + ceil($answeredTime / 60) * $price;
    if ($dialStatus == "ANSWER") {
        agi_logCall($call, $price, $answeredTime, $dialStatus);
        agi_credit($account, -$total);
    } else {
        if ($logIfFailed) {
            agi_logCall($call, $price, $answeredTime, $dialStatus);
        }
    }
    return $total;
}
function outside_dial(&$call)
{
    global $db;
    // 1°) trouver à quel réseau appartient l'extension
    $net = outside_getNetworkId($call);
    agi_log(DEBUG_DEBUG, 'outside_dial() : ' . $call->get_extension() . " -> {$net}");
    if ($net < 0) {
        return agi_notFound($call);
    }
    // 2°) faut-il annoncer le prix à l'utilisateur ?
    //	faut-il continuer plus cher ?
    $query = "select P.Announce, P.AskHigherCost " . "  from People_PrePay_Settings as P  " . " where People_Extension = " . $call->get_responsable();
    $query = $db->query($query);
    check_db($query);
    if (!($row = $query->fetchRow(DB_FETCHMODE_ORDERED))) {
        // not found : paramètre par défaut :
        $askHigher = false;
        $announce = true;
        agi_log(DEBUG_INFO, "outside_dial() : account not found");
    } else {
        $askHigher = $row[1];
        $announce = $row[0];
    }
    agi_log(DEBUG_DEBUG, "outside_dial() : {$announce} - {$askHigher}");
    // 3°) récupérer la liste des providers et leur prix
    $query = "select N.Name, N.channel, P.ConnectionPrice, P.Price, " . "       P.RmDigits, P.AddDigits, N.DialOpts " . " from  NetworkProvider as N, Price as P, " . "\t NetworkTimeZone_details as T " . " where P.Network_ID = {$net} " . "   and P.NetworkProvider_ID = N.ID " . "   and P.NetworkTimeZone_ID = T.NetworkTimeZone_ID " . "   and (" . date("i") . " between start_min and end_min )" . "   and (" . date("G") . " between start_hour and end_hour )" . "   and (" . date("n") . " between start_month and end_month )" . "   and (" . date("j") . " between start_dom and end_dom )" . "   and (" . date("w") . " between start_dow and end_dow )" . " order by P.Price, P.ConnectionPrice ";
    $query = $db->query($query);
    check_db($query);
    /*	0 : name	
     *	1 : channel
     *	2 : priceConn
     *	3 : price/min
     *	4 : RmDigits
     *	5 : AddDigits
     *	6 : DialOpts
     */
    if ($query->numRows() == 0) {
        return agi_notFound($call);
    }
    $provider = $query->fetchRow(DB_FETCHMODE_ORDERED);
    // 4°) on tente d'appeler
    $isFirst = true;
    // première tentative au prix le plus bas
    while (($isFirst || $askHigher) && $provider != NULL) {
        $price = $provider[3];
        // 5°) on annonce au besoin :
        if ($announce) {
            agi_play_soundSet(SOUNDSET_PRICE_ANNOUNCE, "");
            agi_sayNumber(ceil($price * 100));
            agi_play_soundSet(SOUNDSET_CURRENCY, "");
        }
        // on teste l'un à la suite de l'autre tout les providers
        // qui ont le même prix d'appel
        while ($provider[3] == $price && $provider != NULL) {
            $callStr = $provider[1] . $provider[5] . substr($call->get_extension(), $provider[4]);
            agi_log(DEBUG_DEBUG, "outside_dial() : trying : {$callStr}");
            $result = agi_call($call, $callStr, $provider[6], $provider[2], $provider[3], false);
            if ($result >= 0 || $call->get_lastTryStatus() != "CHANUNAVIL") {
                // succeed
                return $result;
            }
            $provider = $query->fetchRow(DB_FETCHMODE_ORDERED);
        }
        // annonce qu'il est impossible d'effectuer l'appel au prix
        // annoncé précédement
        agi_play_soundSet(SOUNDSET_UNAVAIL_AT_PRICE, "");
        $first = false;
        // téléchargement du provider suivant
        $provider = $query->fetchRow(DB_FETCHMODE_ORDERED);
    }
    agi_logCall($call, 0, 0, "NOT ROUTABLE");
    return -1;
}