<?php

namespace PremiumStockMarketWidgets;

/**
 * Class Plugin - WordPress plugin
 * @package PremiumStockMarketWidgets
 */
class Plugin
{
    const VERSION           = '2.1.10';
    const MIN_PHP_VERSION   = '5.6.0';
    const CODE              = 'smw';
    const ID                = 'premium-stock-market-widgets';
    const NAME              = 'Premium Stock Market Widgets';
    const SHORTCODE         = 'stock_market_widget';
    const JS_GLOBAL_VAR     = 'premiumStockMarketWidgets';
    const ADMIN_TEMPLATES   = 'admin';

    private $pluginDir;
    private $pluginUrl;
    private $config;
    private $ajaxUrl;
    private $ajaxNonce;
    private $ajaxMethod;

    // note that constructor can be called multiple times during page load, due to possibly multiple AJAX requests
    function __construct()
    {
        $this->pluginDir = SMW_ROOT_DIR . DIRECTORY_SEPARATOR;
        $this->pluginUrl = plugins_url() . '/' . self::ID; // on SSL enabled websites WP_PLUGIN_URL still contains plain HTTP protocol, so it using function instead
        $this->config = get_option(self::CODE . '_config');
        $this->ajaxUrl = admin_url('admin-ajax.php');
        $this->ajaxMethod = $this->getConfigVariable('ajax_method');

        $enqueuePriority = $this->getConfigVariable('enqueue_priority');

        // shortcode
        add_shortcode(self::SHORTCODE, [$this, 'shortcode']);

        // actions
        add_action('init', [$this, 'init']);
        add_action('wp_enqueue_scripts', [$this, 'loadAssets'], $enqueuePriority);
        add_action('admin_init', [$this, 'adminInit']);
        add_action('admin_menu', [$this, 'addAdminMenu']);
        add_action('admin_enqueue_scripts', [$this, 'loadAdminAssets'], $enqueuePriority);
        add_action('template_redirect', [$this, 'displayVirtualAssetPage']);

        // filters
        add_filter('query_vars', [$this, 'addAssetQueryVariables']);
        add_filter('the_title', [$this, 'disableTitle']);
        add_filter('plugin_action_links_' . self::ID . '/' . self::ID . '.php', [$this, 'addPluginActionLinks']);

        $this->addAjaxHandler('AssetSearch');
        $this->addAjaxHandler('AssetSearch', TRUE);
        $this->addAjaxHandler('GetMarketData');
        $this->addAjaxHandler('GetMarketData', TRUE);
    }

    /**
     * Load assets for public users
     */
    public function loadAssets()
    {
        $this->loadStyles();
        $this->loadScripts();
    }

    /**
     * Load assets for admin users
     */
    public function loadAdminAssets()
    {
        // always enqueue CSS styles, because fontawesome icons are required on all pages
        $this->loadStyles();

        $script = basename($_SERVER['PHP_SELF']);
        // enqueue JS scripts only when plugin pages are viewed
        if ($script == 'admin.php' && strpos($_SERVER['QUERY_STRING'], 'page='.self::ID) !== FALSE) {
            $this->loadAdminScripts();
        }
    }

    /**
     * Load CSS files for public users
     */
    private function loadStyles()
    {
        $this->loadStyle(self::CODE . '-plugin-style', 'assets/css/style.css');
    }

    /**
     * Load JS scripts for public users
     */
    private function loadScripts()
    {
        $this->loadScript(self::CODE . '-plugin-main', 'assets/js/dist/app.js', ['jquery'], TRUE);
        $this->localizeScript(self::CODE . '-plugin-main', self::JS_GLOBAL_VAR, $this->jsVariables);
    }

    /**
     * Load JS scripts for admin users
     */
    private function loadAdminScripts()
    {
        $this->loadScript(self::CODE . '-plugin-main', 'assets/js/dist/builder.js', ['jquery'], TRUE);
        $this->localizeScript(self::CODE . '-plugin-main', self::JS_GLOBAL_VAR, $this->jsVariables);
    }


