<?php
class SendsmsApi
{
    var $url = "https://api.sendsms.ro/json";

    var $curl = false;

    var $debugState = false;

    var $error = null;

    var $username = null;

    var $password = null;

    var $performActionsImmediately = true;

    var $queuedActions = array();

    function __construct()
    {
        $ver = explode(".", phpversion());
        if (($ver[0] >= 5)) {
            $this->debug("Version OK " . implode(".", $ver));
            if (!function_exists('json_decode') || !function_exists('json_encode')) {
                $this->debug("You need the json_encode and json_decode functions to use this Class, JSON is available in PHP 5.2.0 and up for alternatives please see https://json.org");
                $this->debug("Your PHP version is " . implode(".", $ver) . " " . __FILE__);
                die();
            }
        } else {
            $this->debug("You need at least PHP 5 to use this Class " . __FILE__);
            die();
        }
    }

    function call_api($url)
    {
        if (function_exists('curl_init')) {
            if ($this->curl === FALSE) {
                $this->curl = curl_init();
            } else {
                curl_close($this->curl);
                $this->curl = curl_init();
            }
            $this->debug($url);
            curl_setopt($this->curl, CURLOPT_HEADER, 1);
            curl_setopt($this->curl, CURLOPT_URL, $url);
            curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($this->curl, CURLINFO_HEADER_OUT, true);
            curl_setopt($this->curl, CURLOPT_HTTPHEADER, array("Connection: keep-alive"));

            $result = curl_exec($this->curl);

            $size = curl_getinfo($this->curl, CURLINFO_HEADER_SIZE);
            $request_headers = curl_getinfo($this->curl, CURLINFO_HEADER_OUT);
            $response_headers = substr($result, 0, $size);
            $result = substr($result, $size);

            $this->debug("--- HTTP Request trace --- ");
            $this->debug($request_headers, false);
            $this->debug($response_headers, false);
            $this->debug($result);

            if ($result !== FALSE) {
                return json_decode($result, true);
            }
            return false;
        } else {
            $this->debug("You need cURL to use this API Library");
        }

        return FALSE;
    }

    function call_api_action($method, $params, $authenticate = true)
    {
        if ($this->performActionsImmediately) {
            $url = $this->url . "?action=" . urlencode($method->getName());
            if ($authenticate) {
                if (!is_null($this->password) && !is_null($this->username)) {
                    $url .= "&username=" . urlencode($this->username);
                    $url .= "&password=" . urlencode($this->password);
                } else {
                    $this->debug("You need to specify your username and password using setUsername() and setPassword()");
                    return FALSE;
                }
            }
            $parameters = $method->getParameters();
            for ($i = 0; $i < count($params); $i++) {
                if (!is_bool($params[$i]) && !is_null($params[$i])) {
                    $url .= "&" . urlencode($parameters[$i]->getName()) . "=" . urlencode($params[$i]);
                } elseif (is_bool($params[$i]) && !is_null($params[$i])) {
                    $url .= "&" . urlencode($parameters[$i]->getName()) . "=" . urlencode($params[$i] ? "true" : "false");
                }
            }

            return $this->call_api($url);
        } else {
            if (is_null($this->username) || is_null($this->password)) {
                $this->debug("You need to specify your username and password using setUsername() and setPassword() to perform bulk actions");
                return FALSE;
            }
            $action = array(
                'command' => $method->getName(),
                'params' => array()
            );

            $parameters = $method->getParameters();
            for ($i = 0; $i < count($params); $i++) {
                $action['params'][$parameters[$i]->getName()] = $params[$i];
            }

            $this->queuedActions[] = $action;
            return TRUE;
        }
    }

    /**
     *   Set the global username
     *
     *   @param string $username
     */
    function setUsername($username)
    {
        $this->username = $username;
    }

    /**
     *   Set the global password / API Key
     *
     *   @param string $password
     */
    function setPassword($password)
    {
        $this->password = $password;
    }

