<?php

require_once 'i24h_settings.php';

class I24hSession
{
    const I24H_ID_URL               = 'v2/access?vendor_id=2&device_id=%s&stream=orig&_format=json';
    const I24H_OTPS_URL             = 'v2/otps';
    const I24H_OTPS_AUTH_URL        = 'v2/auth/otp';
    const I24H_USER_LOGIN           = 'v2/auth/login';
    const I24H_LOGOUT_URL           = 'v2/users/self/devices/';
    const I24H_USER                 = 'v2/users';
    const I24H_USER_DEVICE          = 'v2/users/self/devices?access_token=%s';
    const I24H_USER_SELF            = 'v2/users/self?access_token=%s';
    const I24H_SELF_NETWORK         = 'v2/users/self/network?access_token=%s';
    const I24H_USER_SELF_NETWORK    = 'v2/users/self/network';
    const I24H_USER_SUBSCRIPTION    = 'v2/users/self/subscriptions/current?access_token=%s';
    const I24H_AUTH_DEVICE          = 'v2/auth/device';
    const I24H_DEVICE_LIST          = 'v2/users/self/devices?access_token=%s';
    const I24H_DELETE_DEVICE        = 'v2/users/self/devices/%s?access_token=%s';
    const I24H_GET_URL_URL          = 'http://ts://%s/dune/plugini.php?action=get_url&login=%s&pass=%s';
    const I24H_SERVICES_URL         = 'v2/packets?includes=channels,videos,availables&access_token=%s&format=json';
    const I24H_SERVICES_AV_URL      = 'v2/users/self/subscriptions/current?access_token=%s&format=json';
    const I24H_BALANCE_URL          = 'v2/users/self?access_token=%s&format=json';
    const I24H_ADD_SERVICE          = 'v2/users/self/subscriptions?access_token=%s&format=json';
    const I24H_PATCH_SERVICE        = 'v2/users/self/subscriptions/%s?access_token=%s&format=json';
    const I24H_DEL_SERVICE          = 'v2/users/self/subscriptions/%s?access_token=%s&format=json';
    const VIDEO_IN_PACKETS          = 'v2/packets?includes=videos&access_token=%s&format=json';
    const VIDEO_ALLOW               = 'v2/users/self/subscriptions/current?includes=packet.videos&access_token=%s&format=json';
    const VIDEO_SOURCE              = 'v2/videos/sources?access_token=%s&format=json';
    const VIDEO_SOURCE_IN_PACKETS   = 'v2/videos/sources/%s/packets?access_token=%s&format=json';

    private $http_opts      = null;
    private $sid_name       = null;
    private $sid            = null;
    private $sid_uid        = null;
    private $token          = null;
    private $mbr_id         = null;
    private $mbr_phone      = null;
    private $mbr_username   = null;
    private $parental_code  = null;
    private $ip_address     = null;
    private $support_phone  = null;
    private $support_email  = null;
    private $support_url    = null;
    private $provider_name  = null;
    private $provider_id    = null;
    private $terms          = null;
    private $proxy          = null;
    private $country        = null;
    private $city           = null;
    private $agreement      = null;
    private $provider_title = null;
    private $provider_desc  = null;
    private $has_tariffs    = null;
    private $current_packets        = null;
    private $channel_need_reloading = null;

    private $login_incorrect = false;

    private $account = null;
    private $services = null;
    private $settings = null;

    private $channel_list = null;
    private $unset_login_listener = null;
    private $service_list_cache = null;
    private $service_list = null;
    private $paysystems_list = null;
    private $videos_in_packets = null;
    private $current_videos = null;
    
    private $api_server = null;

    public function __construct($unset_login_listener)
    {
        $this->http_opts = array (
            CURLOPT_FOLLOWLOCATION  => true,
            CURLOPT_MAXREDIRS       => 10,
            CURLOPT_COOKIEFILE      => '/tmp/24h2.cookies',
            CURLOPT_COOKIEJAR       => '/tmp/24h2.cookies'
        );
        $this->unset_login_listener = $unset_login_listener;
    }
    
    public function get_http_opts(){return $this->http_opts;}
    public function get_sid(){return $this->sid;}
    public function get_sid_uid(){return $this->sid_uid;}
    public function get_token(){return $this->token;}
    public function get_channel_list(){return $this->channel_list;}
    public function get_account(){return $this->account;}
    public function get_settings(){return $this->settings;}
    public function set_api_server($proxy) {$this->api_server = $proxy;}
    public function is_login_incorrect(){return $this->login_incorrect; }
    public function is_logged_in(){return ($this->mbr_id>0); }
    public function get_ip_address(){return $this->ip_address;}
    public function get_phone(){return $this->mbr_phone;}
    public function get_username(){return $this->mbr_username;}
    public function get_support_url(){return $this->support_url;}
    public function get_support_phone(){return $this->support_phone;}
    public function get_support_email(){return $this->support_email;}
    public function get_terms(){return $this->terms;}
    public function get_agreement(){return $this->agreement;}
    public function get_parental_code(){return $this->parental_code;}
    public function get_has_tariffs(){return $this->has_tariffs;}
    public function get_provider_id(){return $this->provider_id;}
    public function get_provider_name(){return $this->provider_name;}
    public function get_provider_desc(){return $this->provider_desc;}
    public function get_plugin_version(){return I24HSettings::get_version();}