    /**
     * Init function
     */
    public function init()
    {
        // get list of logo images
        $assetsLogoImages = array_slice(scandir($this->pluginDir . '/assets/images/logo'),2);
        // convert the list to symbol => image associative array, e.g. ['AAPL' => 'AAPL.png']
        $assetsLogoImages = array_combine(array_map(function($image) {
            return substr($image, 0, strrpos($image,'.'));
        }, $assetsLogoImages), $assetsLogoImages);

        // nonce for AJAX requests
        $this->ajaxNonce = wp_create_nonce(__DIR__);

        // load translation files
        load_plugin_textdomain(self::ID, false, self::ID . '/languages');

        // add a rewrite rule if virtual page regexp is set
        if ($this->getConfigVariable('asset_page_regexp')) {
            // rewrite rule will transform URL into query string (GET) parameters
            // e.g. ^nasdaq/([a-zA-Z0-9-\.=\^\$]+)/?$
            add_rewrite_rule($this->getConfigVariable('asset_page_regexp'), 'index.php?' . self::CODE . '_asset=$matches[1]', 'top');
        }

        // it's important to call translation functions AFTER load_plugin_textdomain() is called, otherwise translations will not work
        $this->jsVariables = [
            'shortcodeOpenTag' => '[' . self::SHORTCODE . ' ',
            'shortcodeCloseTag' => ']',
            'pluginUrl' => $this->pluginUrl,
            'websiteUrl' => get_site_url(), // WordPress root URL
            'ajaxUrl' => $this->ajaxUrl,
            'ajaxNonce' => $this->ajaxNonce,
            'ajaxMethod' => $this->ajaxMethod,
            'assetsLogoImages' => $assetsLogoImages,
            'thousandsSeparator' => $this->getConfigVariable('thousands_separator'),
            'decimalSeparator' => $this->getConfigVariable('decimal_separator'),
            'locale' => $this->getConfigVariable('locale'),
            'assetRecognitionRegexp' => $this->getConfigVariable('asset_recognition_regexp'),
            'assetNamesOverrides' => $this->getConfigVariable('asset_names_overrides'),
            // text.json needs to be modified when the below strings changed
            'text' => [
                '_self' => __('Same window', 'premium-stock-market-widgets'),
                '_blank' => __('New window', 'premium-stock-market-widgets'),
                '15m' => __('15 minutes', 'premium-stock-market-widgets'),
                '30m' => __('30 minutes', 'premium-stock-market-widgets'),
                '60m' => __('60 minutes', 'premium-stock-market-widgets'),
                '90m' => __('90 minutes', 'premium-stock-market-widgets'),
                '1h' => __('1 hour', 'premium-stock-market-widgets'),
                '1d' => __('1 day', 'premium-stock-market-widgets'),
                '5d' => __('5 days', 'premium-stock-market-widgets'),
                '1wk' => __('1 week', 'premium-stock-market-widgets'),
                '1mo' => __('1 month', 'premium-stock-market-widgets'),
                '3mo' => __('3 months', 'premium-stock-market-widgets'),
                '6mo' => __('6 months', 'premium-stock-market-widgets'),
                '1y' => __('1 year', 'premium-stock-market-widgets'),
                '2y' => __('2 years', 'premium-stock-market-widgets'),
                '5y' => __('5 years', 'premium-stock-market-widgets'),
                '10y' => __('10 years', 'premium-stock-market-widgets'),
                '52_week_low' => __('52 week low', 'premium-stock-market-widgets'),
                '52_week_low_change_abs' => __('52 week low change', 'premium-stock-market-widgets'),
                '52_week_low_change_pct' => __('52 week low % change', 'premium-stock-market-widgets'),
                '52_week_high' => __('52 week high', 'premium-stock-market-widgets'),
                '52_week_high_change_abs' => __('52 week high change', 'premium-stock-market-widgets'),
                '52_week_high_change_pct' => __('52 week high % change', 'premium-stock-market-widgets'),
                '52_week_change' => __('52 week change', 'premium-stock-market-widgets'),
                '52_week_low_high' => __('52 week low / high', 'premium-stock-market-widgets'),
                '52_week_range' => __('52 week range', 'premium-stock-market-widgets'),
                '5_year_avg_dividend_yield' => __('Five Year Avg Dividend Yield', 'premium-stock-market-widgets'),
                '50_day_average' => __('50 day average', 'premium-stock-market-widgets'),
                '200_day_average' => __('200 day average', 'premium-stock-market-widgets'),
                'address' => __('Address', 'premium-stock-market-widgets'),
                'annual_dividend_rate' => __('Trailing Annual Dividend Rate', 'premium-stock-market-widgets'),
                'annual_dividend_yield' => __('Trailing Annual Dividend Yield', 'premium-stock-market-widgets'),
                'algorithm' => __('Algorithm', 'premium-stock-market-widgets'),
                'anonymity' => __('Anonymity', 'premium-stock-market-widgets'),
                'analyst_opinions' => __('Analyst opinions count', 'premium-stock-market-widgets'),
                'api' => __('API', 'premium-stock-market-widgets'),
                'api_type' => __('API type', 'premium-stock-market-widgets'),
                'asc' => __('Ascending', 'premium-stock-market-widgets'),
                'ask' => __('Ask', 'premium-stock-market-widgets'),
                'asset' => __('Asset', 'premium-stock-market-widgets'),
                'assets' => __('Assets', 'premium-stock-market-widgets'),
                'average_volume' => __('Average volume', 'premium-stock-market-widgets'),
                'average_volume_10_days' => __('Average volume 10 days', 'premium-stock-market-widgets'),
                'axes' => __('Display axes', 'premium-stock-market-widgets'),
                'beta' => __('Beta', 'premium-stock-market-widgets'),
                'bid' => __('Bid', 'premium-stock-market-widgets'),
                'book_value' => __('Book value', 'premium-stock-market-widgets'),
                'bottomCenter' => __('Bottom center', 'premium-stock-market-widgets'),
                'bottomLeft' => __('Bottom left', 'premium-stock-market-widgets'),
                'bottomRight' => __('Bottom right', 'premium-stock-market-widgets'),
                'buy' => __('Buy', 'premium-stock-market-widgets'),
                'center' => __('Center', 'premium-stock-market-widgets'),
                'change_abs' => __('Change', 'premium-stock-market-widgets'),
                'change_pct' => __('% Change', 'premium-stock-market-widgets'),
                'chart' => __('Chart', 'premium-stock-market-widgets'),
                'city' => __('City', 'premium-stock-market-widgets'),
                'close' => __('Close', 'premium-stock-market-widgets'),
                'color' => __('Color', 'premium-stock-market-widgets'),
                'copy' => __('Copy', 'premium-stock-market-widgets'),
                'country' => __('Country', 'premium-stock-market-widgets'),
                'current_ratio' => __('Current ratio', 'premium-stock-market-widgets'),
                'currency' => __('Currency', 'premium-stock-market-widgets'),
                'currency_symbol' => __('Currency symbol', 'premium-stock-market-widgets'),
                'currencies' => __('Currencies', 'premium-stock-market-widgets'),
                'cursor' => __('Cursor', 'premium-stock-market-widgets'),
                'date' => __('Date', 'premium-stock-market-widgets'),
                'day_low_high' => __('Day low / high', 'premium-stock-market-widgets'),
                'date_time' => __('Date / time', 'premium-stock-market-widgets'),
                'debt_equity' => __('Debt / Equity', 'premium-stock-market-widgets'),
                'desc' => __('Descending', 'premium-stock-market-widgets'),
                'description' => __('Description', 'premium-stock-market-widgets'),
                'direction' => __('Direction', 'premium-stock-market-widgets'),
                'display_chart' => __('Display chart for selected asset', 'premium-stock-market-widgets'),
                'display_header' => __('Display header', 'premium-stock-market-widgets'),
                'dividend_rate' => __('Dividend rate', 'premium-stock-market-widgets'),
                'dividend_yield' => __('Dividend yield', 'premium-stock-market-widgets'),
                'earnings_growth' => __('Earnings growth', 'premium-stock-market-widgets'),
                'ebitda' => __('EBITDA', 'premium-stock-market-widgets'),
                'ebitda_margin' => __('EBITDA margin', 'premium-stock-market-widgets'),
                'employees_count' => __('Number of employees', 'premium-stock-market-widgets'),
                'enterprise_ebitda' => __('Enterprise EBITDA', 'premium-stock-market-widgets'),
                'enterprise_revenue' => __('Enterprise revenue', 'premium-stock-market-widgets'),
                'enterprise_value' => __('Enterprise value', 'premium-stock-market-widgets'),
                'eps' => __('Earnings per share', 'premium-stock-market-widgets'),
                'ex_dividend_date' => __('Ex-Dividend date', 'premium-stock-market-widgets'),
                'exchange_code' => __('Exchange code', 'premium-stock-market-widgets'),
                'exchange_name' => __('Exchange', 'premium-stock-market-widgets'),
                'exchange_tz_name' => __('Exchange timezone', 'premium-stock-market-widgets'),
                'exchange_tz_code' => __('Exchange timezone code', 'premium-stock-market-widgets'),
                'field' => __('Field', 'premium-stock-market-widgets'),
                'fields' => __('Fields', 'premium-stock-market-widgets'),
                'forward_eps' => __('Forward earnings per share', 'premium-stock-market-widgets'),
                'forward_pe_ratio' => __('Forward P/E ratio', 'premium-stock-market-widgets'),
                'free_cashflow' => __('Free cashflow', 'premium-stock-market-widgets'),
                'gross_profit' => __('Gross profit', 'premium-stock-market-widgets'),
                'gross_margin' => __('Gross margin', 'premium-stock-market-widgets'),
                'high' => __('High', 'premium-stock-market-widgets'),
                'industry' => __('Industry', 'premium-stock-market-widgets'),
                'interval' => __('Interval', 'premium-stock-market-widgets'),
                'yes' => __('Yes', 'premium-stock-market-widgets'),
                'last_split_factor' => __('Last split factor', 'premium-stock-market-widgets'),
                'last_split_date' => __('Last split date', 'premium-stock-market-widgets'),
                'last_update' => __('Last update', 'premium-stock-market-widgets'),
                'last_update_ago' => __('Last update', 'premium-stock-market-widgets'),
                'left' => __('Left', 'premium-stock-market-widgets'),
                'limit' => __('Limit', 'premium-stock-market-widgets'),
                'line' => __('Line', 'premium-stock-market-widgets'),
                'link' => __('Link', 'premium-stock-market-widgets'),
                'logo' => __('Logo', 'premium-stock-market-widgets'),
                'logo_name' => __('Name', 'premium-stock-market-widgets'),
                'logo_name_link' => __('Name', 'premium-stock-market-widgets'),
                'low' => __('Low', 'premium-stock-market-widgets'),
                'low_high' => __('Low / High', 'premium-stock-market-widgets'),
                'market' => __('Market', 'premium-stock-market-widgets'),
                'market_cap' => __('Market cap', 'premium-stock-market-widgets'),
                'market_cap2' => __('Mkt cap', 'premium-stock-market-widgets'),
                'markup' => __('Text (markup)', 'premium-stock-market-widgets'),
                'max' => __('Max', 'premium-stock-market-widgets'),
                'mode' => __('Mode', 'premium-stock-market-widgets'),
                'name' => __('Name', 'premium-stock-market-widgets'),
                'name_lc' => __('Name (LC)', 'premium-stock-market-widgets'),
                'name_link' => __('Name', 'premium-stock-market-widgets'),
                'net_income_to_common' => __('Net income to common', 'premium-stock-market-widgets'),
                'no' => __('No', 'premium-stock-market-widgets'),
                'number_b' => __('b', 'premium-stock-market-widgets'),
                'number_k' => __('k', 'premium-stock-market-widgets'),
                'number_m' => __('m', 'premium-stock-market-widgets'),
                'number_t' => __('t', 'premium-stock-market-widgets'),
                'open' => __('Open', 'premium-stock-market-widgets'),
                'operating_cashflow' => __('Operating cashflow', 'premium-stock-market-widgets'),
                'operating_margin' => __('Operating margin', 'premium-stock-market-widgets'),
                'page_url' => __('Asset page URL', 'premium-stock-market-widgets'),
                'pagination' => __('Pagination', 'premium-stock-market-widgets'),
                'pause' => __('Pause on hover', 'premium-stock-market-widgets'),
                'payout_ratio' => __('Payout ratio', 'premium-stock-market-widgets'),
                'pe_ratio' => __('P/E ratio', 'premium-stock-market-widgets'),
                'peg_ratio' => __('PEG ratio', 'premium-stock-market-widgets'),
                'period' => __('Period', 'premium-stock-market-widgets'),
                'phone' => __('Phone', 'premium-stock-market-widgets'),
                'position' => __('Position', 'premium-stock-market-widgets'),
                'preview' => __('Preview', 'premium-stock-market-widgets'),
                'previous_close' => __('Previous close', 'premium-stock-market-widgets'),
                'price' => __('Price', 'premium-stock-market-widgets'),
                'price_book' => __('Price / Book', 'premium-stock-market-widgets'),
                'price_to_sales_trailing_12_months' => __('Price / Sales', 'premium-stock-market-widgets'),
                'profit_margin' => __('Profit margin', 'premium-stock-market-widgets'),
                'portfolio_date' => __('Purchase date', 'premium-stock-market-widgets'),
                'portfolio_price' => __('Purchase price', 'premium-stock-market-widgets'),
                'portfolio_sell_date' => __('Sell date', 'premium-stock-market-widgets'),
                'portfolio_sell_price' => __('Sell price', 'premium-stock-market-widgets'),
                'portfolio_structure' => __('Portfolio structure', 'premium-stock-market-widgets'),
                'portfolio_quantity' => __('Quantity', 'premium-stock-market-widgets'),
                'portfolio_change_abs' => __('Change', 'premium-stock-market-widgets'),
                'portfolio_change_pct' => __('% Change', 'premium-stock-market-widgets'),
                'portfolio_cost' => __('Cost', 'premium-stock-market-widgets'),
                'portfolio_value' => __('Market value', 'premium-stock-market-widgets'),
                'portfolio_return_abs' => __('Return', 'premium-stock-market-widgets'),
                'portfolio_return_pct' => __('% Return', 'premium-stock-market-widgets'),
                'quantity' => __('Quantity', 'premium-stock-market-widgets'),
                'quarter_earnings_growth' => __('Quarterly earnings growth', 'premium-stock-market-widgets'),
                'quick_ratio' => __('Quick ratio', 'premium-stock-market-widgets'),
                'range' => __('Range', 'premium-stock-market-widgets'),
                'range_short_5d' => __('5d', 'premium-stock-market-widgets'),
                'range_short_1mo' => __('1m', 'premium-stock-market-widgets'),
                'range_short_3mo' => __('3m', 'premium-stock-market-widgets'),
                'range_short_6mo' => __('6m', 'premium-stock-market-widgets'),
                'range_short_1y' => __('1y', 'premium-stock-market-widgets'),
                'range_short_2y' => __('2y', 'premium-stock-market-widgets'),
                'range_short_5y' => __('5y', 'premium-stock-market-widgets'),
                'range_short_10y' => __('10y', 'premium-stock-market-widgets'),
                'read_more' => __('Read more', 'premium-stock-market-widgets'),
                'recommendation_mean' => __('Recommendation mean', 'premium-stock-market-widgets'),
                'recommendation_key' => __('Recommendation key', 'premium-stock-market-widgets'),
                'revenue_growth' => __('Revenue growth', 'premium-stock-market-widgets'),
                'revenue_per_share' => __('Revenue per share', 'premium-stock-market-widgets'),
                'return_on_assets' => __('Return on assets', 'premium-stock-market-widgets'),
                'return_on_equity' => __('Return on equity', 'premium-stock-market-widgets'),
                'right' => __('Right', 'premium-stock-market-widgets'),
                'rows_per_page' => __('Rows per page', 'premium-stock-market-widgets'),
                'search' => __('Search', 'premium-stock-market-widgets'),
                'search_placeholder' => __('Symbol or company name', 'premium-stock-market-widgets'),
                'search2' => __('Search...', 'premium-stock-market-widgets'),
                'search_not_found' => __('No matching records found', 'premium-stock-market-widgets'),
                'sector' => __('Sector', 'premium-stock-market-widgets'),
                'sell' => __('Sell', 'premium-stock-market-widgets'),
                'shares_outstanding' => __('Shares outstanding', 'premium-stock-market-widgets'),
                'shares_float' => __('Shares float', 'premium-stock-market-widgets'),
                'shares_short' => __('Shares short', 'premium-stock-market-widgets'),
                'short_ratio' => __('Short ratio', 'premium-stock-market-widgets'),
                'short_pct_of_float' => __('Short % of float', 'premium-stock-market-widgets'),
                'shortcode' => __('Shortcode', 'premium-stock-market-widgets'),
                'server_locations' => __('Server locations', 'premium-stock-market-widgets'),
                'sort_field' => __('Sort field', 'premium-stock-market-widgets'),
                'sort_direction' => __('Sort direction', 'premium-stock-market-widgets'),
                'symbol' => __('Symbol', 'premium-stock-market-widgets'),
                'symbol_lc' => __('Symbol (LC)', 'premium-stock-market-widgets'),
                'speed' => __('Speed', 'premium-stock-market-widgets'),
                'start_expanded' => __('Start expanded', 'premium-stock-market-widgets'),
                'state' => __('State', 'premium-stock-market-widgets'),
                'style' => __('Extra CSS styles', 'premium-stock-market-widgets'),
                'target' => __('Target', 'premium-stock-market-widgets'),
                'target_high_price' => __('Target high price', 'premium-stock-market-widgets'),
                'target_low_price' => __('Target low price', 'premium-stock-market-widgets'),
                'target_mean_price' => __('Target mean price', 'premium-stock-market-widgets'),
                'target_median_price' => __('Target median price', 'premium-stock-market-widgets'),
                'template' => __('Template', 'premium-stock-market-widgets'),
                'theme' => __('Theme', 'premium-stock-market-widgets'),
                'timeout' => __('Timeout', 'premium-stock-market-widgets'),
                'topCenter' => __('Top center', 'premium-stock-market-widgets'),
                'topLeft' => __('Top left', 'premium-stock-market-widgets'),
                'topRight' => __('Top right', 'premium-stock-market-widgets'),
                'total' => __('Total', 'premium-stock-market-widgets'),
                'total_cash' => __('Total cash', 'premium-stock-market-widgets'),
                'total_cash_per_share' => __('Total cash per share', 'premium-stock-market-widgets'),
                'total_debt' => __('Total debt', 'premium-stock-market-widgets'),
                'total_portfolio_change_abs' => __('Total change', 'premium-stock-market-widgets'),
                'total_portfolio_change_pct' => __('Total % change', 'premium-stock-market-widgets'),
                'total_portfolio_cost' => __('Total cost', 'premium-stock-market-widgets'),
                'total_portfolio_value' => __('Total value', 'premium-stock-market-widgets'),
                'total_portfolio_return_abs' => __('Total return', 'premium-stock-market-widgets'),
                'total_portfolio_return_pct' => __('Total % return', 'premium-stock-market-widgets'),
                'total_revenue' => __('Total revenue', 'premium-stock-market-widgets'),
                'type' => __('Type', 'premium-stock-market-widgets'),
                'unknown' => __('Unknown', 'premium-stock-market-widgets'),
                'url' => __('URL', 'premium-stock-market-widgets'),
                'variables' => __('Available substitute variables'),
                'volume' => __('Volume', 'premium-stock-market-widgets'),
                'website' => __('Website', 'premium-stock-market-widgets'),
                'zip' => __('ZIP', 'premium-stock-market-widgets'),
            ]
        ];
    }

