<?php
if (!defined('BASEPATH')) exit('No direct script access allowed');

class sitemap_model extends CI_Model
{

    /**
     * Construct
     */
    public function __construct()
    {
        parent::__construct();

        // load library
        $this->load->library('sitemap/sitemap_item');
    }

    /**
     * Generate sitemap
     *
     * @return boolean
     */
    public function generate()
    {
        $this->createXML($this->get_sitemap_data());

        return TRUE;
    }

    /**
     * Get modules
     *
     * @return array
     */
    public function get_modules()
    {
        $sitemap_modules = array('resmng');

        $query = $this->db->
                select('acl_resource_name')->
                order_by('id_acl_resource', 'DESC')->
                where('active', TRUE)->
                get('acl_resource')->result_array();

        if (!empty($query)) {
            foreach ($query as $v) {
                foreach (array_keys($this->config->item('modules_locations')) as $loc) {
                    if (file_exists($loc.$v['acl_resource_name'].'/libraries/'.$v['acl_resource_name'].'_sitemap_api.php')) {
                        $sitemap_modules[] = $v['acl_resource_name'];
                    }
                }
            }
        }

        return $sitemap_modules;
    }

    /**
     * Set modules
     *
     * @param array $save_array
     */
    public function set_modules($save_array = array())
    {
        if (!empty($save_array)) {
            $this->db->empty_table('sitemap_config');
            foreach ($save_array as $k => $v) {
                $data = array(
                    'module_name' => $k,
                    'changefreq'  => $v['changefreq'],
                    'priority'    => $v['priority'],
                    'basepage'    => $v['basepage']
                );
                $this->db->insert('sitemap_config', $data);
            }
        }
    }

    /**
     * Get modules db data
     *
     * @return array
     */
    public function get_modules_db()
    {
        $options = array('always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never');
        $temp    = '';

        $pages = $this->get_base_page();

        $sitemap_modules_db = $this->db->
                select('module_name, changefreq, priority, basepage')->
                get('sitemap_config')->result_array();

        // add default data
        $modules = array_column($sitemap_modules_db, 'module_name');
        if (!in_array('resmng', $modules)) {
            $sitemap_modules_db[] = [
                'module_name' => 'resmng',
                'changefreq'  => 'daily',
                'priority'    => 0.5,
                'basepage'    => 0
            ];
        }

        foreach ($sitemap_modules_db as $k => $v) {


            foreach ($options as $key => $value) {
                if ($value == $v['changefreq']) {
                    $temp .= '<option selected="selected" value="'.$value.'">'.$value.'</option>';
                } else {
                    $temp .= '<option value="'.$value.'">'.$value.'</option>';
                }
            }

            $sitemap_modules_db[$k]['changefreq'] = $temp;
            $temp                                 = '';

            $temp = '<option value="0">---</option>';
            if (!empty($pages)) {
                foreach ($pages as $key => $value) {

                    if ($value['id_resource_type_page'] == $v['basepage']) {
                        $temp .= '<option selected="selected" value="'.$value['id_resource_type_page'].'">'.$value['name'].'</option>';
                    } else {
                        $temp .= '<option value="'.$value['id_resource_type_page'].'">'.$value['name'].'</option>';
                    }
                }
            }
            $sitemap_modules_db[$k]['basepage'] = $temp;
            $temp                               = '';
        }

        return $sitemap_modules_db;
    }

    /**
     * Get base page
     *
     * @return array
     */
    public function get_base_page()
    {
        $sql = $this->db->
                select('id_resource_type_page, name')->
                get('resource_type_page')->result_array();

        return $sql;
    }

    /**
     * Prepare sitemap. If link not allowed set it to db
     *
     * @return array
     */
    public function prepare_sitemap()
    {
        // get data
        $data = $this->get_sitemap_data();

        // prepare default data
        $responses = [];

        // parse locations
        foreach ($data as $item) {
            $loc = $item->get_loc();
            if (!empty($loc)) {
                // get response
                $responses[$loc] = $this->getResponse($loc);
            }
        }

        // set error links
        $error_link = [];
        foreach ($responses as $response) {
            // prepare error links
            if ($response['httpCode'] != 200 || strpos($response, 'content="noindex') !== false) {
                $error_link[] = $loc;
            }
        }
        if (!empty($error_link)) {
            $this->set_error_links(array_unique($error_link));
        }
        // set images
        $page_images = [];
        foreach ($data as $item) {
            if (!in_array($item->get_loc(), $error_link) && empty($item->get_images()) && isset($responses[$item->get_loc()])) {
                $html = $responses[$item->get_loc()]['html'];

                // parse html
                preg_match_all('/<img[^>]+>/i', $html, $data);

                // parse html data
                $images = [];
                if (isset($data[0])) {
                    foreach ($data[0] as $image) {
                        preg_match_all('/(src)=("[^"]*")/i', $image, $images[$image]);
                    }
                }

                // prepare $page_images
                foreach ($images as $image) {
                    if (isset($image[2][0])) {
                        // prepare path
                        $path = str_replace('"', '', $image[2][0]);
                        if (strpos($path, 'http') === false) {
                            $path = base_url($path);
                        }

                        $page_images[] = [
                            'href' => $item->get_loc(),
                            'path' => $path
                        ];
                    }
                }
            }
        }
        if (!empty($page_images)) {
            $this->set_images($page_images);
        }

        return ['status' => true];
    }