    /**
     *   Gets a list of contacts for a particular group
     *
     *   @global string $username
     *   @global string $password
     *   @param int $group_id: The ID of the group
     */
    function address_book_contacts_get_list($group_id)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Add a contact to a group
     *
     *   @global string $username
     *   @global string $password
     *   @param int $group_id: The group ID to add the record to
     *   @param string $phone_number: Phone number of the contact
     *   @param string $first_name (optional): First name of the contact
     *   @param string $last_name (optional): Last name of the contact
     */
    function address_book_contact_add($group_id, $phone_number, $first_name = null, $last_name = null)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Delete a contact
     *
     *   @global string $username
     *   @global string $password
     *   @param int $contact_id
     */
    function address_book_contact_delete($contact_id)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Update an existing contact
     *
     *   @global string $username
     *   @global string $password
     *   @param int $contact_id: The contact ID of the record
     *   @param string $phone_number (optional): Phone number of the contact
     *   @param string $first_name (optional): First name of the contact
     *   @param string $last_name (optional): Last name of the contact
     */
    function address_book_contact_update($contact_id, $phone_number = null, $first_name = null, $last_name = null)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Retrieves a list of address book groups
     *
     *   @global string $username
     *   @global string $password
     */
    function address_book_groups_get_list()
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Adds a new address book group
     *
     *   @global string $username
     *   @global string $password
     *   @param string $name: The new of the new group
     */
    function address_book_group_add($name)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Deletes an address book group
     *
     *   @global string $username
     *   @global string $password
     *   @param int $group_id: The ID of the group
     */
    function address_book_group_delete($group_id)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Retrieves a list of the user batches.
     *
     *   @global string $username
     *   @global string $password
     */
    function batches_list()
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Checks the status of a batch
     *
     *   @global string $username
     *   @global string $password
     *   @param int $batch_id: The ID of the batch
     */
    function batch_check_status($batch_id)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Creates a new batch
     *
     *   @global string $username
     *   @global string $password
     *   @param string $name: The name of the batch
     *   @param int $throughput (optional): Throughput to deliver this batch at
     *   @param boolean $filter (optional): Filter this batch against the global blocklist
     *   @param string $file_type (optional): The type of the file
     *   @param string $start_time (optional): The time when the batch will start
     */
    function batch_create($name, $file, $throughput = 0, $filter = false, $file_type = 'csv', $start_time = null)
    {
        /* This function has special requirements in terms of streaming raw data, hence it calls the API directly */
        if (function_exists('curl_init')) {
            if ($this->curl === FALSE) {
                $this->curl = curl_init();
            } else {
                curl_close($this->curl);
                $this->curl = curl_init();
            }


            if (!file_exists($file)) {
                $this->debug("File {$file} does not exist");
                return FALSE;
            }

            if ($file_type != 'zip') {
                $data = "data=" . urlencode(file_get_contents($file));
            } else {
                $data = "data=" . urlencode(base64_encode(file_get_contents($file)));
            }

            $url = $this->url . "?action=batch_create";
            $url .= "&username=" . urlencode($this->username);
            $url .= "&password=" . urlencode($this->password);
            $url .= "&name=" . urlencode($name);
            $url .= "&file_type=" . urlencode($file_type);
            $url .= "&filter=" . ($filter ? 'true' : 'false');
            $url .= "&throughput=" . $throughput;

            if (!is_null($start_time)) {
                $url .= "&start_time=" . urlencode($start_time);
            }

            $this->debug($url);
            $this->debug($data);
            curl_setopt($this->curl, CURLOPT_HEADER, 1);
            curl_setopt($this->curl, CURLOPT_URL, $url);
            curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($this->curl, CURLINFO_HEADER_OUT, true);
            curl_setopt($this->curl, CURLOPT_HTTPHEADER, array("Connection: keep-alive"));
            curl_setopt($this->curl, CURLOPT_POST, 1);
            curl_setopt($this->curl, CURLOPT_POSTFIELDS, $data);

            $result = curl_exec($this->curl);

            $size = curl_getinfo($this->curl, CURLINFO_HEADER_SIZE);
            $request_headers = curl_getinfo($this->curl, CURLINFO_HEADER_OUT);
            $response_headers = substr($result, 0, $size);
            $result = substr($result, $size);

            $this->debug("--- HTTP Request trace --- ");
            $this->debug($request_headers, false);
            $this->debug($response_headers, false);
            $this->debug($result);

            if ($result !== FALSE) {
                return json_decode($result, true);
            }
            return false;
        } else {
            $this->debug("You need cURL to use this API Library");
        }
        return false;
    }