    /**
     * Customize plugin action links on plugins page
     * @param $links
     * @return mixed
     */
    public function addPluginActionLinks($links)
    {
        $link = '<a href="https://codecanyon.net/downloads" target="_blank"><i class="fa fa-star"></i><i class="fa fa-star"></i><i class="fa fa-star"></i><i class="fa fa-star"></i><i class="fa fa-star"></i> Rate plugin</a>';
        array_unshift($links, $link);
        return $links;
    }

    /**
     * Init function for admin
     */
    public function adminInit()
    {
        //
    }

    /**
     * Add custom query (GET) variables
     * @param $vars
     * @return array
     */
    public function addAssetQueryVariables($vars)
    {
        $vars[] = self::CODE . '_asset';
        return $vars;
    }

    /**
     * Create a virtual page and display custom asset content.
     * This function is called when the asset page regexp is matched.
     *
     * @return bool
     */
    public function displayVirtualAssetPage()
    {
        global $wp, $wp_query;

        $asset = get_query_var(self::CODE . '_asset');

        // it's important to check that the regexp was matched and hence necessary variables were popuplated, because this hook is called for every page request.
        if (!$asset)
            return;

        // check that there is quotes market data for the requested asset, otherwise return 404 error
        $data = json_decode((new MarketData(['type' => 'quotes', 'assets' => [$asset]]))->get());
        if (!isset($data->success) || !$data->success) {
            $wp_query->set_404();
            status_header(404);
            return;
        }

        // replace assets attribute in all widgets with the asset retrieved from the URL
        $content = preg_replace('#(assets=")[a-z0-9-\.=\^\$]*(")#i', '$1'.strtoupper($asset).'$2', $this->getConfigVariable('asset_page_content'));

        // create virtual WordPress page
        $post_id = -1;
        $post = new \stdClass();
        $post->ID = $post_id;
        $post->post_author = 1;
        $post->post_date = current_time('mysql');
        $post->post_date_gmt = current_time('mysql', 1);
        $post->post_title = $asset; // title will be hidden, so it doesn't matter what to put here
        $post->post_content = $content;
        $post->comment_status = 'closed';
        $post->ping_status = 'closed';
        $post->post_name = 'some name';
        $post->post_type = 'page';
        $post->filter = 'raw';

        $wp_post = new \WP_Post($post);

//        wp_cache_add($post_id, $wp_post, 'posts');

        $wp_query->post = $wp_post;
        $wp_query->posts = [ $wp_post ];
        $wp_query->queried_object = $wp_post;
        $wp_query->queried_object_id = $post_id;
        $wp_query->found_posts = 1;
        $wp_query->post_count = 1;
        $wp_query->max_num_pages = 1;
        $wp_query->is_page = true;
        $wp_query->is_singular = true;
        $wp_query->is_single = false;
        $wp_query->is_attachment = false;
        $wp_query->is_archive = false;
        $wp_query->is_category = false;
        $wp_query->is_tag = false;
        $wp_query->is_tax = false;
        $wp_query->is_author = false;
        $wp_query->is_date = false;
        $wp_query->is_year = false;
        $wp_query->is_month = false;
        $wp_query->is_day = false;
        $wp_query->is_time = false;
        $wp_query->is_search = false;
        $wp_query->is_feed = false;
        $wp_query->is_comment_feed = false;
        $wp_query->is_trackback = false;
        $wp_query->is_home = false;
        $wp_query->is_embed = false;
        $wp_query->is_404 = false;
        $wp_query->is_paged = false;
        $wp_query->is_admin = false;
        $wp_query->is_preview = false;
        $wp_query->is_robots = false;
        $wp_query->is_posts_page = false;
        $wp_query->is_post_type_archive = false;
    }