    public function get_api_server()
    {
        if (empty($this->api_server)) {
            $this->api_server = I24HSettings::$API_SERVER;
        }
        return $this->api_server;
    }


    public function get_current_packets(){

        if (empty($this->current_packets)) {

            $subcribers = $this->api_call(
                sprintf(
                    $this->get_api_server() . self::I24H_USER_SUBSCRIPTION, $this->get_token()), true);
            $this->has_tariffs = false;
            $this->current_packets = $subcribers;
            foreach ($subcribers as $s) {
                $this->has_tariffs = true;
            }
        }
        return $this->current_packets;
    }

    public function get_videos_in_packets()
    {
        if (empty($videos_in_packets)){
            $this->retriveVideosPackets();
        }
        return $this->videos_in_packets;
    }

    public function get_current_videos()
    {
        if (empty($this->current_videos)){
            $this->retriveCurrentVideos();
        }
        return $this->current_videos;
    }


    private function retriveVideosPackets()
    {
        unset($this->videos_in_packets);
        $sources = $this->api_call(sprintf($this->get_api_server() . self::VIDEO_SOURCE, $this->get_token()),true);
        foreach ($sources as $s){
            $packets = $this->api_call(sprintf($this->get_api_server() . self::VIDEO_SOURCE_IN_PACKETS, $s->id , $this->get_token()),true);
            foreach ($packets as $p) {
                $this->videos_in_packets[$s->id][] = $p->base?'"'.$p->name.'"':'доп. пакет "'.$p->name.'"';
            }
        }
    }

    private function retriveCurrentVideos()
    {
        $tariff = $this->api_call(
            sprintf(
                $this->get_api_server() . self::VIDEO_ALLOW, $this->get_token()), true);
        unset($this->current_videos);
        foreach ($tariff as $t) {
            foreach ($t->packet->videos as $v) {
                $this->current_videos[$v->id] = $v->title;
            }
        }
        //////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////
//        $this->current_videos[3] = "Megogo";
        //////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////
    }

    public function get_channel_need_reloading()
    {
        return $this->channel_need_reloading;
    }

    public function set_channel_need_reloading($flag){
        $this->channel_need_reloading = $flag;
    }

    public function set_mbr_phone($phone){
        $this->mbr_phone = $phone;
    }

    public function set_mbr_username($username){
        $this->mbr_username = $username;
    }

    public function set_token($token){
        $this->token = $token;
    }

    public function clear_http_ops(){
        unset($this->http_opts[CURLOPT_HTTPHEADER]);
        unset($this->http_opts[CURLOPT_CUSTOMREQUEST]);
    }

    public function get_movie_need_reloading(){return $this->movie_need_reloading;}
    public function set_movie_need_reloading($flag){$this->movie_need_reloading = $flag;}

    public function set_parental_code($new_code)
    {
        try
        {
            $this->http_opts[CURLOPT_CUSTOMREQUEST] ='PATCH';
            $this->http_opts[CURLOPT_HTTPHEADER]    ='Content-Type: application/json';
            $doc = $this->api_call(
                sprintf(
                    $this->get_api_server() . self::I24H_USER_SELF,$this->token),true,
                array("pincode"=>$new_code));
            $this->parental_code = $new_code;

            unset($this->http_opts[CURLOPT_CUSTOMREQUEST]);
            unset($this->http_opts[CURLOPT_HTTPHEADER]);

            return true;
        }
        catch (Exception $e)
        {
            hd_print("Error code = ".$e->getCode());
            return false;
        }

    }

    public function get_device_list(){
        try
        {

            $doc = $this->api_call(
                sprintf(
                    $this->get_api_server() . self::I24H_DEVICE_LIST,$this->token),true);
            return $doc;
        }
        catch (Exception $e)
        {
            hd_print("Error code = ".$e->getCode());
            return false;

        }
    }

    public function unset_login()
    {
        $this->logged_in = false;
        $this->sid_name = null;
        $this->sid = null;
        $this->account = null;
        $this->services = null;
        $this->settings = null;
        $this->channel_list = null;
        $this->token = null;
        $this->mbr_id = null;
        unset($this->service_list);
        unset($this->service_list_cache);
        unset($this->videos_in_packets);
        unset($this->current_videos);
        unset($this->current_packets);
    }

    public function logout(&$plugin_cookies)
    {
    	if (isset($this->token)) {
    	    try
    	    {
                $this->delete_device($this->get_device_id($plugin_cookies));
                $this->http_opts[CURLOPT_HTTPHEADER]    = 'Content-Type: application/json';
    	        $this->http_opts[CURLOPT_CUSTOMREQUEST] = 'DELETE';
    	    	$doc = $this->api_call(sprintf($this->get_api_server() . self::I24H_LOGOUT_URL, $this->token));
                unset($this->http_opts[CURLOPT_HTTPHEADER]);
                unset($this->http_opts[CURLOPT_CUSTOMREQUEST]);
                $plugin_cookies->device_id = '';
    	    }
    	    catch (Exception $e)
    	    {
    	    	throw $this->dune_api_exception($e,
    	    	    'Stream url request failed.',
    	    	    true);
    	    }
    	    unset($this->token);
    	}
        unset($this->service_list);
        unset($this->service_list_cache);
        unset($this->videos_in_packets);
        unset($this->current_videos);
        unset($this->current_packets);
        $this->unset_login_listener->unset_login();
    }