    /**
     *   Starts the given batch
     *
     *   @global string $username
     *   @global string $password
     *   @param int $batch_id: The ID of the batch
     */
    function batch_start($batch_id)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Stops/pauses the given batch
     *
     *   @global string $username
     *   @global string $password
     *   @param int $batch_id: The ID of the batch
     */
    function batch_stop($batch_id)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Add the given number to block list
     *
     *   @global string $username
     *   @global string $password
     *   @param int $phonenumber: The phone number
     */
    function blocklist_add($phonenumber)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Delete the given number from block list
     *
     *   @global string $username
     *   @global string $password
     *   @param int $phonenumber: The phone number
     */
    function blocklist_del($phonenumber)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Check if the given number is in block list
     *
     *   @global string $username
     *   @global string $password
     *   @param int $phonenumber: The phone number
     */
    function blocklist_check($phonenumber)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   This action allows you to execute multiple actions within the API with a single request.
     *
     *   @global string $username
     *   @global string $password
     */
    function execute_multiple()
    {
        if (function_exists('curl_init')) {
            if ($this->curl === FALSE) {
                $this->curl = curl_init();
            } else {
                curl_close($this->curl);
                $this->curl = curl_init();
            }

            $url = $this->url . "?action=execute_multiple";
            $url .= "&username=" . urlencode($this->username);
            $url .= "&password=" . urlencode($this->password);

            $this->debug($url);
            $this->debug("data=" . urlencode(json_encode($this->queuedActions)));
            curl_setopt($this->curl, CURLOPT_HEADER, 1);
            curl_setopt($this->curl, CURLOPT_URL, $url);
            curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($this->curl, CURLINFO_HEADER_OUT, true);
            curl_setopt($this->curl, CURLOPT_POST, 1);
            curl_setopt($this->curl, CURLOPT_POSTFIELDS, "data=" . urlencode(json_encode($this->queuedActions)));
            curl_setopt($this->curl, CURLOPT_HTTPHEADER, array("Connection: keep-alive"));

            $result = curl_exec($this->curl);

            $size = curl_getinfo($this->curl, CURLINFO_HEADER_SIZE);
            $request_headers = curl_getinfo($this->curl, CURLINFO_HEADER_OUT);
            $response_headers = substr($result, 0, $size);
            $result = substr($result, $size);

            $this->debug("--- HTTP Request trace --- ");
            $this->debug($request_headers, false);
            $this->debug("\n");
            $this->debug($response_headers, false);
            $this->debug($result);


            if ($result !== FALSE) {
                return json_decode($result, true);
            }
            return false;
        } else {
            $this->debug("You need cURL to use this API Library");
        }
        return FALSE;
    }