    /**
     * Disable title on virtual asset pages
     * @param $title
     */
    public function disableTitle($title)
    {
        $asset = get_query_var(self::CODE . '_asset');

        if ($asset && in_the_loop())
            return;

        return $title;
    }

    /**
     * Add custom plugin menu and sub menu items
     */
    public function addAdminMenu()
    {
        add_menu_page(self::NAME, self::NAME, 'edit_posts', self::ID, [$this, 'displayWidgetConfigPage'], $this->pluginUrl . '/assets/images/icon.png');
        $subMenuId = add_submenu_page(self::ID, self::NAME, '<i class="fa fa-wrench"></i> ' . __('Builder', 'premium-stock-market-widgets'), 'edit_posts', self::ID . '-builder', [$this, 'displayWidgetConfigPage']);
        add_action('load-' . $subMenuId, [$this, 'addHelp']);

        // add Settings sub menu
        $subMenuId = add_submenu_page(self::ID, self::NAME, '<i class="fa fa-cogs"></i> ' . __('Settings', 'premium-stock-market-widgets'), 'edit_posts', self::ID . '-settings', [$this, 'displayPluginSettingsPage']);
        add_action('load-' . $subMenuId, [$this, 'addHelp']);

        // explicitly remove the default top sub menu added by Wordpress
        remove_submenu_page(self::ID, self::ID);
    }