    public function delete_device($device_id){
        if (isset($this->token)) {
            try
            {
                $this->http_opts[CURLOPT_HTTPHEADER]    = array('Content-Type: application/json');
                $this->http_opts[CURLOPT_CUSTOMREQUEST] = 'DELETE';
                $doc = $this->api_call(sprintf($this->get_api_server() . self::I24H_DELETE_DEVICE, $device_id, $this->token));
                unset($this->http_opts[CURLOPT_HTTPHEADER]);
                unset($this->http_opts[CURLOPT_CUSTOMREQUEST]);
                return true;
            }
            catch (Exception $e)
            {
                throw $this->dune_api_exception($e,
                    'Stream url request failed.',
                    true);
            }
            unset($this->token);
        }else{
            return true;
        }
    }


    private function fetch_document($url)
    {
        $doc = HD::http_get_document($url, $this->http_opts);
        return $doc;
    }

    private function fetch_post_document($url, $data)
    {
        $doc = HD::http_post_document($url, $data, $this->http_opts);
        return $doc;
    }

    public function api_call($url, $silent=true, $data=null)
    {
//        $silent=false;
        for (;;)
        {
            if (!$silent) hd_print("api_call: $url");
            if (isset($data)) {
                if (!$silent) hd_print("POST data: ".print_r($data,true));
            	$str = $this->fetch_post_document($url, $data);
            } else {
            	$str = $this->fetch_document($url);
            }

            if (!$silent) hd_print("Document:\n$str\n");

            $reply = json_decode($str);

            if (!$silent) hd_print("Reply from server:".print_r($reply,true));

            if ($reply === null)
                throw new Exception('Invalid data received from server');


            if (!empty($reply->status_code)&&($reply->status_code != 200)&&($reply->status_code != 400)&&($reply->status_code != 401)&&($reply->status_code != 403)) {

                if (!$silent) hd_print("PRINT REPLY: ".print_r($reply,true));

                throw new Exception($reply->detail);
            }
            break;
        }

        return $reply;
    }

    public function dune_api_exception($e, $def_caption, $is_playback)
    {
        $is_i24h_error = ($e instanceof I24hException);
        if (!$is_i24h_error)
        {
            $title = !$is_playback ? 'Error' :
                'Failed to connect to Internet.';
            $text_lines = $is_playback ? array() :
                array(
                 'Failed to connect to Internet.',
                 'Please check Internet connection.'
                );
            return new DuneException(
                $def_caption, -1,
                ActionFactory::show_error(false, $title, $text_lines));
        }

        $ecode = $e->getCode();
        $fatal = 
            $ecode == 11 || $ecode == 12 || $ecode == 13;

//        if ($fatal)
//            $this->logout();

        if ($ecode == 2)
        {
            $this->login_incorrect = true;

            $title = !$is_playback ? 'Ошибка' :
                'Неправильные данные подписки, проверьте номер и пароль.';
            $text_lines = $is_playback ? array() :
                array('Неправильные данные подписки, проверьте номер и пароль.');
            return new DuneException(
                $def_caption, $ecode,
                ActionFactory::show_error($fatal, $title, $text_lines));
        }

        if ($ecode == 4)
        {
            $title = !$is_playback ? 'Ошибка' :
                'Подписка истекла. Зайдите на 24h.tv и пополните счет для ее продления.';
            $text_lines = $is_playback ? array() :
                array('Подписка истекла. Зайдите на 24h.tv и пополните счет для ее продления.');
            return new DuneException(
                $def_caption, $ecode,
                ActionFactory::show_error($fatal, $title, $text_lines));
        }

        if ($ecode == 5)
        {
            $title = !$is_playback ? 'Ошибка' :
                'Неправильный телефонный номер. Используейте формат 79XXXXXXXXX (11 цифр).';
            $text_lines = $is_playback ? array() :
                array('Неправильный телефонный номер. Используейте формат 79XXXXXXXXX (11 цифр).');
            return new DuneException(
                $def_caption, $ecode,
                ActionFactory::show_error($fatal, $title, $text_lines));
        }
        
        if ($ecode == 6)
        {
            $title = !$is_playback ? 'Ошибка' :
                'Слишком много запросов. Попробуйте попозже.';
            $text_lines = $is_playback ? array() :
                array('Слишком много запросов. Попробуйте попозже.');
            return new DuneException(
                $def_caption, $ecode,
                ActionFactory::show_error($fatal, $title, $text_lines));
        }

        if ($ecode == 20)
        {
            $title = !$is_playback ? 'Ошибка' :
                $e->getMessage();
            $text_lines = $is_playback ? array() :
                array($e->getMessage());
            return new DuneException(
                $def_caption, $ecode,
                ActionFactory::show_error($fatal, $title, $text_lines));
        }

        if ($ecode == 19)
        {
            $title = !$is_playback ? 'Error' :
                'Current code is wrong.';
            $text_lines = $is_playback ? array() :
                array('Current code is wrong.');
            return new DuneException(
                $def_caption, $ecode,
                ActionFactory::show_error($fatal, $title, $text_lines));
        }

        $title = !$is_playback ? 'Ошибка' : $e->getMessage();
        $text_lines = $is_playback ? array() :
            array(rtrim($e->getMessage()),
                'Error code: ' . $ecode);
        return new DuneException(
            $def_caption, $ecode,
            ActionFactory::show_error($fatal, $title, $text_lines));
    }
    
