<?php

class AMVG_search_videos{

    private $params,
            $errors,
            $feed_url,
            $feed_infos,
            $videos,
            $wp_version;

    function __construct( $params ){

        global $wp_version;

        $this->wp_version   = $wp_version;
        $this->params       = $params;

        //connecting to API
        $api_params = array(
            'license_key'   => WPSCORE()->get_license_key(),
            'signature'     => WPSCORE()->get_client_signature(),
            'server_addr'   => WPSCORE()->get_server_addr(),
            'server_name'   => WPSCORE()->get_server_name(),
            'core_version'  => WPSCORE_VERSION,
            'time'          => ceil( time() / 1000 ),
            'partner_id'    => $this->params['partner']['id']
        );

        $args = array(
            'timeout'   => 50,
            'sslverify' => false
        );

        $base64_params = base64_encode( serialize($api_params) );

        $response = wp_remote_get( WPSCORE()->get_api_url( 'amvg/get_feed', $base64_params), $args );

        if ( !is_wp_error( $response ) && $response['headers']['content-type'] === 'application/json; charset=UTF-8' ) {

            $response_body = json_decode( wp_remote_retrieve_body( $response ) );

            if( $response_body === null ){
                WPSCORE()->write_log( 'error','Connection to API (get_feed) failed (null)', __FILE__, __LINE__ );
                return false;
            }elseif( 200 !== $response_body->data->status ) {
                WPSCORE()->write_log( 'error','Connection to API (get_feed) failed (status: <code>' . $response_body->data->status . '</code> message: <code>' . $response_body->message . '</code>)', __FILE__, __LINE__ );
                return false;
            }else{
                //success
                if( isset( $response_body->data->feed_infos ) ) {
                    $this->feed_infos = $response_body->data->feed_infos;
                    $this->feed_url   = $this->get_partner_feed_infos( $this->feed_infos->feed_url->data );
                    if( ! $this->feed_url ){
                        WPSCORE()->write_log( 'error','Connection to Partner\'s API failed (feed url: <code>' . $this->feed_url . '</code> partner id: <code>:' . $this->params['partner']['id'] . '</code>)' , __FILE__, __LINE__ );
                        return false;
                    }
                    switch( $this->params['partner']['data_type'] ){
                        //retrieving videos from native feed
                        case 'native':
                            return $this->retrieve_videos_from_native_feed();
                            break;

                        //retrieving videos from json feed
                        case 'json':
                            return $this->retrieve_videos_from_json_feed();
                            break;

                        //retrieving videos from xml feed
                        default:
                            return $this->retrieve_videos_from_xml_feed();
                            break;
                    }
                }else{
                    WPSCORE()->write_log( 'error','Connection to API (get_feed) failed (message: <code>' . $response_body->message . '</code>)', __FILE__, __LINE__ );
                }
            }
        }else{
            if( isset( $response->errors['http_request_failed'] ) ) {
                WPSCORE()->write_log( 'error','Connection to API (get_feed) failed (error: <code>' . json_encode( $response->errors ) . '</code>)', __FILE__, __LINE__ );
                return false;
            }
        }
        return false;
    }

    public function get_videos(){
        return $this->videos;
    }

    public function get_errors(){
        return $this->errors;
    }

    public function has_errors(){
        return ! empty( $this->errors );
    }

    private function retrieve_videos_from_native_feed(){

        $array_valid_videos         = array();
        $count_valid_feed_items     = 0;
        $current_page = $first_page = $first_page = $this->get_partner_feed_infos($this->feed_infos->feed_first_page->data);
        $end                        = false;
        $existing_ids               = $this->get_partner_existing_ids();
        $root_feed_url              = $this->feed_url;

        $paged = '';
        if( isset( $this->feed_infos->feed_paged ) ){
            $paged                  = $this->get_partner_feed_infos($this->feed_infos->feed_paged->data);
        }

        while( false === $end ){

            //XNXX
            if( $this->params['source'] == 'xnxx' ){
                $this->$feed_url = $root_feed_url . '/' . $current_page . '/';
            }

            //Youjizz
            if( $this->params['partner']['id'] == 'youjizz' ){
                $this->feed_url = $root_feed_url . '-' . $current_page . '.html';
            }

            if( $current_page > $first_page ){
                if( $this->params['partner']['id'] == 'youjizz' ){
                    $this->feed_url = $root_feed_url . '-' . $current_page . '.html';
                }else{
                    $this->feed_url = $root_feed_url . $paged . $current_page;
                }
            }

            $ch = curl_init();
            curl_setopt($ch, CURLOPT_HEADER, true);

            $custom_proxy = false;
            
            if( $this->params['partner']['id'] == 'porntube' ){

                $custom_proxy_ip    = xbox_get_field_value( 'amvg-options', 'proxy-ip' );
                $custom_proxy_port  = xbox_get_field_value( 'amvg-options', 'proxy-port' );

                if( ! empty($custom_proxy_ip) && ! empty( $custom_proxy_port) ){
                    $custom_proxy = true;
                    curl_setopt($ch, CURLOPT_PROXY, $custom_proxy_ip);
                    curl_setopt($ch, CURLOPT_PROXYPORT, $custom_proxy_port);
                }
                //curl_setopt($ch, CURLOPT_PROXY, '163.172.220.221');
                //curl_setopt($ch, CURLOPT_PROXYPORT, '8888');
            }


            curl_setopt($ch, CURLOPT_REFERER, trim($this->feed_url));
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_URL, trim($this->feed_url));
            curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8) AppleWebKit/535.6.2 (KHTML, like Gecko) Version/5.2 Safari/535.6.2');