    public function addHelp()
    {
        $screen = get_current_screen();
        $screen->add_help_tab([
            'id' => self::ID . '-overview',
            'title' => __('Usage', 'premium-stock-market-widgets'),
            'content' => file_get_contents($this->pluginDir . self::ADMIN_TEMPLATES . '/help/usage.html')
        ]);
        $screen->add_help_tab([
            'id' => self::ID . '-advanced',
            'title' => __('Advanced', 'premium-stock-market-widgets'),
            'content' => file_get_contents($this->pluginDir . self::ADMIN_TEMPLATES . '/help/advanced.html')
        ]);
        $screen->set_help_sidebar(file_get_contents($this->pluginDir . self::ADMIN_TEMPLATES . '/help/sidebar.html'));
    }

    /**
     * Generate widget for given shortcode
     * @param shortcode params
     * @return shortcode HTML
     */
    public function shortcode($shortcode)
    {
        // shortcode() is called each time the plugin is initialized, so need to check if anything was passed or not
        if (empty($shortcode)) return;

        // transform shortcode array into key="value" string
        $shortcodeParams = implode(' ', array_map(function ($value, $key) {
            return $key . '="' . $value . '"';
        }, array_values($shortcode), array_keys($shortcode)));

        return '<stock-market-widget ' . $shortcodeParams . '></stock-market-widget>';
    }