    public function get_device_serial_id() {
    	$h = fopen('/fconfig/dune_license.dlf', "r");
    	$l = fgets($h);
    	fclose($h);
    	preg_match('/\d+ \d+ (\S+) /', $l, $matches);
    	return preg_replace('/-/','',$matches[1]);
    }

    public function get_device_id(&$plugin_cookies) {
        if (!empty($plugin_cookies->device_id)) {
            return $plugin_cookies->device_id;
        }else{
            return $this->get_device_serial_id();
        }
    }

    public function set_device_id(&$plugin_cookies, $device_id='') {
        $plugin_cookies->device_id = $device_id;
        return true;
    }



    public function verify_device(&$plugin_cookies) {

    	$device_id = $this->get_device_id($plugin_cookies);
        $this->get_self_network();
    	
    	if ($device_id) {
    	    $doc = "";
    	    try
    	    {
    	    	$doc = $this->api_call(
    	    	    sprintf(
    	    	    	$this->get_api_server() . self::I24H_AUTH_DEVICE),true,
    	    	    	array('device_id'=>$device_id));
    	    }
    	    catch (Exception $e)
    	    {
    	        hd_print("Error code = ".$e->getCode());
    	        hd_print("DOC: ".print_r($doc,true));
    	    }
//            hd_print("Status code = ".$doc->status_code);
            if (!empty($doc->status_code)){
                $this->token = "";
            }else{
                $this->token = $doc->access_token;
                $this->sid_name = 'sid';
                $user = $this->api_call(
                    sprintf(
                        $this->get_api_server() . self::I24H_USER_SELF, $doc->access_token),true);
                $this->mbr_id = $user->id;
                $this->mbr_phone = $user->phone;

                $username = $user->username;

                if (!empty(I24HSettings::$USERNAME_PREFIX)){
                    $username = preg_replace("/^" . I24HSettings::$USERNAME_PREFIX."/", "", $username);
                    if (!empty($this->provider_id)){
                        $username = preg_replace("/^" . $this->provider_id . "_/", "", $username);
                    }
                }
//                $this->mbr_username = $user->username;
                $this->set_mbr_username($username);
                $this->parental_code = $user->parental_code;
                if (!empty($user->provider->name)) {
                    $this->provider_name = $user->provider->name;
                }else{
                    $this->provider_name = "";
                }
                $this->channel_need_reloading = true;
                $this->movie_need_reloading = true;
                $this->get_current_packets();
            }

            unset($this->service_list);
            unset($this->service_list_cache);
            unset($this->videos_in_packets);
            unset($this->current_videos);
            unset($this->current_packets);

    	}
    }

    public function api_get_stream_url($playback_url)
    {
        $this->check_logged_in();

        if (substr($playback_url, 0, 12) === 'http://ts://')
            $playback_url = 'http://' . substr($playback_url, 12);
        else if (substr($playback_url, 0, 13) === 'http://mp4://')
            $playback_url = 'http://' . substr($playback_url, 13);

        try
        {
            $doc = $this->api_call($playback_url);
        }
        catch (Exception $e)
        {
            throw $this->dune_api_exception($e,
                'Stream url request failed.',
                true);
        }

        if (!isset($doc->url))
            throw new Exception('Get_url failed.');

        $len = strlen($doc->url);
        $pos = $len;
        for ($i = 10; $i < $len; $i++)
        {
            if ($doc->url[$i] == '"' || $doc->url[$i] == ' ')
            {
                $pos = $i;
                break;
            }
        }

        $url = substr($doc->url, 0, $pos);

        if (substr($url, 0, 10) === 'http/ts://')
            return 'http://' . substr($url, 10);

        return $url;
    }

    private function api_login(&$plugin_cookies, $user_name, $password)
    {
        $device_id = $this->get_device_id($plugin_cookies);
//        hd_print("Trying to login, device id ".$device_id);
        try
        {

            $doc = $this->api_call(
                sprintf(
                    $this->get_api_server() . self::I24H_OTPS_AUTH_URL), true,
                     array('phone' => preg_replace('/^8/', '7', $user_name), 'token' => $password));
//            hd_print("Response ".$doc->status_code." ".$doc->access_token);
            $this->token=$doc->access_token;

        }
        catch (Exception $e)
        {
            throw $this->dune_api_exception($e, 'Ошибка авторизации!.', false);
        }
        if (!empty($doc->status_code)) {
            throw $this->dune_api_exception(new I24hException($doc->message, 12), $doc_message, false);
        }

    }