            if( isset( $this->feed_infos->feed_cookies ) && count( $this->feed_infos->feed_cookies ) > 0 ){
                $cookies = $this->feed_infos->feed_cookies;
                $array_cookies = array();

                foreach ( (array) $cookies as $key => $value) {
                    $array_cookies[] = 'Cookie: ' . $key . '=' . $this->get_partner_feed_infos($value);
                }
                curl_setopt($ch, CURLOPT_HTTPHEADER, $array_cookies);
            }

            $html = str_get_html(curl_exec($ch));

            $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

            curl_close($ch);

            if( 200 != $httpcode ){
                switch( $httpcode ){
                    case 403:
                    case 0:
                        if( $custom_proxy ){
                            $this->errors = array( 'code' => 'CURL ERROR ' . $httpcode, 'message' => 'This Proxy (' . $custom_proxy_ip . ':' . $custom_proxy_port . ') might have been banned for this partner.', 'solution' => 'Please configure the Proxy options.' );
                             WPSCORE()->write_log( 'error','Connection to native site ('. $this->params['partner']['id'] . ') failed <code>CURL HTTP CODE: ' . $httpcode . '</code> with Proxy <code>' . $custom_proxy_ip . ':' . $custom_proxy_port . '</code>', __FILE__, __LINE__ );
                        }else{
                            $this->errors = array( 'code' => 'CURL ERROR ' . $httpcode, 'message' => 'Your Server IP might have been banned for this partner.', 'solution' => 'Please configure the Proxy options.' );
                            WPSCORE()->write_log( 'error','Connection to native site ('. $this->params['partner']['id'] . ') failed <code>CURL HTTP CODE: ' . $httpcode . '</code>', __FILE__, __LINE__ );
                        }
                        break;
                    default:
                        $this->errors = array( 'code' => 'CURL ERROR ' . $httpcode, 'message' => 'Do not panic!', 'solution' => 'Please contact the WP-Script dev team' );
                        WPSCORE()->write_log( 'error','Connection to native site ('. $this->params['partner']['id'] . ') failed <code>CURL HTTP CODE: ' . $httpcode . '</code>', __FILE__, __LINE__ );
                        break;
                    break;
                }
                return false;
            }else{

                $videos_blocks = $html->find( $this->get_partner_feed_infos( $this->feed_infos->feed_item_path->node ) );

                if( count( (array)$videos_blocks ) == 0 ){
                    $end = true;
                }else{

                    foreach( (array)$videos_blocks as $video_block ){

                        if( false === $end ){

                            $video_id = $this->find_native($video_block, 'feed_item_id');

                            //xnxx
                            if( $this->params['partner']['id'] == 'xnxx'){
                                preg_match("|id=\"pic_(.+)\" onload|U", $video_id, $matches);
                                $video_id = $matches[1];
                            }

                            //xvideos
                            if( $this->params['partner']['id'] == 'xvideos' ){
                                preg_match("|id=\"pic_(.+)\" onload|U", $video_id, $matches);
                                $video_id = $matches[1];
                            }

                            //youjizz
                            if( $this->params['partner']['id'] == 'youjizz' ){
                                preg_match("|-([0-9]+)\.html|U", $video_id, $matches);
                                $video_id = $matches[1];
                            }

                            if( $video_id != false && !in_array( $video_id, (array) $existing_ids ) ){

                                $feed_item = new AMVG_Native_Item( $video_block );

                                $feed_item->init( $this->params, $this->feed_infos );
                                if( $feed_item->is_valid() ){
                                    $array_valid_videos[] = (array) $feed_item->get_data_for_json($count_valid_feed_items);
                                    ++$count_valid_feed_items;
                                }
                                if( $count_valid_feed_items >= $this->params['limit'] ){
                                    $end = true;
                                }
                            }
                        }

                        $video_block->clear();
                        unset($video_block);
                    }
                    ++$current_page;
                }
                $html->clear();
                unset($html);
            }
        }//endif
        $this->videos = $array_valid_videos;
        return true;
    }

    private function retrieve_videos_from_json_feed(){

        $existing_ids               = $this->get_partner_existing_ids();
        $array_valid_videos         = array();
        $count_valid_feed_items     = 0;
        $end                        = false;

        $args = array(
            'timeout'       => 300,
            'sslverify'     => false,
            'user-agent'    => 'WordPress/' . $this->wp_version . '; ' . home_url(),
        );

        if( isset( $this->feed_infos->feed_auth ) ){
            $args['headers'] = array('Authorization' => $this->get_partner_feed_infos( $this->feed_infos->feed_auth->data));
        }

        $response  = wp_remote_get( $this->feed_url, $args );

        if ( is_wp_error( $response ) ) {
            WPSCORE()->write_log( 'error','Retrieving videos from JSON feed failed <code>PARTNER: ' . $this->params['partner']['name'] . '</code> <code>ERROR: ' . json_encode( $response->errors ) . '</code>', __FILE__, __LINE__ );
            return false;
        }

        $response_body = json_decode( wp_remote_retrieve_body( $response ), true );

        //améliorer root selon paramètres / ou si null dans la config
        if( isset( $this->feed_infos->feed_item_path->node ) ){
            $root       = $this->feed_infos->feed_item_path->node;
            $array_feed = $response_body[$root];
        }else{
            $root       = 0;
            $array_feed = $response_body;
        }

        $sub_root       = '';
        $exploded_root  = explode( '/', $root );

        //subroot case
        if( count( $exploded_root ) >= 2 ){
            $root = reset( $exploded_root );
            $sub_root = end( $exploded_root );
            $sub_root_type = explode( ':', $sub_root );

            if( reset( $sub_root_type ) == 'single' ){
                $sub_root = end($sub_root_type);
            }
            $array_feed = $response_body[$root];
        }

        $count_total_feed_items = count( $array_feed );
        if( $count_total_feed_items < $this->params['limit'] ){
            $this->params['limit'] = $count_total_feed_items;
        }
        $current_item = 0;
        while( $end === false ){
            if( $sub_root != '' ){
                $feed_item = new AMVG_Json_Item( $array_feed[$current_item][$sub_root] );
            }else{
                $feed_item = new AMVG_Json_Item( $array_feed[$current_item] );
            }
            $feed_item->init( $this->params, $this->feed_infos );
            if( $feed_item->is_valid() && !in_array( $feed_item->get_id(), (array) $existing_ids ) ){
                $array_valid_videos[] = (array) $feed_item->get_data_for_json( $count_valid_feed_items );
                ++$count_valid_feed_items;
            }
            if( ( $count_valid_feed_items >= $this->params['limit'] ) || $current_item >= ( $count_total_feed_items - 1 ) ){
                $end = true;
            }
            ++$current_item;
        }
        unset($array_feed);
        $this->videos = $array_valid_videos;
        return true;
    }

    private function retrieve_videos_from_xml_feed(){

        $xml_reader                 = new XMLReader();
        $existing_ids               = $this->get_partner_existing_ids();
        $array_valid_videos         = array();
        $count_valid_feed_items     = 0;
        $end                        = false;

        if ( !$xml_reader->open( $this->feed_url ) || !$xml_reader->read() ){            
            //full xml
            $args = array(
                'timeout'       => 300,
                'sslverify'     => false,
                'user-agent'    => 'WordPress/' . $this->wp_version . '; ' . home_url()
            );
            $response = wp_remote_get( $this->feed_url, $args );

            if ( !is_wp_error( $response ) ) {
                $response_body  = wp_remote_retrieve_body( $response );
                $full_xml       = simplexml_load_string( $response_body );
                $count_total_feed_items = count( $full_xml );
                if( $count_total_feed_items < $this->params['limit'] ){
                    $this->params['limit'] = $count_total_feed_items;
                }
                $current_item = 0;
                while( $end === false ){
                    $xml_elts   = $full_xml->children()->{$this->feed_infos->feed_item_path->node};
                    $feed_item  = new AMVG_Xml_Item( $xml_elts[$current_item]->asXML() );
                    $feed_item->init( $this->params, $this->feed_infos );
                    if( $feed_item->is_valid() && !in_array( $feed_item->get_id(), (array) $existing_ids ) ){
                        $array_valid_videos[] = (array) $feed_item->get_data_for_json( $count_valid_feed_items );
                        ++$count_valid_feed_items;
                    }
                    if( ( $count_valid_feed_items >= $this->params['limit'] ) || $current_item >= ( $count_total_feed_items - 1 ) ){
                        $end = true;
                    }
                    ++$current_item;
                }
                unset( $full_xml, $xml_elts, $feed_item);
            }else{
                if( isset( $response->errors['http_request_failed'] ) ){
                    wp_die( $response->errors['http_request_failed'] );
                }
            }
        }else{
            //stream xml
            $end = false;
            while ( $xml_reader->read() && $end === false ) {
                switch ($xml_reader->nodeType) {
                    case (XMLREADER::ELEMENT):
                        if ( $xml_reader->localName == $this->feed_infos->feed_item_path->node){
                            $feed_item = new AMVG_Xml_Item($xml_reader->readOuterXML());//extends SimpleXMLElement
                            $feed_item->init( $this->params, $this->feed_infos );
                            if( $feed_item->is_valid() && !in_array( $feed_item->get_id(), (array) $existing_ids ) ){
                                $array_valid_videos[] = (array) $feed_item->get_data_for_json($count_valid_feed_items);
                                ++$count_valid_feed_items;
                            }
                            if( $count_valid_feed_items >= $this->params['limit'] ){
                                $end = true;
                            }
                        }
                }
            }
            $xml_reader->close();
        }
        $this->videos = $array_valid_videos;
        return true;
    }


    private function find_native($video_block, $feed_item){

        $array_video_id = array(
            'query'     => $this->get_partner_feed_infos( $this->feed_infos->{$feed_item}->find->query ),
            'offset'    => $this->get_partner_feed_infos( $this->feed_infos->{$feed_item}->find->offset ),
            'attr'      => $this->get_partner_feed_infos( $this->feed_infos->{$feed_item}->find->attr )
        );

        if( $array_video_id['query'] != '' ){
            return $video_block->find( (string) $array_video_id['query'], (int) $array_video_id['offset'] )->{$array_video_id['attr']};
        }else{
            return $video_block->{$array_video_id['attr']};
        }
    }


    private function get_partner_feed_infos( $partner_feed_item ){
        $results = array();
        preg_match_all("/<%(.+)%>/U", $partner_feed_item, $results);

        foreach ( (array) $results[1] as $result) {
            if( strpos( $result, 'get_partner_option' ) !== false){
                $saved_partner_options  = WPSCORE()->get_product_option( 'AMVG', $this->params['partner']['id'] . '_options' );
                $option                 = str_replace( array( 'get_partner_option("', '")'), array('', ''),  $result);
                $new_result             = '$saved_partner_options["' . $option . '"]';
                $partner_feed_item      = str_replace('<%' . $result . '%>', eval('return ' . $new_result . ';'), $partner_feed_item);
            }else{
                $partner_feed_item      = str_replace('<%' . $result . '%>', eval('return ' . $result . ';'), $partner_feed_item);
            }
        }

        return $partner_feed_item;
    }

    private function get_partner_existing_ids(){
        global $wpdb;

        $custom_post_type = xbox_get_field_value( 'amvg-options', 'custom-video-post-type' );
        $custom_post_type = $custom_post_type != '' ? $custom_post_type : 'post';

        $query_str = "
            SELECT wposts.ID, wpostmetaVideoId.meta_value videoId
            FROM $wpdb->posts wposts, $wpdb->postmeta wpostmetasponsor, $wpdb->postmeta wpostmetaVideoId
            WHERE wposts.ID = wpostmetasponsor.post_id
            AND ( wpostmetasponsor.meta_key = 'partner' AND wpostmetasponsor.meta_value = %s )
            AND (wposts.ID =  wpostmetaVideoId.post_id AND wpostmetaVideoId.meta_key = 'video_id')
            AND wposts.post_type = %s
        ";

        $bdd_videos = $wpdb->get_results( $wpdb->prepare( $query_str, $this->params["partner"]['id'], $custom_post_type), OBJECT );

        $partner_videos_ids = array();

        foreach( (array)$bdd_videos as $bdd_video ){
            $partner_videos_ids[$bdd_video->ID] = $bdd_video->videoId;
        }

        unset( $bdd_videos );
        return $partner_videos_ids;
    }
}