    /**
     * Get market data
     */
    public function ajaxGetMarketData()
    {
        check_ajax_referer(__DIR__, 'nonce');
        print (new MarketData($_REQUEST))->get();
        wp_die();
    }

    /**
     * Search for a given symbol (autocomplete)
     */
    public function ajaxAssetSearch()
    {
        check_ajax_referer(__DIR__, 'nonce');
        print (new \PremiumStockMarketWidgets\AssetSearch($_REQUEST))->get();
        wp_die();
    }

    public function displayWidgetConfigPage()
    {
        require_once($this->pluginDir . self::ADMIN_TEMPLATES . '/builder.php');
    }

    public function displayPluginSettingsPage()
    {
        $settingsSaved = FALSE;

        if (!empty($_POST)) {
            $this->config['thousands_separator'] = isset($_POST['thousands_separator']) ? $_POST['thousands_separator'] : ',';
            $this->config['decimal_separator'] = isset($_POST['decimal_separator']) ? $_POST['decimal_separator'] : '.';
            $this->config['enqueue_priority'] = isset($_POST['enqueue_priority']) ? $_POST['enqueue_priority'] : 10;
            $this->config['ajax_method'] = isset($_POST['ajax_method']) ? $_POST['ajax_method'] : 'post';
            $this->config['locale'] = isset($_POST['locale']) ? $_POST['locale'] : 'en';
            $this->config['asset_recognition_regexp'] = isset($_POST['asset_recognition_regexp']) ? stripslashes($_POST['asset_recognition_regexp']) : '';
            $this->config['asset_page_regexp'] = isset($_POST['asset_page_regexp']) ? stripslashes($_POST['asset_page_regexp']) : '';
            $this->config['asset_page_content'] = isset($_POST['asset_page_content']) ? stripslashes($_POST['asset_page_content']) : '';
            $this->config['asset_names_overrides'] = isset($_POST['asset_names_overrides']) ? WPHelper::textareaToArray($_POST['asset_names_overrides']) : '';
            // save settings
            $settingsSaved = update_option(self::CODE . '_config', $this->config);
            flush_rewrite_rules(FALSE);
        }

        require_once($this->pluginDir . self::ADMIN_TEMPLATES . '/settings.php');
    }