    public function try_login(&$plugin_cookies)
    {
        if (!isset($plugin_cookies->user_name))
            throw new Exception('Не указан номер телефона!');

        try
        {
            $this->verify_device($plugin_cookies);
            $this->api_login($plugin_cookies,
                $plugin_cookies->user_name,
                $plugin_cookies->password);

           $this->verify_device($plugin_cookies);
           unset($this->service_list);
           unset($this->service_list_cache);
           unset($this->videos_in_packets);
           unset($this->current_videos);

        }
        catch (Exception $e)
        {
            $this->logout($plugin_cookies);
            throw $e;
        }
    }

    public function ensure_logged_in(&$plugin_cookies)
    {
        if ($this->mbr_id)
            return;

        $this->verify_device($plugin_cookies);
        
        if (!$this->mbr_id) {
            throw $this->dune_api_exception(new I24hException('Вы не вошли в систему. Зайдите в настройки и укажите свой пароль.', 12), 12, false);
        }
    }

    public function check_logged_in()
    {
        if (!$this->mbr_id)
            throw new I24hException('Вы не вошли в систему. Зайдите в настройки и укажите свой пароль.', 12);
    }

    private function do_get_edit_subscription_defs(&$plugin_cookies, $handler, $add_params){
        return I24HSettings::get_login_defs($this,$handler, $add_params);
    }


    public function show_information_before_login(&$plugin_cookies, $handler, $add_params = null){

        $defs = array();
        $doc = $this->provider_desc;
        ControlFactory::add_multiline_label($defs, '', 'Управление: "P+" - пролистать вверх, "P-" - пролистать вниз.'."\n\n".$doc, 16);
//        ControlFactory::add_close_dialog_and_apply_button($defs,
//            $handler, array(),
//            'go_to_get_registration_form', 'Далее', 300);


        ControlFactory::add_button($defs,
            $handler, $add_params,
            'go_to_get_registration_form', ' ', 'Далее', 500);

//        ControlFactory::add_close_dialog_and_apply_button($defs,
//            $handler, array(),
//            'go_to_get_registration_form', 'Далее', 500);
//        $pin_apply = UserInputHandlerRegistry::create_action($handler, 'go_to_get_registration_form', array('action_type'=>'apply'));

//        ControlFactory::add_custom_close_dialog_and_apply_buffon($defs,'go_to_get_registration_form', 'Далее', 300, $pin_apply);
        $defs[] = array
        (
            GuiControlDef::name => 'close',
            GuiControlDef::title => '',
            GuiControlDef::kind => GUI_CONTROL_BUTTON,
            GuiControlDef::specific_def =>
                array
                (
                    GuiButtonDef::caption => 'Отмена',
                    GuiButtonDef::width => 500,
                    GuiButtonDef::push_action =>
                        ActionFactory::close_dialog(),
                ),
            GuiControlDef::params => null,
        );

        return ActionFactory::show_dialog($this->provider_title, $defs, true, 1800);


    }


    public function show_registration_form(
        &$plugin_cookies, $handler, $add_params = null)
    {

//        return $this->show_information_screen_before_login($plugin_cookies, $handler);
//        hd_print("provider_title = " . $this->provider_title);
        return ActionFactory::show_dialog(
            empty($this->provider_title) ? 'Подписка на ТВ' : $this->provider_title,
            $this->do_get_edit_subscription_defs(
                $plugin_cookies, $handler, $add_params),
            true, I24HSettings::$LOGIN_WINDOW_WIDTH);
    }


    public function apply_subscription(&$plugin_cookies, &$user_input,$handler)
    {
        $post_action = null;
        if (!isset($user_input->control_id) ||
            $user_input->control_id != 'apply_subscription')
        {
            return false;
        }

        if ($user_input->user_name === '')
        {
            return array(
                'need_close_dialog' => false,
                'action' =>
                    ActionFactory::show_error(false,
                        'Error',
                        array('Не указан номер телефона или код авторизации.')));
        }
        try
        {
//            hd_print("OTPS AUTH ".$user_input->user_name." ".$user_input->password);
            $doc = $this->api_call(
                sprintf(
                    $this->get_api_server() . self::I24H_OTPS_AUTH_URL), true,
                array('phone' => preg_replace('/^8/', '7', $user_input->user_name), 'token' => $user_input->password));

            if (!empty($doc->status_code)&&($doc->status_code == 403)){

                return array(
                    'need_close_dialog' => false,
                    'action' =>
                        ActionFactory::show_error(false,
                            'Ошибка',
                            array($doc->detail)));
            }
            if (empty($doc->access_token)){

                $defs = array();

                ControlFactory::add_label($defs,
                    null, 'Введите код высланный по SMS,',
                    array('indent' => 0));
                ControlFactory::add_vgap($defs, -20);
                ControlFactory::add_label($defs,
                    null, 'На номер +'.$user_input->user_name,
                    array('indent' => 0));
                ControlFactory::add_vgap($defs, 30);
                ControlFactory::add_text_field($defs,$handler,null,'password','Код авторизации','',true,true,false,true,300);
                ControlFactory::add_vgap($defs, 30);
                ControlFactory::add_close_dialog_and_apply_button($defs,$handler,array(),'apply_subscription','Ввести код повторно',300);

                return array(
                    'need_close_dialog' => true,
                    'action' =>
                        ActionFactory::show_dialog('Неверный код, попробуйте снова!',$defs,true));

            }else{
                $this->token = $doc->access_token;
                $post_action = ActionFactory::open_folder(MediaURL::encode(array('screen_id'=>I24hTopScreen::ID)),I24HSettings::$WINDOW_CAPTION);
                $post_action = ActionFactory::close_dialog_and_run($post_action);

            }

        }
        catch (Exception $e)
        {
            throw $this->dune_api_exception($e, 'Ошибка авторизации!.', false);
        }

        unset($this->http_opts[CURLOPT_HTTPHEADER]);
        unset($this->http_opts[CURLOPT_CUSTOMREQUEST]);

        $this->mbr_phone = $user_input->user_name;
        $plugin_cookies->user_name = $user_input->user_name;
        $plugin_cookies->password = $user_input->password;

        $reg_dev = $this->register_device($plugin_cookies);
        if ($reg_dev){return $reg_dev;}
/*        try
        {
//            $this->try_login($plugin_cookies);
        }
        catch (DuneException $e)
        {
            $post_action = $e->get_error_action();

            $plugin_cookies->password = '';
        }
*/
        return array(
            'need_close_dialog' => true,
            'action' => $post_action);
    }