    /**
     *   This performs an HLR request and gives you the result via an HTTP callback
     *
     *   @global string $username
     *   @global string $password
     *   @param string $number
     *   @param string $report_url: This is the URL you want to be called with the resulting information
     */
    function hlr_perform($number, $report_url)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   This performs an HLR request and gives you the result immediately.
     *
     *   @global string $username
     *   @global string $password
     *   @param string $number
     */
    function hlr_perform_synchronous($number)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   This performs an MNP request and gives you the result immediately.
     *
     *   @global string $username
     *   @global string $password
     *   @param string $number
     */
    function mnp_perform($number)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   This function returns all inbound (MO) messages for the user which have an ID larger than 'last_id'.
     *
     *   @global string $username
     *   @global string $password
     *   @param int $last_id
     */
    function messages_get($last_id)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Statistics for the user account.
     *
     *   @global string $username
     *   @global string $password
     *   @param string user_id (optional): the sub user id that these statistics are for
     *   @param string start_date (optional): start point of the statistics
     *   @param string end_date (optional): end point of the statistics
     */
    function messages_statistics($user_id = null, $start_date = null, $end_date = null)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Send an SMS message
     *
     *   @global string $username
     *   @global string $password
     *   @param string $to
     *   @param string $text: The body of your message
     *   @param string $from (optional): The expeditor's label
     *   @param int $report_mask (optional): Delivery report request bitmask
     *   @param string $report_url (optional): URL to call when delivery status changes
     *   @param string $charset (optional): Character set to use
     *   @param int $data_coding (optional): Data coding
     *   @param int $message_class (optional): Message class
     *   @param int $auto_detect_encoding (optional): Auto detect the encoding and send appropriately 1 = on, 0 = off.
     *   @param string/boolean $short (optional): 1. "string" Add sort url at the end of message or search for key {short} in message and replace with short url when parameter contain URL
     *                                            2. "boolean" Searches long url and replaces them with coresponding sort url when shrot parameter is "true"
     */
    function message_send($to, $text, $from = null, $report_mask = 19, $report_url = null, $charset = null, $data_coding = null, $message_class = -1, $auto_detect_encoding = null, $short = false)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Send an SMS message with and gdpr link
     *
     *   @global string $username
     *   @global string $password
     *   @param string $to
     *   @param string $text: The body of your message
     *   @param string $from (optional): The expeditor's label
     *   @param int $report_mask (optional): Delivery report request bitmask
     *   @param string $report_url (optional): URL to call when delivery status changes
     *   @param string $charset (optional): Character set to use
     *   @param int $data_coding (optional): Data coding
     *   @param int $message_class (optional): Message class
     *   @param int $auto_detect_encoding (optional): Auto detect the encoding and send appropriately 1 = on, 0 = off.
     *   @param string/boolean $short (optional): 1. "string" Add sort url at the end of message or search for key {short} in message and replace with short url when parameter contain URL
     *                                            2. "boolean" Searches long url and replaces them with coresponding sort url when shrot parameter is "true"
     */
    function message_send_gdpr($to, $text, $from = null, $report_mask = 19, $report_url = null, $charset = null, $data_coding = null, $message_class = -1, $auto_detect_encoding = null, $short = false)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Checks the status of a message
     *
     *   @global string $username
     *   @global string $password
     *   @param string $message_id: The ID of the message
     */
    function message_status($message_id)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Function to ensure communication
     */
    function ping()
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args, false);
    }

    /**
     *   This action allows you to check the price you can expect to pay for a message to the destination in 'to'
     *
     *   @global string $username
     *   @global string $password
     *   @param string $to: A phone number
     */
    function route_check_price($to)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   This action allows a third party application to get an authentication key in order to make use of a user's account.
     *
     *   @param string $application_name: The name of the application to be authorized
     */
    function user_authorize_application($application_name)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args, false);
    }

    /**
     *   Get the API Key
     *
     *   @param string request_key: The original request key returned from user_authorize_application()
     */
    function user_get_api_key($request_key)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args, false);
    }

    /**
     *   Gets the user balance
     *
     *   @global string $username
     *   @global string $password
     */
    function user_get_balance()
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Gets the user details
     *
     *   @global string $username
     *   @global string $password
     */
    function user_get_info()
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   This function returns the verified phone number for the given user
     *
     *   @global string $username
     *   @global string $password
     */
    function user_get_phone_number()
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Transfer credit from one account to another
     *
     *   @global string $username
     *   @global string $password
     *   @param string target_username: The username to move funds to (this must be a sub-user of your account)
     *   @param float amount: The amount to transfer
     */
    function user_transfer_funds($target_username, $amount)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Add a new IP to the API Key whitelist
     *  
     *   @global string $username
     *   @global string $password
     *   @param string $ipaddr: The IP to whitelist
     */
    function token_add_ip($ipaddr)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   List all whitelisted IPs of the API Key
     *  
     *   @global string $username
     *   @global string $password
     */
    function token_list_ips()
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    /**
     *   Authorization of the key generated by user_authorize_application
     *  
     *   @global string $username
     *   @global string $password
     *   @param string $request_key: The key returned by user_authorize_application
     */
    function user_allow_token_request($request_key)
    {
        $args = func_get_args();
        return $this->call_api_action(new ReflectionMethod(__CLASS__, __FUNCTION__), $args);
    }

    function performActionsImmediately($state)
    {
        $this->performActionsImmediately = $state;
    }

    function getError()
    {
        return $this->error;
    }
    
    function ok($result)
    {
        if (is_array($result)) {
            if (array_key_exists('status', $result)) {
                if ($result['status'] >= 0) {
                    return TRUE;
                }
                $this->error = $result['message'];
            }
        } else {
            if ($result === TRUE) {
                $this->error = "Command queued";
                return TRUE;
            }
            $this->error = "Error communicating with API";
        }
        return FALSE;
    }

    function debug($str)
    {
        if ($this->$debugState) {
            error_log('SendSMS: ' . $str);
        }
    }

    function setDebugState($state)
    {
        $this->debugState = $state;
    }
}