    /**
     * Enqueue style
     * @param $code
     * @param $filePath
     * @param array $dependencies
     */
    private function loadStyle($code, $filePath, $dependencies = [])
    {
        wp_enqueue_style($code, substr($filePath, 0, 4) != 'http' ? $this->pluginUrl . '/' . $filePath : $filePath, $dependencies, self::VERSION);
    }

    /**
     * Enqueue JavaScript
     * @param $code
     * @param $filePath
     * @param array $dependencies
     * @param bool|FALSE $inFooter
     */
    private function loadScript($code, $filePath = NULL, $dependencies = [], $inFooter = FALSE)
    {
        if ($filePath) {
            wp_enqueue_script($code, substr($filePath, 0, 4) != 'http' ? $this->pluginUrl . '/' . $filePath : $filePath, $dependencies, self::VERSION, $inFooter);
        } else {
            // enqueue built-in script like jQuery UI, underscore etc
            wp_enqueue_script($code);
        }
    }

    /**
     * Add custom JavaScript variables
     * @param $code
     * @param $objectName
     * @param $objectProperties
     */
    private function localizeScript($code, $objectName, $objectProperties)
    {
        wp_localize_script($code, $objectName, $objectProperties);
    }

    /**
     * Add AJAX handler
     * @param $name - name of the handler. Public function ajax$name should also be added
     * @param bool|FALSE $public
     */
    private function addAjaxHandler($name, $public = FALSE)
    {
        // e.g. AJAX action will look like smwDisplayWidgetPreview
        add_action('wp_ajax_' . ($public ? 'nopriv_' : '') . self::CODE . $name, [$this, 'ajax' . $name]);
    }

    private function getConfigVariable($name)
    {
        return isset($this->config[$name]) ? $this->config[$name] : NULL;
    }
}

?>