    /**
     * Set images to DB
     *
     * @param array $data
     * @return void
     */
    protected function set_images($data)
    {
        $this->db->query('DELETE FROM sitemap_image');

        foreach ($data as $item) {
            $this->db->insert('sitemap_image', ['href' => $item['href'], 'path' => $item['path']]);
        }
    }

    /**
     * Set error links to DB
     * 
     * @param array $data
     * @return void
     */
    protected function set_error_links($data)
    {
        $this->db->query('DELETE FROM sitemap_error_link');

        foreach ($data as $link) {
            $this->db->insert('sitemap_error_link', array('link' => $link));
        }
    }

    /**
     * Get error links to DB
     * 
     * @return array
     */
    public function get_error_links()
    {
        $query  = $this->db->
                select('link')->
                order_by('id_sitemap_error_link', 'ASC')->
                get('sitemap_error_link')->result_array();
        $result = array();
        foreach ($query as $link) {
            $result[] = $link['link'];
        }


        return $result;
    }

    /**
     * Check url by curl response 
     * 
     * @param string $url
     * @return array
     */
    protected function getResponse($url)
    {
        $curlObj  = curl_init();
        curl_setopt($curlObj, CURLOPT_URL, $url);
        curl_setopt($curlObj, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($curlObj);
        $httpCode = curl_getinfo($curlObj, CURLINFO_HTTP_CODE);
        curl_close($curlObj);

        return [
            'html'     => $response,
            'httpCode' => $httpCode
        ];
    }

    /**
     * Get all sitemap data from project
     * 
     * @return array
     */
    protected function get_sitemap_data()
    {
        $sitemap_modules = $this->get_modules();
        $sitemap_modules = array_unique($sitemap_modules);

        // prepare data
        $data = [];
        $libs = [];

        // load data
        foreach ($sitemap_modules as $v) {
            $module = ($v == 'resmng') ? 'sitemap' : $v;
            $lib    = $v.abstract_sitemap::LIBRARY_SUFIX;
            if (!in_array($lib, $libs)) {
                $this->load->library($module.'/'.$lib);
                $data   = array_merge($data, $this->{$lib}->get_module_map());
                $libs[] = $lib;
            }
        }

        // set images
        $images = $this->get_images();
        if (!empty($images)) {
            foreach ($data as $item) {
                foreach ($images as $image) {
                    if ($image['href'] == $item->get_loc()) {
                        $item->add_image($image['path']);
                    }
                }
            }
        }

        return $data;
    }

    /**
     * Get images from db
     *
     * @return array
     */
    protected function get_images()
    {
        $data = $this->db->
            select('href, path')->
            get('sitemap_image')->
            result_array();

        return (!empty($data)) ? $data : [];
    }

    /**
     * Create XML
     *
     * @param array $data
     * @return string
     */
    protected function createXML($data = array())
    {

        $mapdata = '<?xml version="1.0" encoding="UTF-8"?>
                  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
                  xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">';

        foreach ($data as $item) {
            if (!empty($item->get_loc()) && !in_array($item->get_loc(), $this->get_error_links())) {
                $mapdata .= '<url><loc>'.$item->get_loc().'</loc>';
                if (!empty($item->get_lastmod())) {
                    $mapdata .= '<lastmod>'.$item->get_lastmod().'</lastmod>';
                }
                if (!empty($item->get_changefreq())) {
                    $mapdata .= '<changefreq>'.$item->get_changefreq().'</changefreq>';
                }
                if (!empty($item->get_priority())) {
                    $mapdata .= '<priority>'.$item->get_priority().'</priority>';
                }
                if (!empty($item->get_images())) {
                    foreach ($item->get_images() as $image) {
                        $mapdata .= '<image:image><image:loc>'.$image.'</image:loc></image:image>';
                    }
                }
                $mapdata .= '</url>';
            }
        }
        $mapdata .= '</urlset>';

        $this->load->library('ciext/configurator');
        $conf = new configurator();
        $conf->set_resource('sitemap');
        $data = $conf->get_config();

        if (empty($data['cache_life'])) {
            $data['cache_life'] = $this->config->item('cache_life_time');
        }

        $this->cache->save('sitemap_xml', $mapdata, $data['cache_life']);

        return $mapdata;
    }
}