    public function register_device(&$plugin_cookies)
    {
        $h = fopen('/tmp/run/versions.txt', "r");
        $fw = "";$pl = "";

        $file_handle = fopen("/tmp/run/versions.txt", "r");
        while (!feof($file_handle)) {
            $l = fgets($file_handle);
            if (preg_match('/firmware_version=(\S+)/', $l, $matches)){$fw = $matches[1];}
            if (preg_match('/product=(\S+)/', $l, $matches)){$pl = $matches[1];}

        }
        fclose($file_handle);

        unset($this->http_opts[CURLOPT_HTTPHEADER]);
        unset($this->http_opts[CURLOPT_CUSTOMREQUEST]);

        $doc = $this->api_call(sprintf($this->get_api_server() . self::I24H_USER_DEVICE, $this->token),true,array(
#            "id"=> $this->get_device_id(),
            "vendor"=>"DUNE",
            "model"=>empty($pl)?'dune':$pl,
            "version"=>$this->get_plugin_version(),
            "device_type"=>"stb",
            "serial"=>$this->get_device_serial_id()
        ));

        if ((!empty($doc->status_code))&&($doc->status_code == 400 && $doc->detail[0] == 'Too many devices.')) {
            $post_action = ActionFactory::open_folder(I24hDeviceListScreen::get_media_url_str(),I24HSettings::$WINDOW_CAPTION);
            $post_action = ActionFactory::close_dialog_and_run($post_action);
            return array(
                'need_close_dialog' => true,
                'action' => $post_action
            );
        }else{

            $this->set_device_id($plugin_cookies, $doc->id);
            return false;
        }

    }

    public function get_password(&$plugin_cookies, &$user_input, &$handler)
    {

        if (!isset($user_input->control_id)) {
            return false;
        }
        if ($user_input->control_id == 'get_password' || $user_input->control_id == 'get_sms') {
            return I24HSettings::get_password($this,$plugin_cookies, $user_input, $handler);
        } else if ($user_input->control_id == 'reg_show_agreement') {
            return $this->show_user_agreement($plugin_cookies, $user_input, $handler);
        } else if ($user_input->control_id == 'do_login_user_by_username') {
                return I24HSettings::get_password($this,$plugin_cookies, $user_input, $handler);
        }
        return false;
    }

   public function show_user_agreement(&$plugin_cookies, &$user_input, &$handler){

        if(!preg_match('/^7[0-9]{10}$/', $user_input->user_name))
        {
            return array(
                'need_close_dialog' => false,
                'action' =>
                    ActionFactory::show_error(false,
                        'Неверный формат телефона!',
                        array('Используйте формат 7ХXXXXXXXXX')));
        }

        $this->get_self_network();

        $doc = HD::http_get_document($this->agreement);

        $defs = array();
        ControlFactory::add_multiline_label($defs, '', 'Управление: "P+" - пролистать вверх, "P-" - пролистать вниз.'."\n\n".$doc, 16);
        ControlFactory::add_close_dialog_button($defs, 'Назад', 300);
        ControlFactory::add_close_dialog_and_apply_button($defs,
            $handler, array(),
            'get_sms', 'Принять', 300);

        return array(
            'need_close_dialog' => false,
            'action' =>
                ActionFactory::show_dialog('Пользовательское соглашение.', $defs, true, 1800));
    }


    public function get_self_network()
    {
        $network = $this->api_call(
            sprintf(
                $this->get_api_server() . self::I24H_USER_SELF_NETWORK), true);

//        hd_print('get_self_network()');
//        hd_print(print_r($network, true));

        $this->ip_address    = empty($network->remote)?'':$network->remote;

        $support_phone = '';
        if (!empty($network->provider->landing->support->phone)){
            $support_phone = $network->provider->landing->support->phone;
        }else{
            if (!empty($network->default->support->phone)){
                $support_phone = $network->default->support->phone;
            }
        }
        $this->support_phone = $support_phone;

        $support_email = '';
        if (!empty($network->provider->landing->support->email)){
            $support_email = $network->provider->landing->support->email;
        }else{
            if (!empty($network->default->support->email)){
                $support_email = $network->default->support->email;
            }
        }
        $this->support_email = $support_email;

        $support_url = '';
        if (!empty($network->provider->landing->support->url)){
            $support_url = $network->provider->landing->support->url;
        }else{
            if (!empty($network->default->support->url)){
                $support_url = $network->default->support->url;
            }
        }
        $this->support_url = $support_url;

        $provider_title = '';
        if (!empty($network->provider->landing->login->title)){
            $provider_title = $network->provider->landing->login->title;
        }else{
            if (!empty($network->default->login->title)){
                $provider_title = $network->default->login->title;
            }
        }
        $this->provider_title = $provider_title;

        $provider_description = '';
        if (!empty($network->provider->landing->login->description)){
            $provider_description = $network->provider->landing->login->description;
        }else{
            if (!empty($network->default->login->description)){
                $provider_description = $network->default->login->description;
            }
        }
        $this->provider_desc = $provider_description;

//        $this->support_phone = empty($network->default->support->phone)?'':$network->default->support->phone;
//        $this->support_email = empty($network->default->support->email)?'':$network->default->support->email;
//        $this->support_url   = empty($network->default->support->url)?'':$network->default->support->url;
//        $this->provider_title= empty($network->default->login->title)?'':$network->default->login->title;
//        $this->provider_desc = empty($network->default->login->description)?'':$network->default->login->description;

        $this->terms         = empty($network->terms)?'':$network->terms;
        $this->agreement     = empty($network->agreement)?'':$network->agreement;

        $this->provider_id   = empty($network->provider->id)?'':$network->provider->id;
        $this->provider_name = empty($network->provider->name)?'':$network->provider->name;
        $this->country       = empty($network->country)?'':$network->country;
        $this->city          = empty($network->city)?'':$network->city;
        if (!empty($network->provider->proxy)) $this->set_api_server($network->provider->proxy);

    }


    public function get_password_old(&$plugin_cookies, &$user_input)
    {
        if (!isset($user_input->control_id) ||
            $user_input->control_id != 'get_password')
        {
            return false;
        }

        if ($user_input->user_name === '')
        {
            return array(
                'need_close_dialog' => false,
                'action' =>
                    ActionFactory::show_error(false,
                        'Запрос пароля',
                        array('Введите номер телефона для отправки пароля.')));
        }

        try
        {
            $doc = $this->api_call(sprintf($this->get_api_server() . self::I24H_SEND_PWD_URL, preg_replace('/^8/', '7', $user_input->user_name), $this->get_device_id($plugin_cookies)));
        }
        catch (Exception $e)
        {
            throw $this->dune_api_exception($e,
                'Stream url request failed.',
                true);
        }

        return array(
                'need_close_dialog' => false,
                'action' =>
                ActionFactory::show_error(false,
                        'Запрос пароля',
                        array('На указанный номер отправлено SMS с паролем.',
                        	'Дождитесь сообщение, введите пароль и нажмите "Войти". '.$doc->message)));
    }

    public function retrieveURL($channel_id)
    {
        try
        {
            $doc = $this->api_call(sprintf($this->get_api_server() . self::I24H_GET_URL, $this->token, $channel_id));
        }
        catch (Exception $e)
        {
            throw $this->dune_api_exception($e,
                'Stream url request failed.',
                true);
        }

        return $doc;
    }
    
    public function retrieveTimeURL($tm, $channel_id)
    {
        try
        {
            $doc = $this->api_call(sprintf($this->get_api_server() . self::I24H_GET_TIME_URL, $this->token, $tm, $channel_id));
        }
        catch (Exception $e)
        {
            throw $this->dune_api_exception($e,
                'Stream url request failed.',
                true);
        }

        return $doc;
    }
    
    private function retrieveServiceList()
    {
        try
        {
            $doc = $this->api_call(sprintf($this->get_api_server() . self::I24H_SERVICES_URL, $this->token),true);
        }
        catch (Exception $e)
        {
            throw $this->dune_api_exception($e,
                'Stream url request failed.',
                true);
        }

        return $doc;
    }

    private function retrieveInvoicesList()
    {
        try
        {
            $doc = $this->api_call(sprintf($this->get_api_server() . self::I24H_SERVICES_AV_URL, $this->token),true);
        }
        catch (Exception $e)
        {
            throw $this->dune_api_exception($e,
                'Invoices url request failed.',
                true);
        }

        return $doc;
    }

    private function retrievePaysystemsList()
    {
        try
        {
            $doc = $this->api_call(sprintf($this->get_api_server() . self::I24H_PAYSYSTEMS_URL, $this->token));
        }
        catch (Exception $e)
        {
            throw $this->dune_api_exception($e,
                'Paysystems url request failed.',
                true);
        }

        return $doc;
    }

    private function updateInvoices()    
    {
        if (is_null($this->service_list_cache))
            $this->loadServiceList();
        
        $this->service_list = $this->service_list_cache;
        
        $invoices = $this->retrieveInvoicesList();
        $inv_arr = array();
        
        foreach ($invoices as $inv)
        {
            $inv_arr[$inv->id] = $inv;
        }
        
        foreach ($this->service_list as $srv)
        {
            if (isset($inv_arr[$srv->id])) {
                $srv->isSubscribed = 1;
				if (!($inv_arr[$srv->id]->repeated)) {
					$srv->finished = $inv_arr[$srv->id]->finish;
				}
				if ($inv_arr[$srv->id]->status == 7) {
					$srv->starts = $inv_arr[$srv->id]->start;
				}
            } else { 
            	$srv->isSubscribed = 0;
            }
        }
        
    }

    private function loadServiceList()
    {
        $this->service_list_cache = $this->retrieveServiceList();

        if (is_null($this->service_list_cache))
            throw new Exception("Can not retrieve service list");
    }
    
    private function loadPaysystemsList()
    {
        $this->paysystems_list = $this->retrievePaysystemsList();
        
        if (is_null($this->paysystems_list))
            throw new Exception("Can not retrieve service list");
        
    }
    
    public function getServiceList()
    {
        if (empty($this->service_list_cache))
            $this->loadServiceList();
        
        $this->updateInvoices();

        return $this->service_list;
    }

    public function getPaysystemsList()
    {
        if (is_null($this->paysystems_list))
            $this->loadPaysystemsList();
        
        return $this->paysystems_list;
    }

    public function getServiceById($service_id)
    {
        if (empty($this->service_list))
            $this->loadServiceList();

        $this->updateInvoices();

        foreach ($this->service_list as $srv)
        {
            if ($srv->id == $service_id)
                return $srv;
        }

        return null;
    }
    
    private function retrieveBalance()
    {
        try {
            $doc = $this->api_call(sprintf($this->get_api_server() . self::I24H_BALANCE_URL, $this->token));
        }
        catch (Exception $e)
        {
            throw $this->dune_api_exception($e,
                'Balance url request failed.',
                true);
        }
        if (!empty($doc->sources)) {
            $balance = 0;
            foreach ($doc->sources as $sources) {
                if (!empty($sources->amount)) {
                    $balance += $sources->amount;
                }
            }
        }else{
            $balance = '';
        }
        return $balance;
    }
    
    public function getBalance()
    {
        $balance = $this->retrieveBalance();

        if (is_null($balance))
            throw new Exception("Can not retrieve balance.");

        return $balance;
    }
    
    public function addServiceToSubscription($service_id)
    {
        $this->http_opts[CURLOPT_HTTPHEADER]    = array('Content-Type: application/json');
        $packet = json_encode(array(array('packet_id'=>$service_id,'renew'=>'true')));
        try {
            $doc = $this->api_call(sprintf($this->get_api_server() . self::I24H_ADD_SERVICE, $this->token),true,
                $packet
                );
        }
        catch (Exception $e)
        {
            throw $this->dune_api_exception($e,
                'request add service failed.',
                true);
        }

        unset($this->http_opts[CURLOPT_HTTPHEADER]);
        unset($this->service_list);
        unset($this->service_list_cache);
        unset($this->videos_in_packets);
        unset($this->current_videos);
        unset($this->current_packets);
        return $doc;
    }

    public function removeServiceFromSubscription($service_id)
    {

#        hd_print("service_id = ".$service_id." TOKEN = ".$this->token." url ".sprintf($this->get_api_server() . self::I24H_DEL_SERVICE,$service_id, $this->token));
        try {
            $this->http_opts[CURLOPT_CUSTOMREQUEST] ='DELETE';
            $this->http_opts[CURLOPT_HTTPHEADER]    = array('Content-Type: application/json');
            $doc = $this->api_call(sprintf($this->get_api_server() . self::I24H_DEL_SERVICE, $service_id, $this->token), true);
            unset($this->http_opts[CURLOPT_CUSTOMREQUEST]);
        }
        catch (Exception $e)
        {
            throw $this->dune_api_exception($e,
                'request delete service failed.',
                true);
        }

//        unset($this->service_list);
//        unset($this->service_list_cache);
//        unset($this->videos_in_packets);
//        unset($this->current_videos);
//        unset($this->current_packets);
        return true;
    }

    public function patchServiceToSubscription($service_id,$renew = false)
    {
        unset($this->current_packets);
        try
        {
            $this->http_opts[CURLOPT_CUSTOMREQUEST] ='PATCH';
            $this->http_opts[CURLOPT_HTTPHEADER]    =array('Content-Type: application/json');
            $doc = $this->api_call(
                sprintf(
                    $this->get_api_server() . self::I24H_PATCH_SERVICE,$service_id,$this->token),true,
                array("renew"=> empty($renew)?"false":"true"));

            unset($this->http_opts[CURLOPT_CUSTOMREQUEST]);
            unset($this->http_opts[CURLOPT_CUSTOMREQUEST]);
        }
        catch (Exception $e)
        {
            hd_print("Error code = ".$e->getCode());
            return false;
        }
    }



}
